Browse Source

SONAR-11515 Backdate issue when QP has changed

tags/7.5
Benoît Gianinetti 5 years ago
parent
commit
eaac2bf873
15 changed files with 148 additions and 64 deletions
  1. 16
    2
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/IssueCreationDateCalculator.java
  2. 8
    1
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/qualityprofile/ActiveRule.java
  3. 4
    3
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/LoadQualityProfilesStep.java
  4. 18
    11
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/QualityProfileEventsStep.java
  5. 41
    7
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/IssueCreationDateCalculatorTest.java
  6. 1
    1
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/TrackerRawInputFactoryTest.java
  7. 3
    2
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/commonrule/CommentDensityRuleTest.java
  8. 5
    4
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/commonrule/CommonRuleTest.java
  9. 4
    3
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/commonrule/CoverageRuleTest.java
  10. 3
    2
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/commonrule/DuplicatedBlockRuleTest.java
  11. 4
    3
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/commonrule/SkippedTestRuleTest.java
  12. 4
    3
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/commonrule/TestErrorRuleTest.java
  13. 5
    4
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/qualityprofile/ActiveRulesHolderImplTest.java
  14. 1
    1
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/qualityprofile/AlwaysActiveRulesHolderImpl.java
  15. 31
    17
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/QualityProfileEventsStepTest.java

+ 16
- 2
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/IssueCreationDateCalculator.java View File

@@ -33,6 +33,7 @@ import org.sonar.ce.task.projectanalysis.component.Component;
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;
@@ -40,6 +41,7 @@ import org.sonar.core.issue.DefaultIssue;
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;

