import org.sonar.ce.task.projectanalysis.filemove.AddedFileRepository;
import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRule;
import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRulesHolder;
+import org.sonar.ce.task.projectanalysis.qualityprofile.QProfileStatusRepository;
import org.sonar.ce.task.projectanalysis.scm.Changeset;
import org.sonar.ce.task.projectanalysis.scm.ScmInfo;
import org.sonar.ce.task.projectanalysis.scm.ScmInfoRepository;
import org.sonar.core.issue.IssueChangeContext;
import org.sonar.server.issue.IssueFieldsSetter;
+import static org.sonar.ce.task.projectanalysis.qualityprofile.QProfileStatusRepository.Status.UNCHANGED;
import static org.sonar.core.issue.IssueChangeContext.createScan;
/**
private final ActiveRulesHolder activeRulesHolder;
private final RuleRepository ruleRepository;
private final AddedFileRepository addedFileRepository;
+ private QProfileStatusRepository qProfileStatusRepository;
public IssueCreationDateCalculator(AnalysisMetadataHolder analysisMetadataHolder, ScmInfoRepository scmInfoRepository,
IssueFieldsSetter issueUpdater, ActiveRulesHolder activeRulesHolder, RuleRepository ruleRepository,
- AddedFileRepository addedFileRepository) {
+ AddedFileRepository addedFileRepository, QProfileStatusRepository qProfileStatusRepository) {
this.scmInfoRepository = scmInfoRepository;
this.issueUpdater = issueUpdater;
this.analysisMetadataHolder = analysisMetadataHolder;
this.changeContext = createScan(new Date(analysisMetadataHolder.getAnalysisDate()));
this.activeRulesHolder = activeRulesHolder;
this.addedFileRepository = addedFileRepository;
+ this.qProfileStatusRepository = qProfileStatusRepository;
}
@Override
// Rule can't be inactive (see contract of IssueVisitor)
ActiveRule activeRule = activeRulesHolder.get(issue.getRuleKey()).get();
if (activeRuleIsNewOrChanged(activeRule, lastAnalysisOptional.get())
- || ruleImplementationChanged(activeRule.getRuleKey(), activeRule.getPluginKey(), lastAnalysisOptional.get())) {
+ || ruleImplementationChanged(activeRule.getRuleKey(), activeRule.getPluginKey(), lastAnalysisOptional.get())
+ || qualityProfileChanged(activeRule.getQProfileKey())) {
backdateIssue(component, issue);
}
}
}
+ private boolean qualityProfileChanged(@Nullable String qpKey) {
+ // Support issue from report created before scanner protocol update -> no backdating
+ if (qpKey == null) {
+ return false;
+ }
+
+ return qProfileStatusRepository.get(qpKey).filter(s -> !s.equals(UNCHANGED)).isPresent();
+ }
+
private boolean isNewFile(Component component) {
return component.getType() == Component.Type.FILE && addedFileRepository.isAdded(component);
}
private final Map<String, String> params;
private final String pluginKey;
private final long updatedAt;
+ private final String qProfileKey;
- public ActiveRule(RuleKey ruleKey, String severity, Map<String, String> params, long updatedAt, @Nullable String pluginKey) {
+ public ActiveRule(RuleKey ruleKey, String severity, Map<String, String> params, long updatedAt, @Nullable String pluginKey, @Nullable String qProfileKey) {
this.ruleKey = ruleKey;
this.severity = severity;
this.pluginKey = pluginKey;
this.params = ImmutableMap.copyOf(params);
this.updatedAt = updatedAt;
+ this.qProfileKey = qProfileKey;
}
public RuleKey getRuleKey() {
public String getPluginKey() {
return pluginKey;
}
+
+ @CheckForNull
+ public String getQProfileKey() {
+ return qProfileKey;
+ }
}
import org.sonar.core.util.CloseableIterator;
import org.sonar.scanner.protocol.output.ScannerReport;
+import static com.google.common.base.Strings.emptyToNull;
+
public class LoadQualityProfilesStep implements ComputationStep {
private final BatchReportReader batchReportReader;
ScannerReport.ActiveRule scannerReportActiveRule = batchActiveRules.next();
Optional<Rule> rule = ruleRepository.findByKey(RuleKey.of(scannerReportActiveRule.getRuleRepository(), scannerReportActiveRule.getRuleKey()));
if (rule.isPresent() && rule.get().getStatus() != RuleStatus.REMOVED && !rule.get().isExternal()) {
- ActiveRule activeRule = convert(scannerReportActiveRule, rule.get());
- activeRules.add(activeRule);
+ activeRules.add(convert(scannerReportActiveRule, rule.get()));
}
}
}
RuleKey key = RuleKey.of(input.getRuleRepository(), input.getRuleKey());
Map<String, String> params = new HashMap<>(input.getParamsByKeyMap());
long updatedAt = input.getUpdatedAt();
- return new ActiveRule(key, input.getSeverity().name(), params, updatedAt == 0 ? input.getCreatedAt() : updatedAt, rule.getPluginKey());
+ return new ActiveRule(key, input.getSeverity().name(), params, updatedAt == 0 ? input.getCreatedAt() : updatedAt, rule.getPluginKey(), emptyToNull(input.getQProfileKey()));
}
}
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.projectanalysis.qualityprofile.QProfileStatusRepository;
import org.sonar.ce.task.step.ComputationStep;
import org.sonar.core.util.UtcDateUtils;
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.UPDATED;
/**
* Computation of quality profile events
private final MeasureRepository measureRepository;
private final EventRepository eventRepository;
private final LanguageRepository languageRepository;
+ private QProfileStatusRepository qProfileStatusRepository;
public QualityProfileEventsStep(TreeRootHolder treeRootHolder,
MetricRepository metricRepository, MeasureRepository measureRepository, LanguageRepository languageRepository,
- EventRepository eventRepository) {
+ EventRepository eventRepository, QProfileStatusRepository qProfileStatusRepository) {
this.treeRootHolder = treeRootHolder;
this.metricRepository = metricRepository;
this.measureRepository = measureRepository;
this.eventRepository = eventRepository;
this.languageRepository = languageRepository;
+ this.qProfileStatusRepository = qProfileStatusRepository;
}
@Override
return;
}
- // Load base profiles
+ // Load profiles used in current analysis for which at least one file of the corresponding language exists
Optional<Measure> rawMeasure = measureRepository.getRawMeasure(projectComponent, metricRepository.getByKey(CoreMetrics.QUALITY_PROFILES_KEY));
if (!rawMeasure.isPresent()) {
// No qualify profile computed on the project
Map<String, QualityProfile> baseProfiles = parseJsonData(baseMeasure.get());
detectNewOrUpdatedProfiles(projectComponent, baseProfiles, rawProfiles);
- detectNoMoreUsedProfiles(projectComponent, baseProfiles, rawProfiles);
+ detectNoMoreUsedProfiles(projectComponent, baseProfiles);
}
private static Map<String, QualityProfile> parseJsonData(Measure measure) {
return QPMeasureData.fromJson(data).getProfilesByKey();
}
- private void detectNoMoreUsedProfiles(Component context, Map<String, QualityProfile> baseProfiles, Map<String, QualityProfile> rawProfiles) {
+ private void detectNoMoreUsedProfiles(Component context, Map<String, QualityProfile> baseProfiles) {
for (QualityProfile baseProfile : baseProfiles.values()) {
- if (!rawProfiles.containsKey(baseProfile.getQpKey())) {
+ if (qProfileStatusRepository.get(baseProfile.getQpKey()).filter(REMOVED::equals).isPresent()) {
markAsRemoved(context, baseProfile);
}
}
private void detectNewOrUpdatedProfiles(Component component, Map<String, QualityProfile> baseProfiles, Map<String, QualityProfile> rawProfiles) {
for (QualityProfile profile : rawProfiles.values()) {
- QualityProfile baseProfile = baseProfiles.get(profile.getQpKey());
- if (baseProfile == null) {
- markAsAdded(component, profile);
- } else if (profile.getRulesUpdatedAt().after(baseProfile.getRulesUpdatedAt())) {
- markAsChanged(component, baseProfile, profile);
- }
+ qProfileStatusRepository.get(profile.getQpKey()).ifPresent(status -> {
+ if (status.equals(ADDED)) {
+ markAsAdded(component, profile);
+ } else if (status.equals(UPDATED)) {
+ markAsChanged(component, baseProfiles.get(profile.getQpKey()), profile);
+ }
+ });
}
}
import java.util.Map;
import java.util.Optional;
import java.util.function.BiConsumer;
+import java.util.stream.Stream;
+import org.apache.commons.lang.ArrayUtils;
import org.junit.Before;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.ce.task.projectanalysis.filemove.AddedFileRepository;
import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRule;
import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRulesHolder;
+import org.sonar.ce.task.projectanalysis.qualityprofile.QProfileStatusRepository;
import org.sonar.ce.task.projectanalysis.scm.Changeset;
import org.sonar.ce.task.projectanalysis.scm.ScmInfo;
import org.sonar.ce.task.projectanalysis.scm.ScmInfoRepository;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
+import static org.sonar.ce.task.projectanalysis.qualityprofile.QProfileStatusRepository.Status.UNCHANGED;
@RunWith(DataProviderRunner.class)
public class IssueCreationDateCalculatorTest {
private Map<String, ScannerPlugin> scannerPlugins = new HashMap<>();
private RuleRepository ruleRepository = mock(RuleRepository.class);
private AddedFileRepository addedFileRepository = mock(AddedFileRepository.class);
+ private QProfileStatusRepository qProfileStatusRepository = mock(QProfileStatusRepository.class);
private ScmInfo scmInfo;
private Rule rule = mock(Rule.class);
analysisMetadataHolder.setScannerPluginsByKey(scannerPlugins);
analysisMetadataHolder.setAnalysisDate(new Date());
when(component.getUuid()).thenReturn(COMPONENT_UUID);
- underTest = new IssueCreationDateCalculator(analysisMetadataHolder, scmInfoRepository, issueUpdater, activeRulesHolder, ruleRepository, addedFileRepository);
+ underTest = new IssueCreationDateCalculator(analysisMetadataHolder, scmInfoRepository, issueUpdater, activeRulesHolder, ruleRepository, addedFileRepository, qProfileStatusRepository);
when(ruleRepository.findByKey(ruleKey)).thenReturn(Optional.of(rule));
- when(activeRulesHolder.get(any(RuleKey.class)))
- .thenReturn(Optional.empty());
- when(activeRulesHolder.get(ruleKey))
- .thenReturn(Optional.of(activeRule));
- when(issue.getRuleKey())
- .thenReturn(ruleKey);
+ when(activeRulesHolder.get(any(RuleKey.class))).thenReturn(Optional.empty());
+ when(activeRulesHolder.get(ruleKey)).thenReturn(Optional.of(activeRule));
+ when(activeRule.getQProfileKey()).thenReturn("qpKey");
+ when(issue.getRuleKey()).thenReturn(ruleKey);
+ when(qProfileStatusRepository.get(any())).thenReturn(Optional.of(UNCHANGED));
}
@Test
assertChangeOfCreationDateTo(expectedDate);
}
+
+ @Test
+ @UseDataProvider("backdatingDateAndChangedQPStatusCases")
+ public void should_backdate_if_qp_of_the_rule_which_raised_the_issue_has_changed(BiConsumer<DefaultIssue, ScmInfo> configure, long expectedDate, QProfileStatusRepository.Status status) {
+ previousAnalysisWas(2000L);
+ currentAnalysisIs(3000L);
+
+ makeIssueNew();
+ configure.accept(issue, createMockScmInfo());
+ changeQualityProfile(status);
+
+ run();
+
+ assertChangeOfCreationDateTo(expectedDate);
+ }
+
@Test
@UseDataProvider("backdatingDateCases")
public void should_backdate_if_scm_is_available_and_plugin_is_new(BiConsumer<DefaultIssue, ScmInfo> configure, long expectedDate) {
verifyZeroInteractions(activeRulesHolder);
}
+ @DataProvider
+ public static Object[][] backdatingDateAndChangedQPStatusCases() {
+ return Stream.of(backdatingDateCases())
+ .flatMap(datesCases ->
+ Stream.of(QProfileStatusRepository.Status.values())
+ .filter(s -> !UNCHANGED.equals(s))
+ .map(s -> ArrayUtils.add(datesCases, s)))
+ .toArray(Object[][]::new);
+ }
+
@DataProvider
public static Object[][] backdatingDateCases() {
return new Object[][] {
.thenReturn(false);
}
+ private void changeQualityProfile(QProfileStatusRepository.Status status) {
+ when(qProfileStatusRepository.get(any())).thenReturn(Optional.of(status));
+ }
+
private void setIssueBelongToNonExistingRule() {
when(issue.getRuleKey())
.thenReturn(RuleKey.of("repo", "disabled"));
}
private void markRuleAsActive(RuleKey ruleKey) {
- activeRulesHolder.put(new ActiveRule(ruleKey, Severity.CRITICAL, emptyMap(), 1_000L, null));
+ activeRulesHolder.put(new ActiveRule(ruleKey, Severity.CRITICAL, emptyMap(), 1_000L, null, "qp1"));
}
}
public class CommentDensityRuleTest {
private static final String PLUGIN_KEY = "java";
+ private static final String QP_KEY = "qp1";
static RuleKey RULE_KEY = RuleKey.of(CommonRuleKeys.commonRepositoryForLang(PLUGIN_KEY), CommonRuleKeys.INSUFFICIENT_COMMENT_DENSITY);
@Test
public void no_issues_if_enough_comments() {
- activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, ImmutableMap.of(CommonRuleKeys.INSUFFICIENT_COMMENT_DENSITY_PROPERTY, "25"), 1_000L, PLUGIN_KEY));
+ activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, ImmutableMap.of(CommonRuleKeys.INSUFFICIENT_COMMENT_DENSITY_PROPERTY, "25"), 1_000L, PLUGIN_KEY, QP_KEY));
measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.COMMENT_LINES_DENSITY_KEY, Measure.newMeasureBuilder().create(90.0, 1));
DefaultIssue issue = underTest.processFile(FILE, PLUGIN_KEY);
}
private void prepareForIssue(String minDensity, ReportComponent file, double commentLineDensity, int commentLines, int ncloc) {
- activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, ImmutableMap.of(CommonRuleKeys.INSUFFICIENT_COMMENT_DENSITY_PROPERTY, minDensity), 1_000L, PLUGIN_KEY));
+ activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, ImmutableMap.of(CommonRuleKeys.INSUFFICIENT_COMMENT_DENSITY_PROPERTY, minDensity), 1_000L, PLUGIN_KEY, QP_KEY));
measureRepository.addRawMeasure(file.getReportAttributes().getRef(), CoreMetrics.COMMENT_LINES_DENSITY_KEY, Measure.newMeasureBuilder().create(commentLineDensity, 1));
measureRepository.addRawMeasure(file.getReportAttributes().getRef(), CoreMetrics.COMMENT_LINES_KEY, Measure.newMeasureBuilder().create(commentLines));
measureRepository.addRawMeasure(file.getReportAttributes().getRef(), CoreMetrics.NCLOC_KEY, Measure.newMeasureBuilder().create(ncloc));
public class CommonRuleTest {
private static final String PLUGIN_KEY = "java";
+ private static final String QP_KEY = "qp1";
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void test_getMinDensityParam() {
- ActiveRule activeRule = new ActiveRule(RuleTesting.XOO_X1, Severity.MAJOR, ImmutableMap.of("minDensity", "30.5"), 1_000L, PLUGIN_KEY);
+ ActiveRule activeRule = new ActiveRule(RuleTesting.XOO_X1, Severity.MAJOR, ImmutableMap.of("minDensity", "30.5"), 1_000L, PLUGIN_KEY, QP_KEY);
double minDensity = CommonRule.getMinDensityParam(activeRule, "minDensity");
assertThat(minDensity).isEqualTo(30.5);
thrown.expect(IllegalStateException.class);
thrown.expectMessage("Required parameter [minDensity] is missing on rule [xoo:x1]");
- ActiveRule activeRule = new ActiveRule(RuleTesting.XOO_X1, Severity.MAJOR, ImmutableMap.of(), 1_000L, PLUGIN_KEY);
+ ActiveRule activeRule = new ActiveRule(RuleTesting.XOO_X1, Severity.MAJOR, ImmutableMap.of(), 1_000L, PLUGIN_KEY, QP_KEY);
CommonRule.getMinDensityParam(activeRule, "minDensity");
}
thrown.expect(IllegalStateException.class);
thrown.expectMessage("Minimum density of rule [xoo:x1] is incorrect. Got [-30.5] but must be between 0 and 100.");
- ActiveRule activeRule = new ActiveRule(RuleTesting.XOO_X1, Severity.MAJOR, ImmutableMap.of("minDensity", "-30.5"), 1_000L, PLUGIN_KEY);
+ ActiveRule activeRule = new ActiveRule(RuleTesting.XOO_X1, Severity.MAJOR, ImmutableMap.of("minDensity", "-30.5"), 1_000L, PLUGIN_KEY, QP_KEY);
CommonRule.getMinDensityParam(activeRule, "minDensity");
}
thrown.expect(IllegalStateException.class);
thrown.expectMessage("Minimum density of rule [xoo:x1] is incorrect. Got [305] but must be between 0 and 100.");
- ActiveRule activeRule = new ActiveRule(RuleTesting.XOO_X1, Severity.MAJOR, ImmutableMap.of("minDensity", "305"), 1_000L, PLUGIN_KEY);
+ ActiveRule activeRule = new ActiveRule(RuleTesting.XOO_X1, Severity.MAJOR, ImmutableMap.of("minDensity", "305"), 1_000L, PLUGIN_KEY, QP_KEY);
CommonRule.getMinDensityParam(activeRule, "minDensity");
}
}
public abstract class CoverageRuleTest {
private static final String PLUGIN_KEY = "java";
+ private static final String QP_KEY = "qp1";
static ReportComponent FILE = ReportComponent.builder(Component.Type.FILE, 1)
.setFileAttributes(new FileAttributes(false, "java", 1))
@Test
public void no_issue_if_enough_coverage() {
- activeRuleHolder.put(new ActiveRule(getRuleKey(), Severity.CRITICAL, ImmutableMap.of(getMinPropertyKey(), "65"), 1_000L, PLUGIN_KEY));
+ activeRuleHolder.put(new ActiveRule(getRuleKey(), Severity.CRITICAL, ImmutableMap.of(getMinPropertyKey(), "65"), 1_000L, PLUGIN_KEY, QP_KEY));
measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), getCoverageMetricKey(), Measure.newMeasureBuilder().create(90.0, 1));
DefaultIssue issue = underTest.processFile(FILE, "java");
@Test
public void issue_if_coverage_is_too_low() {
- activeRuleHolder.put(new ActiveRule(getRuleKey(), Severity.CRITICAL, ImmutableMap.of(getMinPropertyKey(), "65"), 1_000L, PLUGIN_KEY));
+ activeRuleHolder.put(new ActiveRule(getRuleKey(), Severity.CRITICAL, ImmutableMap.of(getMinPropertyKey(), "65"), 1_000L, PLUGIN_KEY, QP_KEY));
measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), getCoverageMetricKey(), Measure.newMeasureBuilder().create(20.0, 1));
measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), getUncoveredMetricKey(), Measure.newMeasureBuilder().create(40));
measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), getToCoverMetricKey(), Measure.newMeasureBuilder().create(50));
@Test
public void no_issue_if_coverage_is_not_set() {
- activeRuleHolder.put(new ActiveRule(getRuleKey(), Severity.CRITICAL, ImmutableMap.of(getMinPropertyKey(), "65"), 1_000L, PLUGIN_KEY));
+ activeRuleHolder.put(new ActiveRule(getRuleKey(), Severity.CRITICAL, ImmutableMap.of(getMinPropertyKey(), "65"), 1_000L, PLUGIN_KEY, QP_KEY));
DefaultIssue issue = underTest.processFile(FILE, "java");
public class DuplicatedBlockRuleTest {
private static final String PLUGIN_KEY = "java";
+ private static final String QP_KEY = "qp1";
static RuleKey RULE_KEY = RuleKey.of(CommonRuleKeys.commonRepositoryForLang("java"), CommonRuleKeys.DUPLICATED_BLOCKS);
@Test
public void no_issue_if_no_duplicated_blocks() {
- activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.emptyMap(), 1_000L, PLUGIN_KEY));
+ activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.emptyMap(), 1_000L, PLUGIN_KEY, QP_KEY));
measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.DUPLICATED_BLOCKS_KEY, Measure.newMeasureBuilder().create(0));
DefaultIssue issue = underTest.processFile(FILE, "java");
@Test
public void issue_if_duplicated_blocks() {
- activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.emptyMap(), 1_000L, PLUGIN_KEY));
+ activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.emptyMap(), 1_000L, PLUGIN_KEY, QP_KEY));
measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.DUPLICATED_BLOCKS_KEY, Measure.newMeasureBuilder().create(3));
DefaultIssue issue = underTest.processFile(FILE, "java");
public class SkippedTestRuleTest {
private static final String PLUGIN_KEY = "java";
+ private static final String QP_KEY = "qp1";
static RuleKey RULE_KEY = RuleKey.of(CommonRuleKeys.commonRepositoryForLang("java"), CommonRuleKeys.SKIPPED_UNIT_TESTS);
@Test
public void issue_if_skipped_tests() {
- activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.emptyMap(), 1_000L, PLUGIN_KEY));
+ activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.emptyMap(), 1_000L, PLUGIN_KEY, QP_KEY));
measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.SKIPPED_TESTS_KEY, Measure.newMeasureBuilder().create(2));
DefaultIssue issue = underTest.processFile(FILE, "java");
@Test
public void no_issues_if_zero_skipped_tests() {
- activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.emptyMap(), 1_000L, PLUGIN_KEY));
+ activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.emptyMap(), 1_000L, PLUGIN_KEY, QP_KEY));
measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.SKIPPED_TESTS_KEY, Measure.newMeasureBuilder().create(0));
DefaultIssue issue = underTest.processFile(FILE, "java");
@Test
public void no_issues_if_measure_is_absent() {
- activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.emptyMap(), 1_000L, PLUGIN_KEY));
+ activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.emptyMap(), 1_000L, PLUGIN_KEY, QP_KEY));
DefaultIssue issue = underTest.processFile(FILE, "java");
public class TestErrorRuleTest {
private static final String PLUGIN_KEY = "java";
+ private static final String QP_KEY = "qp1";
static RuleKey RULE_KEY = RuleKey.of(CommonRuleKeys.commonRepositoryForLang("java"), CommonRuleKeys.FAILED_UNIT_TESTS);
@Test
public void issue_if_errors_or_failures() {
- activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.emptyMap(), 1_000L, PLUGIN_KEY));
+ activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.emptyMap(), 1_000L, PLUGIN_KEY, QP_KEY));
measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.TEST_ERRORS_KEY, Measure.newMeasureBuilder().create(2));
measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.TEST_FAILURES_KEY, Measure.newMeasureBuilder().create(1));
@Test
public void no_issues_if_zero_errors_and_failures() {
- activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.emptyMap(), 1_000L, PLUGIN_KEY));
+ activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.emptyMap(), 1_000L, PLUGIN_KEY, QP_KEY));
measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.TEST_ERRORS_KEY, Measure.newMeasureBuilder().create(0));
measureRepository.addRawMeasure(FILE.getReportAttributes().getRef(), CoreMetrics.TEST_FAILURES_KEY, Measure.newMeasureBuilder().create(0));
@Test
public void no_issues_if_test_measures_are_absent() {
- activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.emptyMap(), 1_000L, PLUGIN_KEY));
+ activeRuleHolder.put(new ActiveRule(RULE_KEY, Severity.CRITICAL, Collections.emptyMap(), 1_000L, PLUGIN_KEY, QP_KEY));
DefaultIssue issue = underTest.processFile(FILE, "java");
private static final long SOME_DATE = 1_000L;
static final RuleKey RULE_KEY = RuleKey.of("squid", "S001");
+ private static final String QP_KEY = "qp1";
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void get_active_rule() {
- underTest.set(asList(new ActiveRule(RULE_KEY, Severity.BLOCKER, Collections.emptyMap(), SOME_DATE, PLUGIN_KEY)));
+ underTest.set(asList(new ActiveRule(RULE_KEY, Severity.BLOCKER, Collections.emptyMap(), SOME_DATE, PLUGIN_KEY, QP_KEY)));
Optional<ActiveRule> activeRule = underTest.get(RULE_KEY);
assertThat(activeRule.isPresent()).isTrue();
thrown.expect(IllegalStateException.class);
thrown.expectMessage("Active rules have already been initialized");
- underTest.set(asList(new ActiveRule(RULE_KEY, Severity.BLOCKER, Collections.emptyMap(), SOME_DATE, PLUGIN_KEY)));
+ underTest.set(asList(new ActiveRule(RULE_KEY, Severity.BLOCKER, Collections.emptyMap(), SOME_DATE, PLUGIN_KEY, QP_KEY)));
underTest.set(Collections.emptyList());
}
thrown.expectMessage("Active rule must not be declared multiple times: squid:S001");
underTest.set(asList(
- new ActiveRule(RULE_KEY, Severity.BLOCKER, Collections.emptyMap(), SOME_DATE, PLUGIN_KEY),
- new ActiveRule(RULE_KEY, Severity.MAJOR, Collections.emptyMap(), SOME_DATE, PLUGIN_KEY)));
+ new ActiveRule(RULE_KEY, Severity.BLOCKER, Collections.emptyMap(), SOME_DATE, PLUGIN_KEY, QP_KEY),
+ new ActiveRule(RULE_KEY, Severity.MAJOR, Collections.emptyMap(), SOME_DATE, PLUGIN_KEY, QP_KEY)));
}
}
public class AlwaysActiveRulesHolderImpl implements ActiveRulesHolder {
@Override
public Optional<ActiveRule> get(RuleKey ruleKey) {
- return Optional.of(new ActiveRule(ruleKey, Severity.MAJOR, emptyMap(), 1_000L, null));
+ return Optional.of(new ActiveRule(ruleKey, Severity.MAJOR, emptyMap(), 1_000L, null, "qp1"));
}
}
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.QProfileStatusRepository;
+import org.sonar.ce.task.projectanalysis.qualityprofile.QProfileStatusRepositoryImpl;
import org.sonar.ce.task.step.TestComputationStepContext;
import org.sonar.core.util.UtcDateUtils;
import org.sonar.server.qualityprofile.QPMeasureData;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import static org.sonar.api.utils.DateUtils.parseDateTime;
+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 QualityProfileEventsStepTest {
@Rule
private LanguageRepository languageRepository = mock(LanguageRepository.class);
private EventRepository eventRepository = mock(EventRepository.class);
private ArgumentCaptor<Event> eventArgumentCaptor = ArgumentCaptor.forClass(Event.class);
+ private MutableQProfileStatusRepository qProfileStatusRepository = new QProfileStatusRepositoryImpl();
private Metric qualityProfileMetric = mock(Metric.class);
- private QualityProfileEventsStep underTest = new QualityProfileEventsStep(treeRootHolder, metricRepository, measureRepository, languageRepository, eventRepository);
+ private QualityProfileEventsStep underTest = new QualityProfileEventsStep(treeRootHolder, metricRepository, measureRepository, languageRepository, eventRepository, qProfileStatusRepository);
@Before
public void setUp() {
}
@Test
- public void added_event_if_one_new_qp() {
+ public void added_event_if_qp_is_added() {
QualityProfile qp = qp(QP_NAME_1, LANGUAGE_KEY_1, new Date());
+ qProfileStatusRepository.register(qp.getQpKey(), ADDED);
Language language = mockLanguageInRepository(LANGUAGE_KEY_1);
mockMeasures(treeRootHolder.getRoot(), null, arrayOf(qp));
@Test
public void added_event_uses_language_key_in_message_if_language_not_found() {
QualityProfile qp = qp(QP_NAME_1, LANGUAGE_KEY_1, new Date());
+ qProfileStatusRepository.register(qp.getQpKey(), ADDED);
mockLanguageNotInRepository(LANGUAGE_KEY_1);
mockMeasures(treeRootHolder.getRoot(), null, arrayOf(qp));
}
@Test
- public void no_more_used_event_if_qp_no_more_listed() {
+ public void no_more_used_event_if_qp_is_removed() {
QualityProfile qp = qp(QP_NAME_1, LANGUAGE_KEY_1, new Date());
+ qProfileStatusRepository.register(qp.getQpKey(), REMOVED);
mockMeasures(treeRootHolder.getRoot(), arrayOf(qp), null);
Language language = mockLanguageInRepository(LANGUAGE_KEY_1);
@Test
public void no_more_used_event_uses_language_key_in_message_if_language_not_found() {
QualityProfile qp = qp(QP_NAME_1, LANGUAGE_KEY_1, new Date());
-
+ qProfileStatusRepository.register(qp.getQpKey(), REMOVED);
mockMeasures(treeRootHolder.getRoot(), arrayOf(qp), null);
mockLanguageNotInRepository(LANGUAGE_KEY_1);
}
@Test
- public void no_event_if_same_qp_with_same_date() {
+ public void no_event_if_qp_is_unchanged() {
QualityProfile qp = qp(QP_NAME_1, LANGUAGE_KEY_1, new Date());
-
+ qProfileStatusRepository.register(qp.getQpKey(), UNCHANGED);
mockMeasures(treeRootHolder.getRoot(), arrayOf(qp), arrayOf(qp));
underTest.execute(new TestComputationStepContext());
}
@Test
- public void changed_event_if_same_qp_but_no_same_date() {
+ public void changed_event_if_qp_has_been_updated() {
QualityProfile qp1 = qp(QP_NAME_1, LANGUAGE_KEY_1, parseDateTime("2011-04-25T01:05:13+0100"));
QualityProfile qp2 = qp(QP_NAME_1, LANGUAGE_KEY_1, parseDateTime("2011-04-25T01:05:17+0100"));
-
+ qProfileStatusRepository.register(qp2.getQpKey(), UPDATED);
mockMeasures(treeRootHolder.getRoot(), arrayOf(qp1), arrayOf(qp2));
Language language = mockLanguageInRepository(LANGUAGE_KEY_1);
}).when(eventRepository).add(eq(treeRootHolder.getRoot()), any(Event.class));
Date date = new Date();
+ QualityProfile qp1 = qp(QP_NAME_2, LANGUAGE_KEY_1, date);
+ QualityProfile qp2 = qp(QP_NAME_2, LANGUAGE_KEY_2, date);
+ QualityProfile qp3 = qp(QP_NAME_1, LANGUAGE_KEY_1, parseDateTime("2011-04-25T01:05:13+0100"));
+ QualityProfile qp3_updated = qp(QP_NAME_1, LANGUAGE_KEY_1, parseDateTime("2011-04-25T01:05:17+0100"));
+ QualityProfile qp4 = qp(QP_NAME_2, LANGUAGE_KEY_3, date);
+
mockMeasures(
treeRootHolder.getRoot(),
- arrayOf(
- qp(QP_NAME_2, LANGUAGE_KEY_1, date),
- qp(QP_NAME_2, LANGUAGE_KEY_2, date),
- qp(QP_NAME_1, LANGUAGE_KEY_1, parseDateTime("2011-04-25T01:05:13+0100"))),
- arrayOf(
- qp(QP_NAME_1, LANGUAGE_KEY_1, parseDateTime("2011-04-25T01:05:17+0100")),
- qp(QP_NAME_2, LANGUAGE_KEY_2, date),
- qp(QP_NAME_2, LANGUAGE_KEY_3, date)));
+ arrayOf(qp1, qp2, qp3),
+ arrayOf(qp3_updated, qp2, qp4));
mockNoLanguageInRepository();
+ qProfileStatusRepository.register(qp1.getQpKey(), REMOVED);
+ qProfileStatusRepository.register(qp2.getQpKey(), UNCHANGED);
+ qProfileStatusRepository.register(qp3.getQpKey(), UPDATED);
+ qProfileStatusRepository.register(qp4.getQpKey(), ADDED);
underTest.execute(new TestComputationStepContext());
"Stop using '" + QP_NAME_2 + "' (" + LANGUAGE_KEY_1 + ")",
"Use '" + QP_NAME_2 + "' (" + LANGUAGE_KEY_3 + ")",
"Changes in '" + QP_NAME_1 + "' (" + LANGUAGE_KEY_1 + ")");
-
}
private Language mockLanguageInRepository(String languageKey) {