import org.sonar.ce.task.projectanalysis.qualitymodel.RatingSettings; | import org.sonar.ce.task.projectanalysis.qualitymodel.RatingSettings; | ||||
import org.sonar.ce.task.projectanalysis.qualitymodel.ReliabilityAndSecurityRatingMeasuresVisitor; | import org.sonar.ce.task.projectanalysis.qualitymodel.ReliabilityAndSecurityRatingMeasuresVisitor; | ||||
import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRulesHolderImpl; | import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRulesHolderImpl; | ||||
import org.sonar.ce.task.projectanalysis.qualityprofile.QProfileStatusRepositoryImpl; | |||||
import org.sonar.ce.task.projectanalysis.scm.ScmInfoDbLoader; | import org.sonar.ce.task.projectanalysis.scm.ScmInfoDbLoader; | ||||
import org.sonar.ce.task.projectanalysis.scm.ScmInfoRepositoryImpl; | import org.sonar.ce.task.projectanalysis.scm.ScmInfoRepositoryImpl; | ||||
import org.sonar.ce.task.projectanalysis.source.DbLineHashVersion; | import org.sonar.ce.task.projectanalysis.source.DbLineHashVersion; | ||||
NewLinesRepository.class, | NewLinesRepository.class, | ||||
FileSourceDataComputer.class, | FileSourceDataComputer.class, | ||||
SourceLineReadersFactory.class, | SourceLineReadersFactory.class, | ||||
QProfileStatusRepositoryImpl.class, | |||||
// issues | // issues | ||||
RuleRepositoryImpl.class, | RuleRepositoryImpl.class, |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2018 SonarSource SA | |||||
* mailto:info AT sonarsource DOT com | |||||
* | |||||
* This program is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU Lesser General Public | |||||
* License as published by the Free Software Foundation; either | |||||
* version 3 of the License, or (at your option) any later version. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
* Lesser General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Lesser General Public License | |||||
* along with this program; if not, write to the Free Software Foundation, | |||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||||
*/ | |||||
package org.sonar.ce.task.projectanalysis.qualityprofile; | |||||
public interface MutableQProfileStatusRepository extends QProfileStatusRepository { | |||||
/** | |||||
* @throws IllegalStateException if the given quality profile is already registered | |||||
*/ | |||||
void register(String qpKey, Status status); | |||||
} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2018 SonarSource SA | |||||
* mailto:info AT sonarsource DOT com | |||||
* | |||||
* This program is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU Lesser General Public | |||||
* License as published by the Free Software Foundation; either | |||||
* version 3 of the License, or (at your option) any later version. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
* Lesser General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Lesser General Public License | |||||
* along with this program; if not, write to the Free Software Foundation, | |||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||||
*/ | |||||
package org.sonar.ce.task.projectanalysis.qualityprofile; | |||||
import java.util.Optional; | |||||
public interface QProfileStatusRepository { | |||||
Optional<Status> get(String qpKey); | |||||
enum Status { | |||||
/** | |||||
* the QP was used in the last analysis but not anymore in the current one. | |||||
*/ | |||||
REMOVED, | |||||
/** | |||||
* the QP was not used in the last analysis | |||||
*/ | |||||
ADDED, | |||||
/** | |||||
* the QP was used in the last and current analysis and a rule has changed | |||||
*/ | |||||
UPDATED, | |||||
/** | |||||
* neither the QP or a rule has changed since last analysis | |||||
*/ | |||||
UNCHANGED | |||||
} | |||||
} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2018 SonarSource SA | |||||
* mailto:info AT sonarsource DOT com | |||||
* | |||||
* This program is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU Lesser General Public | |||||
* License as published by the Free Software Foundation; either | |||||
* version 3 of the License, or (at your option) any later version. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
* Lesser General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Lesser General Public License | |||||
* along with this program; if not, write to the Free Software Foundation, | |||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||||
*/ | |||||
package org.sonar.ce.task.projectanalysis.qualityprofile; | |||||
import java.util.HashMap; | |||||
import java.util.Map; | |||||
import java.util.Optional; | |||||
import javax.annotation.Nullable; | |||||
import static com.google.common.base.Preconditions.checkNotNull; | |||||
import static com.google.common.base.Preconditions.checkState; | |||||
public class QProfileStatusRepositoryImpl implements MutableQProfileStatusRepository { | |||||
private final Map<String, Status> statuses = new HashMap<>(); | |||||
@Override | |||||
public Optional<Status> get(@Nullable String qpKey) { | |||||
return Optional.ofNullable(statuses.get(qpKey)); | |||||
} | |||||
@Override | |||||
public void register(String qpKey, Status status) { | |||||
checkNotNull(qpKey, "qpKey can't be null"); | |||||
checkNotNull(status, "status can't be null"); | |||||
checkState(statuses.put(qpKey, status) == null, "Quality Profile '%s' is already registered", qpKey); | |||||
} | |||||
} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2018 SonarSource SA | |||||
* mailto:info AT sonarsource DOT com | |||||
* | |||||
* This program is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU Lesser General Public | |||||
* License as published by the Free Software Foundation; either | |||||
* version 3 of the License, or (at your option) any later version. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
* Lesser General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Lesser General Public License | |||||
* along with this program; if not, write to the Free Software Foundation, | |||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||||
*/ | |||||
package org.sonar.ce.task.projectanalysis.qualityprofile; | |||||
import java.util.Collections; | |||||
import java.util.Map; | |||||
import java.util.stream.Collectors; | |||||
import org.sonar.api.measures.CoreMetrics; | |||||
import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder; | |||||
import org.sonar.ce.task.projectanalysis.component.Component; | |||||
import org.sonar.ce.task.projectanalysis.component.CrawlerDepthLimit; | |||||
import org.sonar.ce.task.projectanalysis.component.DepthTraversalTypeAwareCrawler; | |||||
import org.sonar.ce.task.projectanalysis.component.TreeRootHolder; | |||||
import org.sonar.ce.task.projectanalysis.component.TypeAwareVisitorAdapter; | |||||
import org.sonar.ce.task.projectanalysis.measure.Measure; | |||||
import org.sonar.ce.task.projectanalysis.measure.MeasureRepository; | |||||
import org.sonar.ce.task.projectanalysis.metric.MetricRepository; | |||||
import org.sonar.ce.task.step.ComputationStep; | |||||
import org.sonar.server.qualityprofile.QPMeasureData; | |||||
import org.sonar.server.qualityprofile.QualityProfile; | |||||
import static org.sonar.ce.task.projectanalysis.component.ComponentVisitor.Order.POST_ORDER; | |||||
import static org.sonar.ce.task.projectanalysis.qualityprofile.QProfileStatusRepository.Status.ADDED; | |||||
import static org.sonar.ce.task.projectanalysis.qualityprofile.QProfileStatusRepository.Status.REMOVED; | |||||
import static org.sonar.ce.task.projectanalysis.qualityprofile.QProfileStatusRepository.Status.UNCHANGED; | |||||
import static org.sonar.ce.task.projectanalysis.qualityprofile.QProfileStatusRepository.Status.UPDATED; | |||||
public class RegisterQualityProfileStatusStep implements ComputationStep { | |||||
private TreeRootHolder treeRootHolder; | |||||
private MeasureRepository measureRepository; | |||||
private MetricRepository metricRepository; | |||||
private MutableQProfileStatusRepository qProfileStatusRepository; | |||||
private AnalysisMetadataHolder analysisMetadataHolder; | |||||
public RegisterQualityProfileStatusStep(TreeRootHolder treeRootHolder, MeasureRepository measureRepository, MetricRepository metricRepository, | |||||
MutableQProfileStatusRepository qProfileStatusRepository, AnalysisMetadataHolder analysisMetadataHolder) { | |||||
this.treeRootHolder = treeRootHolder; | |||||
this.measureRepository = measureRepository; | |||||
this.metricRepository = metricRepository; | |||||
this.qProfileStatusRepository = qProfileStatusRepository; | |||||
this.analysisMetadataHolder = analysisMetadataHolder; | |||||
} | |||||
@Override | |||||
public void execute(Context context) { | |||||
new DepthTraversalTypeAwareCrawler( | |||||
new TypeAwareVisitorAdapter(CrawlerDepthLimit.PROJECT, POST_ORDER) { | |||||
@Override | |||||
public void visitProject(Component tree) { | |||||
executeForProject(tree); | |||||
} | |||||
}).visit(treeRootHolder.getRoot()); | |||||
} | |||||
private void executeForProject(Component project) { | |||||
measureRepository.getBaseMeasure(project, metricRepository.getByKey(CoreMetrics.QUALITY_PROFILES_KEY)).ifPresent(baseProfilesMeasure -> { | |||||
Map<String, QualityProfile> baseProfiles = parseJsonData(baseProfilesMeasure); | |||||
Map<String, QualityProfile> rawProfiles = analysisMetadataHolder | |||||
.getQProfilesByLanguage().values().stream() | |||||
.collect(Collectors.toMap(QualityProfile::getQpKey, q -> q)); | |||||
registerNoMoreUsedProfiles(baseProfiles, rawProfiles); | |||||
registerNewOrUpdatedProfiles(baseProfiles, rawProfiles); | |||||
}); | |||||
} | |||||
private void registerNoMoreUsedProfiles(Map<String, QualityProfile> baseProfiles, Map<String, QualityProfile> rawProfiles) { | |||||
for (QualityProfile baseProfile : baseProfiles.values()) { | |||||
if (!rawProfiles.containsKey(baseProfile.getQpKey())) { | |||||
register(baseProfile, REMOVED); | |||||
} | |||||
} | |||||
} | |||||
private void registerNewOrUpdatedProfiles(Map<String, QualityProfile> baseProfiles, Map<String, QualityProfile> rawProfiles) { | |||||
for (QualityProfile profile : rawProfiles.values()) { | |||||
QualityProfile baseProfile = baseProfiles.get(profile.getQpKey()); | |||||
if (baseProfile == null) { | |||||
register(profile, ADDED); | |||||
} else if (profile.getRulesUpdatedAt().after(baseProfile.getRulesUpdatedAt())) { | |||||
register(baseProfile, UPDATED); | |||||
} else { | |||||
register(baseProfile, UNCHANGED); | |||||
} | |||||
} | |||||
} | |||||
private void register(QualityProfile profile, QProfileStatusRepository.Status status) { | |||||
qProfileStatusRepository.register(profile.getQpKey(), status); | |||||
} | |||||
private static Map<String, QualityProfile> parseJsonData(Measure measure) { | |||||
String data = measure.getStringValue(); | |||||
if (data == null) { | |||||
return Collections.emptyMap(); | |||||
} | |||||
return QPMeasureData.fromJson(data).getProfilesByKey(); | |||||
} | |||||
@Override | |||||
public String getDescription() { | |||||
return "Compute Quality Profile status"; | |||||
} | |||||
} |
import org.sonar.ce.task.projectanalysis.filemove.FileMoveDetectionStep; | import org.sonar.ce.task.projectanalysis.filemove.FileMoveDetectionStep; | ||||
import org.sonar.ce.task.projectanalysis.measure.PostMeasuresComputationChecksStep; | import org.sonar.ce.task.projectanalysis.measure.PostMeasuresComputationChecksStep; | ||||
import org.sonar.ce.task.projectanalysis.purge.PurgeDatastoresStep; | import org.sonar.ce.task.projectanalysis.purge.PurgeDatastoresStep; | ||||
import org.sonar.ce.task.projectanalysis.qualityprofile.RegisterQualityProfileStatusStep; | |||||
import org.sonar.ce.task.projectanalysis.source.PersistFileSourcesStep; | import org.sonar.ce.task.projectanalysis.source.PersistFileSourcesStep; | ||||
import org.sonar.ce.task.step.ComputationStep; | import org.sonar.ce.task.step.ComputationStep; | ||||
import org.sonar.ce.task.step.ExecuteStatelessInitExtensionsStep; | import org.sonar.ce.task.step.ExecuteStatelessInitExtensionsStep; | ||||
ComplexityMeasuresStep.class, | ComplexityMeasuresStep.class, | ||||
LoadMeasureComputersStep.class, | LoadMeasureComputersStep.class, | ||||
RegisterQualityProfileStatusStep.class, | |||||
ExecuteVisitorsStep.class, | ExecuteVisitorsStep.class, | ||||
PostMeasuresComputationChecksStep.class, | PostMeasuresComputationChecksStep.class, |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2018 SonarSource SA | |||||
* mailto:info AT sonarsource DOT com | |||||
* | |||||
* This program is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU Lesser General Public | |||||
* License as published by the Free Software Foundation; either | |||||
* version 3 of the License, or (at your option) any later version. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
* Lesser General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Lesser General Public License | |||||
* along with this program; if not, write to the Free Software Foundation, | |||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||||
*/ | |||||
package org.sonar.ce.task.projectanalysis.qualityprofile; | |||||
import com.tngtech.java.junit.dataprovider.DataProvider; | |||||
import com.tngtech.java.junit.dataprovider.DataProviderRunner; | |||||
import com.tngtech.java.junit.dataprovider.UseDataProvider; | |||||
import java.util.Optional; | |||||
import java.util.stream.Stream; | |||||
import org.junit.Before; | |||||
import org.junit.Rule; | |||||
import org.junit.Test; | |||||
import org.junit.rules.ExpectedException; | |||||
import org.junit.runner.RunWith; | |||||
import static org.assertj.core.api.Assertions.assertThat; | |||||
@RunWith(DataProviderRunner.class) | |||||
public class QProfileStatusRepositoryImplTest { | |||||
@Rule | |||||
public ExpectedException expectedException = ExpectedException.none(); | |||||
private QProfileStatusRepositoryImpl underTest; | |||||
@Before | |||||
public void setUp() { | |||||
underTest = new QProfileStatusRepositoryImpl(); | |||||
} | |||||
@Test | |||||
@UseDataProvider("qualityProfileStatuses") | |||||
public void get_return_optional_of_status(QProfileStatusRepository.Status status) { | |||||
underTest.register("key", status); | |||||
assertThat(underTest.get("key")).isEqualTo(Optional.of(status)); | |||||
} | |||||
@Test | |||||
@UseDataProvider("qualityProfileStatuses") | |||||
public void get_return_empty_for_qp_not_registered(QProfileStatusRepository.Status status) { | |||||
underTest.register("key", status); | |||||
assertThat(underTest.get("other_key")).isEqualTo(Optional.empty()); | |||||
} | |||||
@Test | |||||
public void get_return_empty_for_null_qp_key() { | |||||
assertThat(underTest.get(null)).isEqualTo(Optional.empty()); | |||||
} | |||||
@Test | |||||
@UseDataProvider("qualityProfileStatuses") | |||||
public void register_fails_with_NPE_if_qpKey_is_null(QProfileStatusRepository.Status status) { | |||||
expectedException.expect(NullPointerException.class); | |||||
expectedException.expectMessage("qpKey can't be null"); | |||||
underTest.register(null, status); | |||||
} | |||||
@Test | |||||
public void register_fails_with_NPE_if_status_is_null() { | |||||
expectedException.expect(NullPointerException.class); | |||||
expectedException.expectMessage("status can't be null"); | |||||
underTest.register("key", null); | |||||
} | |||||
@Test | |||||
@UseDataProvider("qualityProfileStatuses") | |||||
public void register_fails_with_ISE_if_qp_is_already_registered(QProfileStatusRepository.Status status) { | |||||
underTest.register("key", status); | |||||
expectedException.expect(IllegalStateException.class); | |||||
expectedException.expectMessage("Quality Profile 'key' is already registered"); | |||||
underTest.register("key", status); | |||||
} | |||||
@DataProvider | |||||
public static Object[][] qualityProfileStatuses() { | |||||
return Stream.of(QProfileStatusRepository.Status.values()) | |||||
.map(s -> new Object[] {s}) | |||||
.toArray(Object[][]::new); | |||||
} | |||||
} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2018 SonarSource SA | |||||
* mailto:info AT sonarsource DOT com | |||||
* | |||||
* This program is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU Lesser General Public | |||||
* License as published by the Free Software Foundation; either | |||||
* version 3 of the License, or (at your option) any later version. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
* Lesser General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Lesser General Public License | |||||
* along with this program; if not, write to the Free Software Foundation, | |||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||||
*/ | |||||
package org.sonar.ce.task.projectanalysis.step; | |||||
import com.google.common.collect.ImmutableList; | |||||
import java.util.Arrays; | |||||
import java.util.Collections; | |||||
import java.util.Date; | |||||
import java.util.List; | |||||
import java.util.Map; | |||||
import java.util.Optional; | |||||
import java.util.stream.Collectors; | |||||
import javax.annotation.Nullable; | |||||
import org.junit.Before; | |||||
import org.junit.Rule; | |||||
import org.junit.Test; | |||||
import org.sonar.api.measures.CoreMetrics; | |||||
import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder; | |||||
import org.sonar.ce.task.projectanalysis.component.Component; | |||||
import org.sonar.ce.task.projectanalysis.component.ReportComponent; | |||||
import org.sonar.ce.task.projectanalysis.component.TreeRootHolderRule; | |||||
import org.sonar.ce.task.projectanalysis.measure.Measure; | |||||
import org.sonar.ce.task.projectanalysis.measure.MeasureRepository; | |||||
import org.sonar.ce.task.projectanalysis.metric.Metric; | |||||
import org.sonar.ce.task.projectanalysis.metric.MetricRepository; | |||||
import org.sonar.ce.task.projectanalysis.qualityprofile.MutableQProfileStatusRepository; | |||||
import org.sonar.ce.task.projectanalysis.qualityprofile.RegisterQualityProfileStatusStep; | |||||
import org.sonar.ce.task.step.TestComputationStepContext; | |||||
import org.sonar.server.qualityprofile.QPMeasureData; | |||||
import org.sonar.server.qualityprofile.QualityProfile; | |||||
import static org.mockito.ArgumentMatchers.eq; | |||||
import static org.mockito.Mockito.mock; | |||||
import static org.mockito.Mockito.verify; | |||||
import static org.mockito.Mockito.verifyNoMoreInteractions; | |||||
import static org.mockito.Mockito.when; | |||||
import static org.sonar.ce.task.projectanalysis.qualityprofile.QProfileStatusRepository.Status.ADDED; | |||||
import static org.sonar.ce.task.projectanalysis.qualityprofile.QProfileStatusRepository.Status.REMOVED; | |||||
import static org.sonar.ce.task.projectanalysis.qualityprofile.QProfileStatusRepository.Status.UNCHANGED; | |||||
import static org.sonar.ce.task.projectanalysis.qualityprofile.QProfileStatusRepository.Status.UPDATED; | |||||
public class RegisterQualityProfileStatusStepTest { | |||||
private static final String QP_NAME_1 = "qp_1"; | |||||
private static final String QP_NAME_2 = "qp_2"; | |||||
private static final String LANGUAGE_KEY_1 = "language_key1"; | |||||
private static final String LANGUAGE_KEY_2 = "language_key_2"; | |||||
@Rule | |||||
public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule(); | |||||
private MetricRepository metricRepository = mock(MetricRepository.class); | |||||
private MeasureRepository measureRepository = mock(MeasureRepository.class); | |||||
private MutableQProfileStatusRepository qProfileStatusRepository = mock(MutableQProfileStatusRepository.class); | |||||
private AnalysisMetadataHolder analysisMetadataHolder = mock(AnalysisMetadataHolder.class); | |||||
private Metric qualityProfileMetric = mock(Metric.class); | |||||
private RegisterQualityProfileStatusStep underTest = new RegisterQualityProfileStatusStep(treeRootHolder, measureRepository, metricRepository, qProfileStatusRepository, analysisMetadataHolder); | |||||
@Before | |||||
public void setUp() { | |||||
when(metricRepository.getByKey(CoreMetrics.QUALITY_PROFILES_KEY)).thenReturn(qualityProfileMetric); | |||||
treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid("uuid").setKey("key").build()); | |||||
} | |||||
@Test | |||||
public void register_nothing_if_no_base_measure() { | |||||
when(measureRepository.getBaseMeasure(treeRootHolder.getRoot(), qualityProfileMetric)).thenReturn(Optional.empty()); | |||||
underTest.execute(new TestComputationStepContext()); | |||||
verifyNoMoreInteractions(qProfileStatusRepository); | |||||
} | |||||
@Test | |||||
public void register_nothing_if_no_base_and_quality_profile_measure_is_empty() { | |||||
mockBaseQPMeasures(treeRootHolder.getRoot(), null); | |||||
underTest.execute(new TestComputationStepContext()); | |||||
verifyNoMoreInteractions(qProfileStatusRepository); | |||||
} | |||||
@Test | |||||
public void register_removed_profile() { | |||||
QualityProfile qp = qp(QP_NAME_1, LANGUAGE_KEY_1, new Date()); | |||||
mockBaseQPMeasures(treeRootHolder.getRoot(), new QualityProfile[] {qp}); | |||||
underTest.execute(new TestComputationStepContext()); | |||||
verify(qProfileStatusRepository).register(eq(qp.getQpKey()), eq(REMOVED)); | |||||
verifyNoMoreInteractions(qProfileStatusRepository); | |||||
} | |||||
@Test | |||||
public void register_added_profile() { | |||||
QualityProfile qp1 = qp(QP_NAME_1, LANGUAGE_KEY_1, new Date(1000L)); | |||||
QualityProfile qp2 = qp(QP_NAME_2, LANGUAGE_KEY_2, new Date(1000L)); | |||||
mockBaseQPMeasures(treeRootHolder.getRoot(), arrayOf(qp1)); | |||||
mockRawQProfiles(ImmutableList.of(qp1, qp2)); | |||||
underTest.execute(new TestComputationStepContext()); | |||||
verify(qProfileStatusRepository).register(eq(qp1.getQpKey()), eq(UNCHANGED)); | |||||
verify(qProfileStatusRepository).register(eq(qp2.getQpKey()), eq(ADDED)); | |||||
verifyNoMoreInteractions(qProfileStatusRepository); | |||||
} | |||||
@Test | |||||
public void register_updated_profile() { | |||||
QualityProfile qp1 = qp(QP_NAME_1, LANGUAGE_KEY_1, new Date(1000L)); | |||||
QualityProfile qp2 = qp(QP_NAME_1, LANGUAGE_KEY_1, new Date(1200L)); | |||||
mockBaseQPMeasures(treeRootHolder.getRoot(), arrayOf(qp1)); | |||||
mockRawQProfiles(ImmutableList.of(qp2)); | |||||
underTest.execute(new TestComputationStepContext()); | |||||
verify(qProfileStatusRepository).register(eq(qp2.getQpKey()), eq(UPDATED)); | |||||
verifyNoMoreInteractions(qProfileStatusRepository); | |||||
} | |||||
@Test | |||||
public void register_unchanged_profile() { | |||||
QualityProfile qp1 = qp(QP_NAME_1, LANGUAGE_KEY_1, new Date(1000L)); | |||||
mockBaseQPMeasures(treeRootHolder.getRoot(), arrayOf(qp1)); | |||||
mockRawQProfiles(ImmutableList.of(qp1)); | |||||
underTest.execute(new TestComputationStepContext()); | |||||
verify(qProfileStatusRepository).register(eq(qp1.getQpKey()), eq(UNCHANGED)); | |||||
verifyNoMoreInteractions(qProfileStatusRepository); | |||||
} | |||||
private void mockBaseQPMeasures(Component component, @Nullable QualityProfile[] previous) { | |||||
when(measureRepository.getBaseMeasure(component, qualityProfileMetric)).thenReturn(Optional.of(newMeasure(previous))); | |||||
} | |||||
private void mockRawQProfiles(@Nullable List<QualityProfile> previous) { | |||||
Map<String, QualityProfile> qpByLanguages = previous.stream().collect(Collectors.toMap(QualityProfile::getLanguageKey, q -> q)); | |||||
when(analysisMetadataHolder.getQProfilesByLanguage()).thenReturn(qpByLanguages); | |||||
} | |||||
private static QualityProfile qp(String qpName, String languageKey, Date date) { | |||||
return new QualityProfile(qpName + "-" + languageKey, qpName, languageKey, date); | |||||
} | |||||
private static QualityProfile[] arrayOf(QualityProfile... qps) { | |||||
return qps; | |||||
} | |||||
private static Measure newMeasure(@Nullable QualityProfile... qps) { | |||||
return Measure.newMeasureBuilder().create(toJson(qps)); | |||||
} | |||||
private static String toJson(@Nullable QualityProfile... qps) { | |||||
List<QualityProfile> qualityProfiles = qps == null ? Collections.emptyList() : Arrays.asList(qps); | |||||
return QPMeasureData.toJson(new QPMeasureData(qualityProfiles)); | |||||
} | |||||
} |