/**
@@ -55,10 +57,11 @@ public class IssueCreationDateCalculator extends IssueVisitor {
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;
@@ -66,6 +69,7 @@ public class IssueCreationDateCalculator extends IssueVisitor {
this.changeContext = createScan(new Date(analysisMetadataHolder.getAnalysisDate()));
this.activeRulesHolder = activeRulesHolder;
this.addedFileRepository = addedFileRepository;
this.qProfileStatusRepository = qProfileStatusRepository;
}

@Override
@@ -89,12 +93,22 @@ public class IssueCreationDateCalculator extends IssueVisitor {
// 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);
}

+ 8
- 1
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/qualityprofile/ActiveRule.java View File

@@ -33,13 +33,15 @@ public class ActiveRule {
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() {
@@ -62,4 +64,9 @@ public class ActiveRule {
public String getPluginKey() {
return pluginKey;
}

@CheckForNull
public String getQProfileKey() {
return qProfileKey;
}
}

+ 4
- 3
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/LoadQualityProfilesStep.java View File

@@ -35,6 +35,8 @@ import org.sonar.ce.task.step.ComputationStep;
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;
@@ -55,8 +57,7 @@ public class LoadQualityProfilesStep implements ComputationStep {
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()));
}
}
}
@@ -73,6 +74,6 @@ public class LoadQualityProfilesStep implements ComputationStep {
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()));
}
}

+ 18
- 11
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/QualityProfileEventsStep.java View File

@@ -40,12 +40,16 @@ import org.sonar.ce.task.projectanalysis.language.LanguageRepository;
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
@@ -58,15 +62,17 @@ public class QualityProfileEventsStep implements ComputationStep {
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
@@ -87,7 +93,7 @@ public class QualityProfileEventsStep implements ComputationStep {
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
@@ -97,7 +103,7 @@ public class QualityProfileEventsStep implements ComputationStep {

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) {
@@ -108,9 +114,9 @@ public class QualityProfileEventsStep implements ComputationStep {
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);
}
}
@@ -118,12 +124,13 @@ public class QualityProfileEventsStep implements ComputationStep {

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);
}
});
}
}


+ 41
- 7
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/IssueCreationDateCalculatorTest.java View File

@@ -28,6 +28,8 @@ import java.util.HashMap;
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;
@@ -40,6 +42,7 @@ import org.sonar.ce.task.projectanalysis.component.Component;
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;
@@ -60,6 +63,7 @@ import static org.mockito.Mockito.never;
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 {
@@ -84,6 +88,7 @@ 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);

@@ -92,15 +97,14 @@ public class IssueCreationDateCalculatorTest {
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
@@ -251,6 +255,22 @@ public class IssueCreationDateCalculatorTest {

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) {
@@ -302,6 +322,16 @@ public class IssueCreationDateCalculatorTest {
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[][] {
@@ -401,6 +431,10 @@ public class IssueCreationDateCalculatorTest {
.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"));

+ 1
- 1
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/TrackerRawInputFactoryTest.java View File

@@ -367,6 +367,6 @@ public class TrackerRawInputFactoryTest {
}

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"));
}
}

+ 3
- 2
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/commonrule/CommentDensityRuleTest.java View File

@@ -44,6 +44,7 @@ import static org.sonar.ce.task.projectanalysis.component.ReportComponent.DUMB_P
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);

@@ -77,7 +78,7 @@ public class CommentDensityRuleTest {

@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);
@@ -135,7 +136,7 @@ public class CommentDensityRuleTest {
}

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));

+ 5
- 4
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/commonrule/CommonRuleTest.java View File

@@ -32,13 +32,14 @@ import static org.assertj.core.api.Assertions.assertThat;
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);
@@ -49,7 +50,7 @@ public class CommonRuleTest {
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");
}

@@ -58,7 +59,7 @@ public class CommonRuleTest {
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");
}

@@ -67,7 +68,7 @@ public class CommonRuleTest {
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");
}
}

+ 4
- 3
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/commonrule/CoverageRuleTest.java View File

@@ -42,6 +42,7 @@ import static org.assertj.core.api.Assertions.assertThat;
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))
@@ -86,7 +87,7 @@ public abstract class CoverageRuleTest {

@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");
@@ -96,7 +97,7 @@ public abstract class CoverageRuleTest {

@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));
@@ -114,7 +115,7 @@ public abstract class CoverageRuleTest {

@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");


+ 3
- 2
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/commonrule/DuplicatedBlockRuleTest.java View File

@@ -42,6 +42,7 @@ import static org.assertj.core.api.Assertions.assertThat;
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);

@@ -66,7 +67,7 @@ public class DuplicatedBlockRuleTest {

@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");
@@ -76,7 +77,7 @@ public class DuplicatedBlockRuleTest {

@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");

+ 4
- 3
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/commonrule/SkippedTestRuleTest.java View File

@@ -42,6 +42,7 @@ import static org.assertj.core.api.Assertions.assertThat;
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);

@@ -67,7 +68,7 @@ public class SkippedTestRuleTest {

@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");
@@ -80,7 +81,7 @@ public class SkippedTestRuleTest {

@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");
@@ -90,7 +91,7 @@ public class SkippedTestRuleTest {

@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");


+ 4
- 3
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/commonrule/TestErrorRuleTest.java View File

@@ -43,6 +43,7 @@ import static org.sonar.ce.task.projectanalysis.component.ReportComponent.DUMB_P
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);

@@ -69,7 +70,7 @@ public class TestErrorRuleTest {

@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));

@@ -83,7 +84,7 @@ public class TestErrorRuleTest {

@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));

@@ -94,7 +95,7 @@ public class TestErrorRuleTest {

@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");


+ 5
- 4
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/qualityprofile/ActiveRulesHolderImplTest.java View File

@@ -37,6 +37,7 @@ public class ActiveRulesHolderImplTest {
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();
@@ -52,7 +53,7 @@ public class ActiveRulesHolderImplTest {

@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();
@@ -65,7 +66,7 @@ public class ActiveRulesHolderImplTest {
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());

}
@@ -84,7 +85,7 @@ public class ActiveRulesHolderImplTest {
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)));
}
}

+ 1
- 1
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/qualityprofile/AlwaysActiveRulesHolderImpl.java View File

@@ -28,7 +28,7 @@ import static java.util.Collections.emptyMap;
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"));
}

}

+ 31
- 17
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/QualityProfileEventsStepTest.java View File

@@ -44,6 +44,9 @@ 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.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;
@@ -60,6 +63,10 @@ import static org.mockito.Mockito.verify;
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
@@ -76,10 +83,11 @@ public class QualityProfileEventsStepTest {
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() {
@@ -116,8 +124,9 @@ public class QualityProfileEventsStepTest {
}

@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));
@@ -132,6 +141,7 @@ public class QualityProfileEventsStepTest {
@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));
@@ -144,8 +154,9 @@ public class QualityProfileEventsStepTest {
}

@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);
@@ -160,7 +171,7 @@ public class QualityProfileEventsStepTest {
@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);

@@ -172,9 +183,9 @@ public class QualityProfileEventsStepTest {
}

@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());
@@ -183,10 +194,10 @@ public class QualityProfileEventsStepTest {
}

@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);

@@ -209,17 +220,21 @@ public class QualityProfileEventsStepTest {
}).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());

@@ -227,7 +242,6 @@ public class QualityProfileEventsStepTest {
"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) {

Loading…
Cancel
Save