@@ -110,6 +110,7 @@ import org.sonar.ce.task.projectanalysis.qualitymodel.NewReliabilityAndSecurityR | |||
import org.sonar.ce.task.projectanalysis.qualitymodel.RatingSettings; | |||
import org.sonar.ce.task.projectanalysis.qualitymodel.ReliabilityAndSecurityRatingMeasuresVisitor; | |||
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.ScmInfoRepositoryImpl; | |||
import org.sonar.ce.task.projectanalysis.source.DbLineHashVersion; | |||
@@ -218,6 +219,7 @@ public final class ProjectAnalysisTaskContainerPopulator implements ContainerPop | |||
NewLinesRepository.class, | |||
FileSourceDataComputer.class, | |||
SourceLineReadersFactory.class, | |||
QProfileStatusRepositoryImpl.class, | |||
// issues | |||
RuleRepositoryImpl.class, |
@@ -0,0 +1,27 @@ | |||
/* | |||
* 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); | |||
} |
@@ -0,0 +1,46 @@ | |||
/* | |||
* 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 | |||
} | |||
} |
@@ -0,0 +1,45 @@ | |||
/* | |||
* 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); | |||
} | |||
} |
@@ -0,0 +1,123 @@ | |||
/* | |||
* 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"; | |||
} | |||
} |
@@ -25,6 +25,7 @@ import org.sonar.ce.task.container.TaskContainer; | |||
import org.sonar.ce.task.projectanalysis.filemove.FileMoveDetectionStep; | |||
import org.sonar.ce.task.projectanalysis.measure.PostMeasuresComputationChecksStep; | |||
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.step.ComputationStep; | |||
import org.sonar.ce.task.step.ExecuteStatelessInitExtensionsStep; | |||
@@ -73,6 +74,7 @@ public class ReportComputationSteps extends AbstractComputationSteps { | |||
ComplexityMeasuresStep.class, | |||
LoadMeasureComputersStep.class, | |||
RegisterQualityProfileStatusStep.class, | |||
ExecuteVisitorsStep.class, | |||
PostMeasuresComputationChecksStep.class, |
@@ -0,0 +1,101 @@ | |||
/* | |||
* 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); | |||
} | |||
} |
@@ -0,0 +1,179 @@ | |||
/* | |||
* 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)); | |||
} | |||
} |