group=org.sonarsource.sonarqube | group=org.sonarsource.sonarqube | ||||
version=10.5 | version=10.5 | ||||
pluginApiVersion=10.6.0.2114 | |||||
pluginApiVersion=10.7.0.2175 | |||||
description=Open source platform for continuous inspection of code quality | description=Open source platform for continuous inspection of code quality | ||||
projectTitle=SonarQube | projectTitle=SonarQube | ||||
org.gradle.jvmargs=-Xmx2048m | org.gradle.jvmargs=-Xmx2048m |
import static org.sonar.api.measures.CoreMetrics.FALSE_POSITIVE_ISSUES_KEY; | import static org.sonar.api.measures.CoreMetrics.FALSE_POSITIVE_ISSUES_KEY; | ||||
import static org.sonar.api.measures.CoreMetrics.HIGH_IMPACT_ACCEPTED_ISSUES_KEY; | import static org.sonar.api.measures.CoreMetrics.HIGH_IMPACT_ACCEPTED_ISSUES_KEY; | ||||
import static org.sonar.api.measures.CoreMetrics.INFO_VIOLATIONS_KEY; | import static org.sonar.api.measures.CoreMetrics.INFO_VIOLATIONS_KEY; | ||||
import static org.sonar.api.measures.CoreMetrics.MAINTAINABILITY_ISSUES; | |||||
import static org.sonar.api.measures.CoreMetrics.MAINTAINABILITY_ISSUES_KEY; | |||||
import static org.sonar.api.measures.CoreMetrics.MAJOR_VIOLATIONS_KEY; | import static org.sonar.api.measures.CoreMetrics.MAJOR_VIOLATIONS_KEY; | ||||
import static org.sonar.api.measures.CoreMetrics.MINOR_VIOLATIONS_KEY; | import static org.sonar.api.measures.CoreMetrics.MINOR_VIOLATIONS_KEY; | ||||
import static org.sonar.api.measures.CoreMetrics.NEW_ACCEPTED_ISSUES_KEY; | import static org.sonar.api.measures.CoreMetrics.NEW_ACCEPTED_ISSUES_KEY; | ||||
import static org.sonar.api.measures.CoreMetrics.NEW_CODE_SMELLS_KEY; | import static org.sonar.api.measures.CoreMetrics.NEW_CODE_SMELLS_KEY; | ||||
import static org.sonar.api.measures.CoreMetrics.NEW_CRITICAL_VIOLATIONS_KEY; | import static org.sonar.api.measures.CoreMetrics.NEW_CRITICAL_VIOLATIONS_KEY; | ||||
import static org.sonar.api.measures.CoreMetrics.NEW_INFO_VIOLATIONS_KEY; | import static org.sonar.api.measures.CoreMetrics.NEW_INFO_VIOLATIONS_KEY; | ||||
import static org.sonar.api.measures.CoreMetrics.NEW_MAINTAINABILITY_ISSUES_KEY; | |||||
import static org.sonar.api.measures.CoreMetrics.NEW_MAJOR_VIOLATIONS_KEY; | import static org.sonar.api.measures.CoreMetrics.NEW_MAJOR_VIOLATIONS_KEY; | ||||
import static org.sonar.api.measures.CoreMetrics.NEW_MINOR_VIOLATIONS_KEY; | import static org.sonar.api.measures.CoreMetrics.NEW_MINOR_VIOLATIONS_KEY; | ||||
import static org.sonar.api.measures.CoreMetrics.NEW_RELIABILITY_ISSUES_KEY; | |||||
import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_HOTSPOTS_KEY; | import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_HOTSPOTS_KEY; | ||||
import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_ISSUES_KEY; | |||||
import static org.sonar.api.measures.CoreMetrics.NEW_VIOLATIONS_KEY; | import static org.sonar.api.measures.CoreMetrics.NEW_VIOLATIONS_KEY; | ||||
import static org.sonar.api.measures.CoreMetrics.NEW_VULNERABILITIES_KEY; | import static org.sonar.api.measures.CoreMetrics.NEW_VULNERABILITIES_KEY; | ||||
import static org.sonar.api.measures.CoreMetrics.OPEN_ISSUES_KEY; | import static org.sonar.api.measures.CoreMetrics.OPEN_ISSUES_KEY; | ||||
import static org.sonar.api.measures.CoreMetrics.RELIABILITY_ISSUES; | |||||
import static org.sonar.api.measures.CoreMetrics.RELIABILITY_ISSUES_KEY; | |||||
import static org.sonar.api.measures.CoreMetrics.REOPENED_ISSUES_KEY; | import static org.sonar.api.measures.CoreMetrics.REOPENED_ISSUES_KEY; | ||||
import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_KEY; | import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_KEY; | ||||
import static org.sonar.api.measures.CoreMetrics.SECURITY_ISSUES; | |||||
import static org.sonar.api.measures.CoreMetrics.SECURITY_ISSUES_KEY; | |||||
import static org.sonar.api.measures.CoreMetrics.VIOLATIONS_KEY; | import static org.sonar.api.measures.CoreMetrics.VIOLATIONS_KEY; | ||||
import static org.sonar.api.measures.CoreMetrics.VULNERABILITIES_KEY; | import static org.sonar.api.measures.CoreMetrics.VULNERABILITIES_KEY; | ||||
import static org.sonar.api.rule.Severity.BLOCKER; | import static org.sonar.api.rule.Severity.BLOCKER; | ||||
INFO, NEW_INFO_VIOLATIONS_KEY); | INFO, NEW_INFO_VIOLATIONS_KEY); | ||||
static final Map<String, String> IMPACT_TO_METRIC_KEY = Map.of( | static final Map<String, String> IMPACT_TO_METRIC_KEY = Map.of( | ||||
SoftwareQuality.SECURITY.name(), SECURITY_ISSUES.key(), | |||||
SoftwareQuality.RELIABILITY.name(), RELIABILITY_ISSUES.key(), | |||||
SoftwareQuality.MAINTAINABILITY.name(), MAINTAINABILITY_ISSUES.key()); | |||||
SoftwareQuality.SECURITY.name(), SECURITY_ISSUES_KEY, | |||||
SoftwareQuality.RELIABILITY.name(), RELIABILITY_ISSUES_KEY, | |||||
SoftwareQuality.MAINTAINABILITY.name(), MAINTAINABILITY_ISSUES_KEY); | |||||
static final Map<String, String> IMPACT_TO_NEW_METRIC_KEY = Map.of( | |||||
SoftwareQuality.SECURITY.name(), NEW_SECURITY_ISSUES_KEY, | |||||
SoftwareQuality.RELIABILITY.name(), NEW_RELIABILITY_ISSUES_KEY, | |||||
SoftwareQuality.MAINTAINABILITY.name(), NEW_MAINTAINABILITY_ISSUES_KEY); | |||||
private static final Map<RuleType, String> TYPE_TO_METRIC_KEY = ImmutableMap.<RuleType, String>builder() | private static final Map<RuleType, String> TYPE_TO_METRIC_KEY = ImmutableMap.<RuleType, String>builder() | ||||
.put(CODE_SMELL, CODE_SMELLS_KEY) | .put(CODE_SMELL, CODE_SMELLS_KEY) | ||||
String severity = entry.getKey(); | String severity = entry.getKey(); | ||||
String metricKey = entry.getValue(); | String metricKey = entry.getValue(); | ||||
Multiset<String> bag = currentCounters.counterForPeriod().severityBag; | Multiset<String> bag = currentCounters.counterForPeriod().severityBag; | ||||
Metric metric = metricRepository.getByKey(metricKey); | |||||
measureRepository.add(component, metric, Measure.newMeasureBuilder() | |||||
.create(bag.count(severity))); | |||||
addMeasure(component, metricKey, bag.count(severity)); | |||||
} | } | ||||
// waiting for Java 8 lambda in order to factor this loop with the previous one | // waiting for Java 8 lambda in order to factor this loop with the previous one | ||||
RuleType type = entry.getKey(); | RuleType type = entry.getKey(); | ||||
String metricKey = entry.getValue(); | String metricKey = entry.getValue(); | ||||
Multiset<RuleType> bag = currentCounters.counterForPeriod().typeBag; | Multiset<RuleType> bag = currentCounters.counterForPeriod().typeBag; | ||||
Metric metric = metricRepository.getByKey(metricKey); | |||||
measureRepository.add(component, metric, Measure.newMeasureBuilder() | |||||
.create(bag.count(type))); | |||||
addMeasure(component, metricKey, bag.count(type)); | |||||
} | |||||
for (Map.Entry<String, Map<String, Long>> impactEntry : currentCounters.counterForPeriod().impactsBag.entrySet()) { | |||||
String json = ImpactMeasureBuilder.fromMap(impactEntry.getValue()).buildAsString(); | |||||
addMeasure(component, IMPACT_TO_NEW_METRIC_KEY.get(impactEntry.getKey()), json); | |||||
} | } | ||||
addMeasure(component, NEW_ACCEPTED_ISSUES_KEY, currentCounters.counterForPeriod().accepted); | addMeasure(component, NEW_ACCEPTED_ISSUES_KEY, currentCounters.counterForPeriod().accepted); |
import java.util.Set; | import java.util.Set; | ||||
import javax.annotation.Nullable; | import javax.annotation.Nullable; | ||||
import org.assertj.core.data.MapEntry; | import org.assertj.core.data.MapEntry; | ||||
import org.junit.Rule; | |||||
import org.junit.Test; | |||||
import org.junit.jupiter.api.Test; | |||||
import org.junit.jupiter.api.extension.RegisterExtension; | |||||
import org.sonar.api.issue.impact.Severity; | import org.sonar.api.issue.impact.Severity; | ||||
import org.sonar.api.issue.impact.SoftwareQuality; | import org.sonar.api.issue.impact.SoftwareQuality; | ||||
import org.sonar.api.rules.RuleType; | import org.sonar.api.rules.RuleType; | ||||
import static org.sonar.api.measures.CoreMetrics.NEW_CRITICAL_VIOLATIONS; | import static org.sonar.api.measures.CoreMetrics.NEW_CRITICAL_VIOLATIONS; | ||||
import static org.sonar.api.measures.CoreMetrics.NEW_CRITICAL_VIOLATIONS_KEY; | import static org.sonar.api.measures.CoreMetrics.NEW_CRITICAL_VIOLATIONS_KEY; | ||||
import static org.sonar.api.measures.CoreMetrics.NEW_INFO_VIOLATIONS; | import static org.sonar.api.measures.CoreMetrics.NEW_INFO_VIOLATIONS; | ||||
import static org.sonar.api.measures.CoreMetrics.NEW_MAINTAINABILITY_ISSUES; | |||||
import static org.sonar.api.measures.CoreMetrics.NEW_MAJOR_VIOLATIONS; | import static org.sonar.api.measures.CoreMetrics.NEW_MAJOR_VIOLATIONS; | ||||
import static org.sonar.api.measures.CoreMetrics.NEW_MAJOR_VIOLATIONS_KEY; | import static org.sonar.api.measures.CoreMetrics.NEW_MAJOR_VIOLATIONS_KEY; | ||||
import static org.sonar.api.measures.CoreMetrics.NEW_MINOR_VIOLATIONS; | import static org.sonar.api.measures.CoreMetrics.NEW_MINOR_VIOLATIONS; | ||||
import static org.sonar.api.measures.CoreMetrics.NEW_RELIABILITY_ISSUES; | |||||
import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_HOTSPOTS; | import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_HOTSPOTS; | ||||
import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_HOTSPOTS_KEY; | import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_HOTSPOTS_KEY; | ||||
import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_ISSUES; | |||||
import static org.sonar.api.measures.CoreMetrics.NEW_VIOLATIONS; | import static org.sonar.api.measures.CoreMetrics.NEW_VIOLATIONS; | ||||
import static org.sonar.api.measures.CoreMetrics.NEW_VIOLATIONS_KEY; | import static org.sonar.api.measures.CoreMetrics.NEW_VIOLATIONS_KEY; | ||||
import static org.sonar.api.measures.CoreMetrics.NEW_VULNERABILITIES; | import static org.sonar.api.measures.CoreMetrics.NEW_VULNERABILITIES; | ||||
import static org.sonar.api.rules.RuleType.SECURITY_HOTSPOT; | import static org.sonar.api.rules.RuleType.SECURITY_HOTSPOT; | ||||
import static org.sonar.ce.task.projectanalysis.component.ReportComponent.builder; | import static org.sonar.ce.task.projectanalysis.component.ReportComponent.builder; | ||||
import static org.sonar.ce.task.projectanalysis.issue.IssueCounter.IMPACT_TO_METRIC_KEY; | import static org.sonar.ce.task.projectanalysis.issue.IssueCounter.IMPACT_TO_METRIC_KEY; | ||||
import static org.sonar.ce.task.projectanalysis.issue.IssueCounter.IMPACT_TO_NEW_METRIC_KEY; | |||||
import static org.sonar.ce.task.projectanalysis.measure.Measure.newMeasureBuilder; | import static org.sonar.ce.task.projectanalysis.measure.Measure.newMeasureBuilder; | ||||
import static org.sonar.ce.task.projectanalysis.measure.MeasureRepoEntry.entryOf; | import static org.sonar.ce.task.projectanalysis.measure.MeasureRepoEntry.entryOf; | ||||
public class IssueCounterTest { | |||||
class IssueCounterTest { | |||||
private static final Component FILE1 = builder(Component.Type.FILE, 1).build(); | private static final Component FILE1 = builder(Component.Type.FILE, 1).build(); | ||||
private static final Component FILE2 = builder(Component.Type.FILE, 2).build(); | private static final Component FILE2 = builder(Component.Type.FILE, 2).build(); | ||||
private static final Component FILE3 = builder(Component.Type.FILE, 3).build(); | private static final Component FILE3 = builder(Component.Type.FILE, 3).build(); | ||||
private static final Component PROJECT = builder(Component.Type.PROJECT, 4).addChildren(FILE1, FILE2, FILE3).build(); | private static final Component PROJECT = builder(Component.Type.PROJECT, 4).addChildren(FILE1, FILE2, FILE3).build(); | ||||
@Rule | |||||
public BatchReportReaderRule reportReader = new BatchReportReaderRule(); | |||||
@RegisterExtension | |||||
private final BatchReportReaderRule reportReader = new BatchReportReaderRule(); | |||||
@Rule | |||||
public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule(); | |||||
@RegisterExtension | |||||
private final TreeRootHolderRule treeRootHolder = new TreeRootHolderRule(); | |||||
@Rule | |||||
public MetricRepositoryRule metricRepository = new MetricRepositoryRule() | |||||
@RegisterExtension | |||||
private final MetricRepositoryRule metricRepository = new MetricRepositoryRule() | |||||
.add(VIOLATIONS) | .add(VIOLATIONS) | ||||
.add(OPEN_ISSUES) | .add(OPEN_ISSUES) | ||||
.add(REOPENED_ISSUES) | .add(REOPENED_ISSUES) | ||||
.add(HIGH_IMPACT_ACCEPTED_ISSUES) | .add(HIGH_IMPACT_ACCEPTED_ISSUES) | ||||
.add(RELIABILITY_ISSUES) | .add(RELIABILITY_ISSUES) | ||||
.add(MAINTAINABILITY_ISSUES) | .add(MAINTAINABILITY_ISSUES) | ||||
.add(SECURITY_ISSUES); | |||||
.add(SECURITY_ISSUES) | |||||
.add(NEW_RELIABILITY_ISSUES) | |||||
.add(NEW_MAINTAINABILITY_ISSUES) | |||||
.add(NEW_SECURITY_ISSUES); | |||||
@Rule | |||||
public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository); | |||||
private NewIssueClassifier newIssueClassifier = mock(NewIssueClassifier.class); | |||||
private IssueCounter underTest = new IssueCounter(metricRepository, measureRepository, newIssueClassifier); | |||||
@RegisterExtension | |||||
private final MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository); | |||||
private final NewIssueClassifier newIssueClassifier = mock(NewIssueClassifier.class); | |||||
private final IssueCounter underTest = new IssueCounter(metricRepository, measureRepository, newIssueClassifier); | |||||
private static int issueCounter; | |||||
@Test | @Test | ||||
public void count_issues_by_status() { | |||||
void count_issues_by_status() { | |||||
// bottom-up traversal -> from files to project | // bottom-up traversal -> from files to project | ||||
underTest.beforeComponent(FILE1); | underTest.beforeComponent(FILE1); | ||||
underTest.onIssue(FILE1, createIssue(null, STATUS_OPEN, BLOCKER)); | underTest.onIssue(FILE1, createIssue(null, STATUS_OPEN, BLOCKER)); | ||||
} | } | ||||
@Test | @Test | ||||
public void count_issues_by_resolution() { | |||||
void count_issues_by_resolution() { | |||||
// bottom-up traversal -> from files to project | // bottom-up traversal -> from files to project | ||||
underTest.beforeComponent(FILE1); | underTest.beforeComponent(FILE1); | ||||
underTest.onIssue(FILE1, createIssue(null, STATUS_OPEN, BLOCKER)); | underTest.onIssue(FILE1, createIssue(null, STATUS_OPEN, BLOCKER)); | ||||
} | } | ||||
@Test | @Test | ||||
public void count_unresolved_issues_by_severity() { | |||||
void count_unresolved_issues_by_severity() { | |||||
// bottom-up traversal -> from files to project | // bottom-up traversal -> from files to project | ||||
underTest.beforeComponent(FILE1); | underTest.beforeComponent(FILE1); | ||||
underTest.onIssue(FILE1, createIssue(null, STATUS_OPEN, BLOCKER)); | underTest.onIssue(FILE1, createIssue(null, STATUS_OPEN, BLOCKER)); | ||||
} | } | ||||
@Test | @Test | ||||
public void count_unresolved_issues_by_type() { | |||||
void count_unresolved_issues_by_type() { | |||||
// bottom-up traversal -> from files to project | // bottom-up traversal -> from files to project | ||||
// file1 : one open code smell, one closed code smell (which will be excluded from metric) | // file1 : one open code smell, one closed code smell (which will be excluded from metric) | ||||
underTest.beforeComponent(FILE1); | underTest.beforeComponent(FILE1); | ||||
} | } | ||||
@Test | @Test | ||||
public void count_new_issues() { | |||||
void count_new_issues() { | |||||
when(newIssueClassifier.isEnabled()).thenReturn(true); | when(newIssueClassifier.isEnabled()).thenReturn(true); | ||||
underTest.beforeComponent(FILE1); | underTest.beforeComponent(FILE1); | ||||
} | } | ||||
@Test | @Test | ||||
public void count_new_accepted_issues() { | |||||
void count_new_accepted_issues() { | |||||
when(newIssueClassifier.isEnabled()).thenReturn(true); | when(newIssueClassifier.isEnabled()).thenReturn(true); | ||||
underTest.beforeComponent(FILE1); | underTest.beforeComponent(FILE1); | ||||
} | } | ||||
@Test | @Test | ||||
public void count_impacts() { | |||||
void onIssue_shouldCountOverallSoftwareQualitiesMeasures() { | |||||
when(newIssueClassifier.isEnabled()).thenReturn(true); | when(newIssueClassifier.isEnabled()).thenReturn(true); | ||||
underTest.beforeComponent(FILE1); | underTest.beforeComponent(FILE1); | ||||
Set<Map.Entry<String, Measure>> entries = measureRepository.getRawMeasures(FILE1).entrySet(); | Set<Map.Entry<String, Measure>> entries = measureRepository.getRawMeasures(FILE1).entrySet(); | ||||
assertSoftwareQualityMeasures(SoftwareQuality.MAINTAINABILITY, getImpactMeasure(4, 2, 2, 0), entries); | |||||
assertSoftwareQualityMeasures(SoftwareQuality.SECURITY, getImpactMeasure(2, 1, 1, 0), entries); | |||||
assertSoftwareQualityMeasures(SoftwareQuality.RELIABILITY, getImpactMeasure(0, 0, 0, 0), entries); | |||||
assertOverallSoftwareQualityMeasures(SoftwareQuality.MAINTAINABILITY, getImpactMeasure(4, 2, 2, 0), entries); | |||||
assertOverallSoftwareQualityMeasures(SoftwareQuality.SECURITY, getImpactMeasure(2, 1, 1, 0), entries); | |||||
assertOverallSoftwareQualityMeasures(SoftwareQuality.RELIABILITY, getImpactMeasure(0, 0, 0, 0), entries); | |||||
} | |||||
@Test | |||||
void onIssue_shouldCountNewSoftwareQualitiesMeasures() { | |||||
when(newIssueClassifier.isEnabled()).thenReturn(true); | |||||
underTest.beforeComponent(FILE1); | |||||
underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.MAINTAINABILITY, HIGH)); | |||||
underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.MAINTAINABILITY, HIGH)); | |||||
underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_RESOLVED, SoftwareQuality.MAINTAINABILITY, HIGH)); | |||||
underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.MAINTAINABILITY, MEDIUM)); | |||||
underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.RELIABILITY, HIGH)); | |||||
underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.RELIABILITY, LOW)); | |||||
underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_RESOLVED, SoftwareQuality.RELIABILITY, HIGH)); | |||||
underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.RELIABILITY, MEDIUM)); | |||||
underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.SECURITY, MEDIUM)); | |||||
underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.SECURITY, LOW)); | |||||
underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.SECURITY, HIGH)); | |||||
underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.SECURITY, HIGH)); | |||||
underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_RESOLVED, SoftwareQuality.SECURITY, HIGH)); | |||||
underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.SECURITY, MEDIUM)); | |||||
underTest.afterComponent(FILE1); | |||||
underTest.beforeComponent(PROJECT); | |||||
underTest.afterComponent(PROJECT); | |||||
Set<Map.Entry<String, Measure>> entries = measureRepository.getRawMeasures(FILE1).entrySet(); | |||||
assertNewSoftwareQualityMeasures(SoftwareQuality.MAINTAINABILITY, getImpactMeasure(2, 1, 1, 0), entries); | |||||
assertNewSoftwareQualityMeasures(SoftwareQuality.RELIABILITY, getImpactMeasure(2, 0, 1, 1), entries); | |||||
assertNewSoftwareQualityMeasures(SoftwareQuality.SECURITY, getImpactMeasure(4, 2, 1, 1), entries); | |||||
} | } | ||||
private static Map<String, Long> getImpactMeasure(long total, long high, long medium, long low) { | private static Map<String, Long> getImpactMeasure(long total, long high, long medium, long low) { | ||||
return map; | return map; | ||||
} | } | ||||
private void assertSoftwareQualityMeasures(SoftwareQuality softwareQuality, Map<? extends String, Long> expectedMap, | |||||
private void assertOverallSoftwareQualityMeasures(SoftwareQuality softwareQuality, Map<? extends String, Long> expectedMap, | |||||
Set<Map.Entry<String, Measure>> actualRaw) { | Set<Map.Entry<String, Measure>> actualRaw) { | ||||
assertSoftwareQualityMeasures(softwareQuality, expectedMap, actualRaw, IMPACT_TO_METRIC_KEY); | |||||
} | |||||
private void assertNewSoftwareQualityMeasures(SoftwareQuality softwareQuality, Map<? extends String, Long> expectedMap, | |||||
Set<Map.Entry<String, Measure>> actualRaw) { | |||||
assertSoftwareQualityMeasures(softwareQuality, expectedMap, actualRaw, IMPACT_TO_NEW_METRIC_KEY); | |||||
} | |||||
private void assertSoftwareQualityMeasures(SoftwareQuality softwareQuality, Map<? extends String, Long> expectedMap, | |||||
Set<Map.Entry<String, Measure>> actualRaw, Map<String, String> impactToMetricMap) { | |||||
Map.Entry<String, Measure> softwareQualityMap = actualRaw.stream() | Map.Entry<String, Measure> softwareQualityMap = actualRaw.stream() | ||||
.filter(e -> e.getKey().equals(IMPACT_TO_METRIC_KEY.get(softwareQuality.name()))) | |||||
.filter(e -> e.getKey().equals(impactToMetricMap.get(softwareQuality.name()))) | |||||
.findFirst() | .findFirst() | ||||
.get(); | .get(); | ||||
} | } | ||||
@Test | @Test | ||||
public void count_high_impact_accepted_issues() { | |||||
void count_high_impact_accepted_issues() { | |||||
when(newIssueClassifier.isEnabled()).thenReturn(true); | when(newIssueClassifier.isEnabled()).thenReturn(true); | ||||
underTest.beforeComponent(FILE1); | underTest.beforeComponent(FILE1); | ||||
} | } | ||||
@Test | @Test | ||||
public void exclude_hotspots_from_issue_counts() { | |||||
void exclude_hotspots_from_issue_counts() { | |||||
// bottom-up traversal -> from files to project | // bottom-up traversal -> from files to project | ||||
underTest.beforeComponent(FILE1); | underTest.beforeComponent(FILE1); | ||||
underTest.onIssue(FILE1, createSecurityHotspot()); | underTest.onIssue(FILE1, createSecurityHotspot()); | ||||
} | } | ||||
@Test | @Test | ||||
public void exclude_new_hotspots_from_issue_counts() { | |||||
void exclude_new_hotspots_from_issue_counts() { | |||||
when(newIssueClassifier.isEnabled()).thenReturn(true); | when(newIssueClassifier.isEnabled()).thenReturn(true); | ||||
underTest.beforeComponent(FILE1); | underTest.beforeComponent(FILE1); | ||||
private DefaultIssue createNewIssue(@Nullable String resolution, String status, SoftwareQuality softwareQuality, Severity impactSeverity) { | private DefaultIssue createNewIssue(@Nullable String resolution, String status, SoftwareQuality softwareQuality, Severity impactSeverity) { | ||||
DefaultIssue issue = createNewIssue(resolution, status, MAJOR, CODE_SMELL); | DefaultIssue issue = createNewIssue(resolution, status, MAJOR, CODE_SMELL); | ||||
issue.addImpact(SoftwareQuality.MAINTAINABILITY, impactSeverity); | |||||
issue.addImpact(softwareQuality, impactSeverity); | |||||
return issue; | return issue; | ||||
} | } | ||||
private static DefaultIssue createIssue(@Nullable String resolution, String status, String severity, RuleType ruleType) { | private static DefaultIssue createIssue(@Nullable String resolution, String status, String severity, RuleType ruleType) { | ||||
return new DefaultIssue() | return new DefaultIssue() | ||||
.setKey(String.valueOf(++issueCounter)) | |||||
.setResolution(resolution).setStatus(status) | .setResolution(resolution).setStatus(status) | ||||
.setSeverity(severity).setRuleKey(RuleTesting.XOO_X1) | .setSeverity(severity).setRuleKey(RuleTesting.XOO_X1) | ||||
.setType(ruleType); | .setType(ruleType); |
import org.junit.jupiter.api.BeforeEach; | import org.junit.jupiter.api.BeforeEach; | ||||
import org.junit.jupiter.api.Test; | import org.junit.jupiter.api.Test; | ||||
import org.junit.jupiter.api.extension.RegisterExtension; | import org.junit.jupiter.api.extension.RegisterExtension; | ||||
import org.junit.jupiter.params.ParameterizedTest; | |||||
import org.junit.jupiter.params.provider.ValueSource; | |||||
import org.sonar.api.issue.Issue; | import org.sonar.api.issue.Issue; | ||||
import org.sonar.api.issue.impact.Severity; | import org.sonar.api.issue.impact.Severity; | ||||
import org.sonar.api.issue.impact.SoftwareQuality; | import org.sonar.api.issue.impact.SoftwareQuality; | ||||
assertThat(result.stream().filter(g -> !g.isInLeak()).mapToLong(IssueGroupDto::getCount).sum()).isOne(); | assertThat(result.stream().filter(g -> !g.isInLeak()).mapToLong(IssueGroupDto::getCount).sum()).isOne(); | ||||
} | } | ||||
@Test | |||||
void selectIssueImpactGroupsByComponent_shouldReturnImpactGroups() { | |||||
@ParameterizedTest | |||||
@ValueSource(booleans = {true, false}) | |||||
void selectIssueImpactGroupsByComponent_shouldReturnImpactGroups(boolean inLeak) { | |||||
ComponentDto project = db.components().insertPublicProject().getMainBranchComponent(); | ComponentDto project = db.components().insertPublicProject().getMainBranchComponent(); | ||||
ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(project)); | ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(project)); | ||||
RuleDto rule = db.rules().insert(); | RuleDto rule = db.rules().insert(); | ||||
db.issues().insert(rule, project, file, | db.issues().insert(rule, project, file, | ||||
i -> i.setStatus(STATUS_RESOLVED).setResolution(RESOLUTION_FALSE_POSITIVE).replaceAllImpacts(List.of(createImpact(SECURITY, HIGH)))); | i -> i.setStatus(STATUS_RESOLVED).setResolution(RESOLUTION_FALSE_POSITIVE).replaceAllImpacts(List.of(createImpact(SECURITY, HIGH)))); | ||||
Collection<IssueImpactGroupDto> result = underTest.selectIssueImpactGroupsByComponent(db.getSession(), file); | |||||
Collection<IssueImpactGroupDto> result = underTest.selectIssueImpactGroupsByComponent(db.getSession(), file, inLeak ? 1L : Long.MAX_VALUE); | |||||
assertThat(result).hasSize(5); | assertThat(result).hasSize(5); | ||||
assertThat(result.stream().filter(IssueImpactGroupDto::isInLeak)).hasSize(inLeak ? 5 : 0); | |||||
assertThat(result.stream().mapToLong(IssueImpactGroupDto::getCount).sum()).isEqualTo(6); | assertThat(result.stream().mapToLong(IssueImpactGroupDto::getCount).sum()).isEqualTo(6); | ||||
assertThat(result.stream().filter(g -> g.getSoftwareQuality() == SECURITY).mapToLong(IssueImpactGroupDto::getCount).sum()).isEqualTo(4); | assertThat(result.stream().filter(g -> g.getSoftwareQuality() == SECURITY).mapToLong(IssueImpactGroupDto::getCount).sum()).isEqualTo(4); | ||||
assertThat(result.stream().noneMatch(g -> RESOLUTION_FALSE_POSITIVE.equals(g.getResolution()))).isTrue(); | assertThat(result.stream().noneMatch(g -> RESOLUTION_FALSE_POSITIVE.equals(g.getResolution()))).isTrue(); | ||||
assertThat(result.stream().noneMatch(g -> RELIABILITY == g.getSoftwareQuality())).isTrue(); | assertThat(result.stream().noneMatch(g -> RELIABILITY == g.getSoftwareQuality())).isTrue(); | ||||
assertThat(result.stream().noneMatch(g -> MEDIUM == g.getSeverity())).isTrue(); | assertThat(result.stream().noneMatch(g -> MEDIUM == g.getSeverity())).isTrue(); | ||||
} | |||||
@Test | |||||
void selectIssueImpactGroupsByComponent_whenNewCodeFromReferenceBranch_shouldReturnImpactGroups() { | |||||
ComponentDto project = db.components().insertPublicProject().getMainBranchComponent(); | |||||
ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(project)); | |||||
RuleDto rule = db.rules().insert(); | |||||
IssueDto issueInNewCodePeriod = db.issues().insert(rule, project, file, | |||||
i -> i.setStatus(STATUS_OPEN).replaceAllImpacts(List.of(createImpact(SECURITY, HIGH), createImpact(MAINTAINABILITY, LOW)))); | |||||
db.issues().insert(rule, project, file, | |||||
i -> i.setStatus(STATUS_RESOLVED).setResolution(RESOLUTION_WONT_FIX).replaceAllImpacts(List.of(createImpact(SECURITY, HIGH)))); | |||||
db.issues().insertNewCodeReferenceIssue(issueInNewCodePeriod); | |||||
Collection<IssueImpactGroupDto> result = underTest.selectIssueImpactGroupsByComponent(db.getSession(), file, -1L); | |||||
assertThat(result).hasSize(3); | |||||
assertThat(result.stream().filter(IssueImpactGroupDto::isInLeak)).hasSize(2); | |||||
assertThat(result.stream().mapToLong(IssueImpactGroupDto::getCount).sum()).isEqualTo(3); | |||||
assertThat(result.stream().filter(g -> g.getSoftwareQuality() == SECURITY).mapToLong(IssueImpactGroupDto::getCount).sum()).isEqualTo(2); | |||||
assertThat(result.stream().filter(g -> g.getSoftwareQuality() == MAINTAINABILITY).mapToLong(IssueImpactGroupDto::getCount).sum()).isEqualTo(1); | |||||
assertThat(result.stream().filter(g -> g.getSeverity() == HIGH).mapToLong(IssueImpactGroupDto::getCount).sum()).isEqualTo(2); | |||||
assertThat(result.stream().filter(g -> g.getSeverity() == LOW).mapToLong(IssueImpactGroupDto::getCount).sum()).isOne(); | |||||
assertThat(result.stream().filter(g -> STATUS_OPEN.equals(g.getStatus())).mapToLong(IssueImpactGroupDto::getCount).sum()).isEqualTo(2); | |||||
assertThat(result.stream().filter(g -> STATUS_REOPENED.equals(g.getStatus())).mapToLong(IssueImpactGroupDto::getCount).sum()).isZero(); | |||||
assertThat(result.stream().filter(g -> STATUS_RESOLVED.equals(g.getStatus())).mapToLong(IssueImpactGroupDto::getCount).sum()).isOne(); | |||||
assertThat(result.stream().filter(g -> RESOLUTION_WONT_FIX.equals(g.getResolution())).mapToLong(IssueImpactGroupDto::getCount).sum()).isOne(); | |||||
assertThat(result.stream().filter(IssueImpactGroupDto::isInLeak).mapToLong(IssueImpactGroupDto::getCount).sum()).isEqualTo(2); | |||||
assertThat(result.stream().filter(g -> g.isInLeak() && g.getSoftwareQuality() == SECURITY).mapToLong(IssueImpactGroupDto::getCount).sum()).isEqualTo(1); | |||||
assertThat(result.stream().filter(g -> g.isInLeak() && g.getSoftwareQuality() == MAINTAINABILITY).mapToLong(IssueImpactGroupDto::getCount).sum()).isEqualTo(1); | |||||
} | } | ||||
@NotNull | @NotNull | ||||
ComponentDto project = db.components().insertPublicProject().getMainBranchComponent(); | ComponentDto project = db.components().insertPublicProject().getMainBranchComponent(); | ||||
ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(project)); | ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(project)); | ||||
Collection<IssueImpactGroupDto> groups = underTest.selectIssueImpactGroupsByComponent(db.getSession(), file); | |||||
Collection<IssueImpactGroupDto> groups = underTest.selectIssueImpactGroupsByComponent(db.getSession(), file, 1_000L); | |||||
assertThat(groups).isEmpty(); | assertThat(groups).isEmpty(); | ||||
} | } |
return mapper(dbSession).selectIssueGroupsByComponent(component, leakPeriodBeginningDate); | return mapper(dbSession).selectIssueGroupsByComponent(component, leakPeriodBeginningDate); | ||||
} | } | ||||
public Collection<IssueImpactGroupDto> selectIssueImpactGroupsByComponent(DbSession dbSession, ComponentDto component) { | |||||
return mapper(dbSession).selectIssueImpactGroupsByComponent(component); | |||||
public Collection<IssueImpactGroupDto> selectIssueImpactGroupsByComponent(DbSession dbSession, ComponentDto component, long leakPeriodBeginningDate) { | |||||
return mapper(dbSession).selectIssueImpactGroupsByComponent(component, leakPeriodBeginningDate); | |||||
} | } | ||||
public Cursor<IndexedIssueDto> scrollIssuesForIndexation(DbSession dbSession, @Nullable @Param("branchUuid") String branchUuid, | public Cursor<IndexedIssueDto> scrollIssuesForIndexation(DbSession dbSession, @Nullable @Param("branchUuid") String branchUuid, |
private SoftwareQuality softwareQuality; | private SoftwareQuality softwareQuality; | ||||
private Severity severity; | private Severity severity; | ||||
private long count; | private long count; | ||||
private boolean inLeak; | |||||
public IssueImpactGroupDto() { | public IssueImpactGroupDto() { | ||||
// nothing to do | // nothing to do | ||||
public void setCount(long count) { | public void setCount(long count) { | ||||
this.count = count; | this.count = count; | ||||
} | } | ||||
public boolean isInLeak() { | |||||
return inLeak; | |||||
} | |||||
public void setInLeak(boolean inLeak) { | |||||
this.inLeak = inLeak; | |||||
} | |||||
} | } |
Collection<IssueGroupDto> selectIssueGroupsByComponent(@Param("component") ComponentDto component, @Param("leakPeriodBeginningDate") long leakPeriodBeginningDate); | Collection<IssueGroupDto> selectIssueGroupsByComponent(@Param("component") ComponentDto component, @Param("leakPeriodBeginningDate") long leakPeriodBeginningDate); | ||||
Collection<IssueImpactGroupDto> selectIssueImpactGroupsByComponent(@Param("component") ComponentDto component); | |||||
Collection<IssueImpactGroupDto> selectIssueImpactGroupsByComponent(@Param("component") ComponentDto component, @Param("leakPeriodBeginningDate") long leakPeriodBeginningDate); | |||||
List<IssueDto> selectByBranch(@Param("keys") Set<String> keys, @Nullable @Param("changedSince") Long changedSince); | List<IssueDto> selectByBranch(@Param("keys") Set<String> keys, @Nullable @Param("changedSince") Long changedSince); | ||||
<select id="selectIssueImpactGroupsByComponent" resultType="org.sonar.db.issue.IssueImpactGroupDto" parameterType="map"> | <select id="selectIssueImpactGroupsByComponent" resultType="org.sonar.db.issue.IssueImpactGroupDto" parameterType="map"> | ||||
select | select | ||||
i.status as status, | |||||
i.resolution as resolution, | |||||
ii.software_quality as softwareQuality, | |||||
ii.severity as severity, | |||||
count(i.kee) as "count" | |||||
from issues i | |||||
inner join issues_impacts ii on i.kee = ii.issue_key | |||||
where i.status <> 'CLOSED' | |||||
and (i.resolution is null or i.resolution = 'WONTFIX') | |||||
and i.component_uuid = #{component.uuid,jdbcType=VARCHAR} | |||||
group by i.status, i.resolution, ii.software_quality, ii.severity | |||||
i2.status as status, | |||||
i2.resolution as resolution, | |||||
i2.software_quality as softwareQuality, | |||||
i2.severity as severity, | |||||
count(i2.kee) as "count", | |||||
i2.inLeak as inLeak | |||||
from ( | |||||
select | |||||
i.status, | |||||
i.resolution, | |||||
i.kee, | |||||
ii.software_quality, | |||||
ii.severity, | |||||
<if test="leakPeriodBeginningDate >= 0"> | |||||
case when i.issue_creation_date > #{leakPeriodBeginningDate,jdbcType=BIGINT} then ${_true} else ${_false} end as inLeak | |||||
</if> | |||||
<if test="leakPeriodBeginningDate < 0"> | |||||
case when n.uuid is null then ${_false} else ${_true} end as inLeak | |||||
</if> | |||||
from issues i | |||||
inner join issues_impacts ii on i.kee = ii.issue_key | |||||
<if test="leakPeriodBeginningDate < 0"> | |||||
left join new_code_reference_issues n on n.issue_key = i.kee | |||||
</if> | |||||
where i.status <> 'CLOSED' | |||||
and (i.resolution is null or i.resolution = 'WONTFIX') | |||||
and i.component_uuid = #{component.uuid,jdbcType=VARCHAR} | |||||
) i2 | |||||
group by i2.status, i2.resolution, i2.software_quality, i2.severity, i2.inLeak | |||||
</select> | </select> | ||||
<select id="selectIssueKeysByComponentUuid" parameterType="string" resultType="string"> | <select id="selectIssueKeysByComponentUuid" parameterType="string" resultType="string"> |
import static org.assertj.core.api.Assertions.assertThatThrownBy; | import static org.assertj.core.api.Assertions.assertThatThrownBy; | ||||
import static org.assertj.core.api.Assertions.tuple; | import static org.assertj.core.api.Assertions.tuple; | ||||
import static org.sonar.api.measures.CoreMetrics.MAINTAINABILITY_ISSUES_KEY; | import static org.sonar.api.measures.CoreMetrics.MAINTAINABILITY_ISSUES_KEY; | ||||
import static org.sonar.api.measures.CoreMetrics.NEW_MAINTAINABILITY_ISSUES_KEY; | |||||
import static org.sonar.api.measures.CoreMetrics.NEW_RELIABILITY_ISSUES_KEY; | |||||
import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_ISSUES_KEY; | |||||
import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_RATING_KEY; | import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_RATING_KEY; | ||||
import static org.sonar.api.measures.CoreMetrics.RELIABILITY_ISSUES_KEY; | import static org.sonar.api.measures.CoreMetrics.RELIABILITY_ISSUES_KEY; | ||||
import static org.sonar.api.measures.CoreMetrics.SECURITY_ISSUES_KEY; | import static org.sonar.api.measures.CoreMetrics.SECURITY_ISSUES_KEY; | ||||
ComponentDto mainBranch = projectData.getMainBranchComponent(); | ComponentDto mainBranch = projectData.getMainBranchComponent(); | ||||
addProjectPermission(projectData); | addProjectPermission(projectData); | ||||
db.getDbClient().snapshotDao().insert(dbSession, newAnalysis(mainBranch)); | db.getDbClient().snapshotDao().insert(dbSession, newAnalysis(mainBranch)); | ||||
MetricDto dataMetric = dbClient.metricDao().insert(dbSession, newDataMetricDto(SECURITY_ISSUES_KEY)); | |||||
db.measures().insertLiveMeasure(mainBranch, dataMetric, c -> c.setData(SECURITY_ISSUES_KEY + "_data")); | |||||
dataMetric = dbClient.metricDao().insert(dbSession, newDataMetricDto(MAINTAINABILITY_ISSUES_KEY)); | |||||
db.measures().insertLiveMeasure(mainBranch, dataMetric, c -> c.setData(MAINTAINABILITY_ISSUES_KEY + "_data")); | |||||
dataMetric = dbClient.metricDao().insert(dbSession, newDataMetricDto(RELIABILITY_ISSUES_KEY)); | |||||
db.measures().insertLiveMeasure(mainBranch, dataMetric, c -> c.setData(RELIABILITY_ISSUES_KEY + "_data")); | |||||
insertMetricAndLiveMeasure(mainBranch, SECURITY_ISSUES_KEY, "_data"); | |||||
insertMetricAndLiveMeasure(mainBranch, MAINTAINABILITY_ISSUES_KEY, "_data"); | |||||
insertMetricAndLiveMeasure(mainBranch, RELIABILITY_ISSUES_KEY, "_data"); | |||||
ComponentTreeWsResponse response = ws.newRequest() | ComponentTreeWsResponse response = ws.newRequest() | ||||
.setParam(PARAM_COMPONENT, mainBranch.getKey()) | .setParam(PARAM_COMPONENT, mainBranch.getKey()) | ||||
tuple(RELIABILITY_ISSUES_KEY, RELIABILITY_ISSUES_KEY + "_data")); | tuple(RELIABILITY_ISSUES_KEY, RELIABILITY_ISSUES_KEY + "_data")); | ||||
} | } | ||||
@Test | |||||
void execute_whenUsingSupportedNewDATAMetrics_shouldReturnMetrics() { | |||||
ProjectData projectData = db.components().insertPrivateProject(); | |||||
ComponentDto mainBranch = projectData.getMainBranchComponent(); | |||||
addProjectPermission(projectData); | |||||
db.components().insertSnapshot(mainBranch); | |||||
ComponentDto file1 = db.components().insertComponent(newFileDto(mainBranch)); | |||||
insertMetricAndLiveMeasure(file1, NEW_SECURITY_ISSUES_KEY, "_data"); | |||||
insertMetricAndLiveMeasure(file1, NEW_MAINTAINABILITY_ISSUES_KEY, "_data"); | |||||
insertMetricAndLiveMeasure(file1, NEW_RELIABILITY_ISSUES_KEY, "_data"); | |||||
ComponentTreeWsResponse response = ws.newRequest() | |||||
.setParam(PARAM_COMPONENT, mainBranch.getKey()) | |||||
.setParam(PARAM_METRIC_KEYS, format("%s,%s,%s", | |||||
NEW_SECURITY_ISSUES_KEY, | |||||
NEW_MAINTAINABILITY_ISSUES_KEY, | |||||
NEW_RELIABILITY_ISSUES_KEY | |||||
)) | |||||
.setParam(PARAM_ADDITIONAL_FIELDS, "metrics,period") | |||||
.executeProtobuf(ComponentTreeWsResponse.class); | |||||
assertThat(response.getComponents(0).getMeasuresCount()).isEqualTo(3); | |||||
List<Measure> dataMeasures = response.getComponents(0).getMeasuresList(); | |||||
assertThat(dataMeasures) | |||||
.extracting(Measure::getMetric, m-> m.getPeriod().getValue()) | |||||
.containsExactlyInAnyOrder(tuple(NEW_SECURITY_ISSUES_KEY, NEW_SECURITY_ISSUES_KEY + "_data"), | |||||
tuple(NEW_MAINTAINABILITY_ISSUES_KEY, NEW_MAINTAINABILITY_ISSUES_KEY + "_data"), | |||||
tuple(NEW_RELIABILITY_ISSUES_KEY, NEW_RELIABILITY_ISSUES_KEY + "_data") | |||||
); | |||||
} | |||||
@Test | @Test | ||||
void fail_when_setting_more_than_15_metric_keys() { | void fail_when_setting_more_than_15_metric_keys() { | ||||
ComponentDto mainBranch = db.components().insertPrivateProject().getMainBranchComponent(); | ComponentDto mainBranch = db.components().insertPrivateProject().getMainBranchComponent(); | ||||
.setOptimizedBestValue(false); | .setOptimizedBestValue(false); | ||||
} | } | ||||
private void insertMetricAndLiveMeasure(ComponentDto dto, String key, String additionalData) { | |||||
MetricDto dataMetric = dbClient.metricDao().insert(dbSession, newDataMetricDto(key)); | |||||
db.measures().insertLiveMeasure(dto, dataMetric, c -> c.setData(key + additionalData)); | |||||
} | |||||
private static MetricDto newDataMetricDto(String key) { | private static MetricDto newDataMetricDto(String key) { | ||||
return newMetricDto().setValueType(DATA.name()).setKey(key); | return newMetricDto().setValueType(DATA.name()).setKey(key); | ||||
} | } |
return onlyInLeak ? count.leak : count.absolute; | return onlyInLeak ? count.leak : count.absolute; | ||||
} | } | ||||
public String getBySoftwareQuality(SoftwareQuality softwareQuality) { | |||||
public String getBySoftwareQuality(SoftwareQuality softwareQuality, boolean onlyInLeak) { | |||||
Map<Severity, Count> severityToCount = bySoftwareQualityAndSeverity.get(softwareQuality); | Map<Severity, Count> severityToCount = bySoftwareQualityAndSeverity.get(softwareQuality); | ||||
ImpactMeasureBuilder impactMeasureBuilder; | ImpactMeasureBuilder impactMeasureBuilder; | ||||
if (severityToCount != null) { | if (severityToCount != null) { | ||||
impactMeasureBuilder = ImpactMeasureBuilder.newInstance(); | impactMeasureBuilder = ImpactMeasureBuilder.newInstance(); | ||||
for (Severity severity : Severity.values()) { | for (Severity severity : Severity.values()) { | ||||
impactMeasureBuilder = impactMeasureBuilder.setSeverity(severity, Optional.ofNullable(severityToCount.get(severity)).map(count -> count.absolute).orElse(0L)); | |||||
impactMeasureBuilder = impactMeasureBuilder.setSeverity(severity, value(severityToCount.get(severity), onlyInLeak)); | |||||
} | } | ||||
impactMeasureBuilder = impactMeasureBuilder.setTotal(severityToCount.values().stream().mapToLong(count -> count.absolute).sum()); | |||||
impactMeasureBuilder = impactMeasureBuilder.setTotal(severityToCount.values().stream().mapToLong(count -> value(count, onlyInLeak)).sum()); | |||||
} else { | } else { | ||||
impactMeasureBuilder = ImpactMeasureBuilder.createEmpty(); | impactMeasureBuilder = ImpactMeasureBuilder.createEmpty(); | ||||
} | } | ||||
public void add(IssueImpactGroupDto group) { | public void add(IssueImpactGroupDto group) { | ||||
absolute += group.getCount(); | absolute += group.getCount(); | ||||
if (group.isInLeak()) { | |||||
leak += group.getCount(); | |||||
} | |||||
} | } | ||||
} | } | ||||
components.getSortedTree().forEach(c -> { | components.getSortedTree().forEach(c -> { | ||||
IssueCounter issueCounter = new IssueCounter(dbClient.issueDao().selectIssueGroupsByComponent(dbSession, c, beginningOfLeak), | IssueCounter issueCounter = new IssueCounter(dbClient.issueDao().selectIssueGroupsByComponent(dbSession, c, beginningOfLeak), | ||||
dbClient.issueDao().selectIssueImpactGroupsByComponent(dbSession, c)); | |||||
dbClient.issueDao().selectIssueImpactGroupsByComponent(dbSession, c, beginningOfLeak)); | |||||
for (MeasureUpdateFormula formula : formulaFactory.getFormulas()) { | for (MeasureUpdateFormula formula : formulaFactory.getFormulas()) { | ||||
if (shouldComputeMetric(formula, useLeakFormulas, components.getBranch(), matrix)) { | if (shouldComputeMetric(formula, useLeakFormulas, components.getBranch(), matrix)) { | ||||
context.change(c, formula); | context.change(c, formula); |
(context, issues) -> context.setValue(issues.countUnresolvedByType(RuleType.SECURITY_HOTSPOT, false))), | (context, issues) -> context.setValue(issues.countUnresolvedByType(RuleType.SECURITY_HOTSPOT, false))), | ||||
new MeasureUpdateFormula(CoreMetrics.RELIABILITY_ISSUES, false, true, new ImpactAddChildren(), | new MeasureUpdateFormula(CoreMetrics.RELIABILITY_ISSUES, false, true, new ImpactAddChildren(), | ||||
(context, issues) -> context.setValue(issues.getBySoftwareQuality(SoftwareQuality.RELIABILITY))), | |||||
(context, issues) -> context.setValue(issues.getBySoftwareQuality(SoftwareQuality.RELIABILITY, false))), | |||||
new MeasureUpdateFormula(CoreMetrics.MAINTAINABILITY_ISSUES, false, true, new ImpactAddChildren(), | new MeasureUpdateFormula(CoreMetrics.MAINTAINABILITY_ISSUES, false, true, new ImpactAddChildren(), | ||||
(context, issues) -> context.setValue(issues.getBySoftwareQuality(SoftwareQuality.MAINTAINABILITY))), | |||||
(context, issues) -> context.setValue(issues.getBySoftwareQuality(SoftwareQuality.MAINTAINABILITY, false))), | |||||
new MeasureUpdateFormula(CoreMetrics.SECURITY_ISSUES, false, true, new ImpactAddChildren(), | new MeasureUpdateFormula(CoreMetrics.SECURITY_ISSUES, false, true, new ImpactAddChildren(), | ||||
(context, issues) -> context.setValue(issues.getBySoftwareQuality(SoftwareQuality.SECURITY))), | |||||
(context, issues) -> context.setValue(issues.getBySoftwareQuality(SoftwareQuality.SECURITY, false))), | |||||
new MeasureUpdateFormula(CoreMetrics.NEW_RELIABILITY_ISSUES, true, true, new ImpactAddChildren(), | |||||
(context, issues) -> context.setValue(issues.getBySoftwareQuality(SoftwareQuality.RELIABILITY, true))), | |||||
new MeasureUpdateFormula(CoreMetrics.NEW_MAINTAINABILITY_ISSUES, true, true, new ImpactAddChildren(), | |||||
(context, issues) -> context.setValue(issues.getBySoftwareQuality(SoftwareQuality.MAINTAINABILITY, true))), | |||||
new MeasureUpdateFormula(CoreMetrics.NEW_SECURITY_ISSUES, true, true, new ImpactAddChildren(), | |||||
(context, issues) -> context.setValue(issues.getBySoftwareQuality(SoftwareQuality.SECURITY, true))), | |||||
new MeasureUpdateFormula(CoreMetrics.VIOLATIONS, false, new AddChildren(), | new MeasureUpdateFormula(CoreMetrics.VIOLATIONS, false, new AddChildren(), | ||||
(context, issues) -> context.setValue(issues.countUnresolved(false))), | (context, issues) -> context.setValue(issues.countUnresolved(false))), |
new Change("10.5", String.format("The metrics %s are now deprecated " + | new Change("10.5", String.format("The metrics %s are now deprecated " + | ||||
"without exact replacement. Use 'maintainability_issues', 'reliability_issues' and 'security_issues' instead.", | "without exact replacement. Use 'maintainability_issues', 'reliability_issues' and 'security_issues' instead.", | ||||
MeasuresWsModule.getDeprecatedMetricsInSonarQube105())), | MeasuresWsModule.getDeprecatedMetricsInSonarQube105())), | ||||
new Change("10.5", "Added new accepted values for the 'metricKeys' param: 'new_maintainability_issues', 'new_reliability_issues', 'new_security_issues'"), | |||||
new Change("10.4", String.format("The metrics %s are now deprecated " + | new Change("10.4", String.format("The metrics %s are now deprecated " + | ||||
"without exact replacement. Use 'maintainability_issues', 'reliability_issues' and 'security_issues' instead.", | "without exact replacement. Use 'maintainability_issues', 'reliability_issues' and 'security_issues' instead.", | ||||
MeasuresWsModule.getDeprecatedMetricsInSonarQube104())), | MeasuresWsModule.getDeprecatedMetricsInSonarQube104())), |
import static java.util.Collections.emptyMap; | import static java.util.Collections.emptyMap; | ||||
import static java.util.Optional.ofNullable; | import static java.util.Optional.ofNullable; | ||||
import static org.sonar.api.measures.CoreMetrics.MAINTAINABILITY_ISSUES_KEY; | import static org.sonar.api.measures.CoreMetrics.MAINTAINABILITY_ISSUES_KEY; | ||||
import static org.sonar.api.measures.CoreMetrics.NEW_MAINTAINABILITY_ISSUES_KEY; | |||||
import static org.sonar.api.measures.CoreMetrics.NEW_RELIABILITY_ISSUES_KEY; | |||||
import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_ISSUES_KEY; | |||||
import static org.sonar.api.measures.CoreMetrics.RELIABILITY_ISSUES_KEY; | import static org.sonar.api.measures.CoreMetrics.RELIABILITY_ISSUES_KEY; | ||||
import static org.sonar.api.measures.CoreMetrics.SECURITY_ISSUES_KEY; | import static org.sonar.api.measures.CoreMetrics.SECURITY_ISSUES_KEY; | ||||
import static org.sonar.api.measures.Metric.ValueType.DATA; | import static org.sonar.api.measures.Metric.ValueType.DATA; | ||||
.setHandler(this) | .setHandler(this) | ||||
.addPagingParams(100, MAX_SIZE) | .addPagingParams(100, MAX_SIZE) | ||||
.setChangelog( | .setChangelog( | ||||
new Change("10.5", "Added new accepted values for the 'metricKeys' param: 'new_maintainability_issues', 'new_reliability_issues', 'new_security_issues'"), | |||||
new Change("10.5", String.format("The metrics %s are now deprecated " + | new Change("10.5", String.format("The metrics %s are now deprecated " + | ||||
"without exact replacement. Use 'maintainability_issues', 'reliability_issues' and 'security_issues' instead.", | "without exact replacement. Use 'maintainability_issues', 'reliability_issues' and 'security_issues' instead.", | ||||
MeasuresWsModule.getDeprecatedMetricsInSonarQube105())), | MeasuresWsModule.getDeprecatedMetricsInSonarQube105())), | ||||
static final Set<String> FORBIDDEN_METRIC_TYPES = Set.of(DISTRIB.name()); | static final Set<String> FORBIDDEN_METRIC_TYPES = Set.of(DISTRIB.name()); | ||||
static final Map<String, Set<String>> PARTIALLY_SUPPORTED_METRICS= Map. of( | static final Map<String, Set<String>> PARTIALLY_SUPPORTED_METRICS= Map. of( | ||||
DATA.name(), Set.of(SECURITY_ISSUES_KEY, MAINTAINABILITY_ISSUES_KEY, RELIABILITY_ISSUES_KEY)); | |||||
DATA.name(), | |||||
Set.of( | |||||
SECURITY_ISSUES_KEY, | |||||
MAINTAINABILITY_ISSUES_KEY, | |||||
RELIABILITY_ISSUES_KEY, | |||||
NEW_SECURITY_ISSUES_KEY, | |||||
NEW_MAINTAINABILITY_ISSUES_KEY, | |||||
NEW_RELIABILITY_ISSUES_KEY)); | |||||
@Override | @Override | ||||
public boolean test(@Nonnull MetricDto input) { | public boolean test(@Nonnull MetricDto input) { |
new Change("10.5", String.format("The metrics %s are now deprecated " + | new Change("10.5", String.format("The metrics %s are now deprecated " + | ||||
"without exact replacement. Use 'maintainability_issues', 'reliability_issues' and 'security_issues' instead.", | "without exact replacement. Use 'maintainability_issues', 'reliability_issues' and 'security_issues' instead.", | ||||
MeasuresWsModule.getDeprecatedMetricsInSonarQube105())), | MeasuresWsModule.getDeprecatedMetricsInSonarQube105())), | ||||
new Change("10.5", "Added new accepted values for the 'metricKeys' param: 'new_maintainability_issues', 'new_reliability_issues', 'new_security_issues'"), | |||||
new Change("10.4", String.format("The metrics %s are now deprecated " + | new Change("10.4", String.format("The metrics %s are now deprecated " + | ||||
"without exact replacement. Use 'maintainability_issues', 'reliability_issues' and 'security_issues' instead.", | "without exact replacement. Use 'maintainability_issues', 'reliability_issues' and 'security_issues' instead.", | ||||
MeasuresWsModule.getDeprecatedMetricsInSonarQube104())), | MeasuresWsModule.getDeprecatedMetricsInSonarQube104())), |
new Change("10.5", String.format("The metrics %s are now deprecated " + | new Change("10.5", String.format("The metrics %s are now deprecated " + | ||||
"without exact replacement. Use 'maintainability_issues', 'reliability_issues' and 'security_issues' instead.", | "without exact replacement. Use 'maintainability_issues', 'reliability_issues' and 'security_issues' instead.", | ||||
MeasuresWsModule.getDeprecatedMetricsInSonarQube105())), | MeasuresWsModule.getDeprecatedMetricsInSonarQube105())), | ||||
new Change("10.5", "Added new accepted values for the 'metricKeys' param: 'new_maintainability_issues', 'new_reliability_issues', 'new_security_issues'"), | |||||
new Change("10.4", String.format("The metrics %s are now deprecated " + | new Change("10.4", String.format("The metrics %s are now deprecated " + | ||||
"without exact replacement. Use 'maintainability_issues', 'reliability_issues' and 'security_issues' instead.", | "without exact replacement. Use 'maintainability_issues', 'reliability_issues' and 'security_issues' instead.", | ||||
MeasuresWsModule.getDeprecatedMetricsInSonarQube104())), | MeasuresWsModule.getDeprecatedMetricsInSonarQube104())), |
import java.util.Optional; | import java.util.Optional; | ||||
import java.util.Set; | import java.util.Set; | ||||
import javax.annotation.Nullable; | import javax.annotation.Nullable; | ||||
import org.junit.Test; | |||||
import org.junit.jupiter.api.Test; | |||||
import org.sonar.api.issue.Issue; | import org.sonar.api.issue.Issue; | ||||
import org.sonar.api.issue.impact.SoftwareQuality; | import org.sonar.api.issue.impact.SoftwareQuality; | ||||
import org.sonar.api.measures.CoreMetrics; | import org.sonar.api.measures.CoreMetrics; | ||||
import static org.sonar.api.measures.CoreMetrics.SECURITY_REVIEW_RATING; | import static org.sonar.api.measures.CoreMetrics.SECURITY_REVIEW_RATING; | ||||
import static org.sonar.test.JsonAssert.assertJson; | import static org.sonar.test.JsonAssert.assertJson; | ||||
public class MeasureUpdateFormulaFactoryImplTest { | |||||
class MeasureUpdateFormulaFactoryImplTest { | |||||
public static final Gson GSON = new GsonBuilder().create(); | |||||
private static final Gson GSON = new GsonBuilder().create(); | |||||
private final MeasureUpdateFormulaFactoryImpl underTest = new MeasureUpdateFormulaFactoryImpl(); | private final MeasureUpdateFormulaFactoryImpl underTest = new MeasureUpdateFormulaFactoryImpl(); | ||||
@Test | @Test | ||||
public void getFormulaMetrics_include_the_dependent_metrics() { | |||||
void getFormulaMetrics_include_the_dependent_metrics() { | |||||
for (MeasureUpdateFormula formula : underTest.getFormulas()) { | for (MeasureUpdateFormula formula : underTest.getFormulas()) { | ||||
assertThat(underTest.getFormulaMetrics()).contains(formula.getMetric()); | assertThat(underTest.getFormulaMetrics()).contains(formula.getMetric()); | ||||
for (Metric<?> dependentMetric : formula.getDependentMetrics()) { | for (Metric<?> dependentMetric : formula.getDependentMetrics()) { | ||||
} | } | ||||
@Test | @Test | ||||
public void hierarchy_adding_numbers() { | |||||
void hierarchy_adding_numbers() { | |||||
new HierarchyTester(CoreMetrics.VIOLATIONS) | new HierarchyTester(CoreMetrics.VIOLATIONS) | ||||
.withValue(1d) | .withValue(1d) | ||||
.withChildrenValues(2d, 3d) | .withChildrenValues(2d, 3d) | ||||
} | } | ||||
@Test | @Test | ||||
public void hierarchy_highest_rating() { | |||||
void hierarchy_highest_rating() { | |||||
new HierarchyTester(CoreMetrics.RELIABILITY_RATING) | new HierarchyTester(CoreMetrics.RELIABILITY_RATING) | ||||
.withValue(1d) | .withValue(1d) | ||||
.withChildrenValues(2d, 3d) | .withChildrenValues(2d, 3d) | ||||
} | } | ||||
@Test | @Test | ||||
public void hierarchy_combining_other_metrics() { | |||||
void hierarchy_combining_other_metrics() { | |||||
new HierarchyTester(SECURITY_HOTSPOTS_TO_REVIEW_STATUS) | new HierarchyTester(SECURITY_HOTSPOTS_TO_REVIEW_STATUS) | ||||
.withValue(SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 1d) | .withValue(SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 1d) | ||||
.withChildrenHotspotsCounts(10, 10, 2, 10) | .withChildrenHotspotsCounts(10, 10, 2, 10) | ||||
} | } | ||||
@Test | @Test | ||||
public void test_violations() { | |||||
void test_violations() { | |||||
withNoIssues().assertThatValueIs(CoreMetrics.VIOLATIONS, 0); | withNoIssues().assertThatValueIs(CoreMetrics.VIOLATIONS, 0); | ||||
with(newGroup(), newGroup().setCount(4)).assertThatValueIs(CoreMetrics.VIOLATIONS, 5); | with(newGroup(), newGroup().setCount(4)).assertThatValueIs(CoreMetrics.VIOLATIONS, 5); | ||||
} | } | ||||
@Test | @Test | ||||
public void test_bugs() { | |||||
void test_bugs() { | |||||
withNoIssues().assertThatValueIs(CoreMetrics.BUGS, 0); | withNoIssues().assertThatValueIs(CoreMetrics.BUGS, 0); | ||||
with( | with( | ||||
newGroup(RuleType.BUG).setSeverity(Severity.MAJOR).setCount(3), | newGroup(RuleType.BUG).setSeverity(Severity.MAJOR).setCount(3), | ||||
} | } | ||||
@Test | @Test | ||||
public void test_code_smells() { | |||||
void test_code_smells() { | |||||
withNoIssues().assertThatValueIs(CoreMetrics.CODE_SMELLS, 0); | withNoIssues().assertThatValueIs(CoreMetrics.CODE_SMELLS, 0); | ||||
with( | with( | ||||
newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setCount(3), | newGroup(RuleType.CODE_SMELL).setSeverity(Severity.MAJOR).setCount(3), | ||||
} | } | ||||
@Test | @Test | ||||
public void test_vulnerabilities() { | |||||
void test_vulnerabilities() { | |||||
withNoIssues().assertThatValueIs(CoreMetrics.VULNERABILITIES, 0); | withNoIssues().assertThatValueIs(CoreMetrics.VULNERABILITIES, 0); | ||||
with( | with( | ||||
newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MAJOR).setCount(3), | newGroup(RuleType.VULNERABILITY).setSeverity(Severity.MAJOR).setCount(3), | ||||
} | } | ||||
@Test | @Test | ||||
public void test_security_hotspots() { | |||||
void test_security_hotspots() { | |||||
withNoIssues().assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS, 0); | withNoIssues().assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS, 0); | ||||
with( | with( | ||||
newGroup(RuleType.SECURITY_HOTSPOT).setSeverity(Severity.MAJOR).setCount(3), | newGroup(RuleType.SECURITY_HOTSPOT).setSeverity(Severity.MAJOR).setCount(3), | ||||
} | } | ||||
@Test | @Test | ||||
public void test_security_review_rating() { | |||||
void test_security_review_rating() { | |||||
with( | with( | ||||
newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3), | newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3), | ||||
newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1)) | newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1)) | ||||
} | } | ||||
@Test | @Test | ||||
public void test_security_hotspots_reviewed() { | |||||
void test_security_hotspots_reviewed() { | |||||
with( | with( | ||||
newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3), | newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3), | ||||
newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1)) | newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1)) | ||||
} | } | ||||
@Test | @Test | ||||
public void test_security_hotspots_reviewed_status() { | |||||
void test_security_hotspots_reviewed_status() { | |||||
with( | with( | ||||
newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3), | newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3), | ||||
newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1)) | newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1)) | ||||
} | } | ||||
@Test | @Test | ||||
public void test_security_hotspots_to_review_status() { | |||||
void test_security_hotspots_to_review_status() { | |||||
with( | with( | ||||
newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3), | newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3), | ||||
newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1)) | newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1)) | ||||
} | } | ||||
@Test | @Test | ||||
public void count_unresolved_by_severity() { | |||||
void count_unresolved_by_severity() { | |||||
withNoIssues() | withNoIssues() | ||||
.assertThatValueIs(CoreMetrics.BLOCKER_VIOLATIONS, 0) | .assertThatValueIs(CoreMetrics.BLOCKER_VIOLATIONS, 0) | ||||
.assertThatValueIs(CoreMetrics.CRITICAL_VIOLATIONS, 0) | .assertThatValueIs(CoreMetrics.CRITICAL_VIOLATIONS, 0) | ||||
} | } | ||||
@Test | @Test | ||||
public void count_resolved() { | |||||
void count_resolved() { | |||||
withNoIssues() | withNoIssues() | ||||
.assertThatValueIs(CoreMetrics.FALSE_POSITIVE_ISSUES, 0) | .assertThatValueIs(CoreMetrics.FALSE_POSITIVE_ISSUES, 0) | ||||
.assertThatValueIs(CoreMetrics.ACCEPTED_ISSUES, 0); | .assertThatValueIs(CoreMetrics.ACCEPTED_ISSUES, 0); | ||||
} | } | ||||
@Test | @Test | ||||
public void count_by_status() { | |||||
void count_by_status() { | |||||
withNoIssues() | withNoIssues() | ||||
.assertThatValueIs(CoreMetrics.CONFIRMED_ISSUES, 0) | .assertThatValueIs(CoreMetrics.CONFIRMED_ISSUES, 0) | ||||
.assertThatValueIs(CoreMetrics.OPEN_ISSUES, 0) | .assertThatValueIs(CoreMetrics.OPEN_ISSUES, 0) | ||||
} | } | ||||
@Test | @Test | ||||
public void test_technical_debt() { | |||||
void test_technical_debt() { | |||||
withNoIssues().assertThatValueIs(CoreMetrics.TECHNICAL_DEBT, 0); | withNoIssues().assertThatValueIs(CoreMetrics.TECHNICAL_DEBT, 0); | ||||
with( | with( | ||||
} | } | ||||
@Test | @Test | ||||
public void test_reliability_remediation_effort() { | |||||
void test_reliability_remediation_effort() { | |||||
withNoIssues().assertThatValueIs(CoreMetrics.RELIABILITY_REMEDIATION_EFFORT, 0); | withNoIssues().assertThatValueIs(CoreMetrics.RELIABILITY_REMEDIATION_EFFORT, 0); | ||||
with( | with( | ||||
} | } | ||||
@Test | @Test | ||||
public void test_security_remediation_effort() { | |||||
void test_security_remediation_effort() { | |||||
withNoIssues().assertThatValueIs(CoreMetrics.SECURITY_REMEDIATION_EFFORT, 0); | withNoIssues().assertThatValueIs(CoreMetrics.SECURITY_REMEDIATION_EFFORT, 0); | ||||
with( | with( | ||||
} | } | ||||
@Test | @Test | ||||
public void test_sqale_debt_ratio_and_sqale_rating() { | |||||
void test_sqale_debt_ratio_and_sqale_rating() { | |||||
withNoIssues() | withNoIssues() | ||||
.assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0) | .assertThatValueIs(CoreMetrics.SQALE_DEBT_RATIO, 0) | ||||
.assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A); | .assertThatValueIs(CoreMetrics.SQALE_RATING, Rating.A); | ||||
} | } | ||||
@Test | @Test | ||||
public void test_effort_to_reach_maintainability_rating_A() { | |||||
void test_effort_to_reach_maintainability_rating_A() { | |||||
withNoIssues() | withNoIssues() | ||||
.assertThatValueIs(CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A, 0.0); | .assertThatValueIs(CoreMetrics.EFFORT_TO_REACH_MAINTAINABILITY_RATING_A, 0.0); | ||||
} | } | ||||
@Test | @Test | ||||
public void test_reliability_rating() { | |||||
void test_reliability_rating() { | |||||
withNoIssues() | withNoIssues() | ||||
.assertThatValueIs(CoreMetrics.RELIABILITY_RATING, Rating.A); | .assertThatValueIs(CoreMetrics.RELIABILITY_RATING, Rating.A); | ||||
} | } | ||||
@Test | @Test | ||||
public void test_security_rating() { | |||||
void test_security_rating() { | |||||
withNoIssues() | withNoIssues() | ||||
.assertThatValueIs(CoreMetrics.SECURITY_RATING, Rating.A); | .assertThatValueIs(CoreMetrics.SECURITY_RATING, Rating.A); | ||||
} | } | ||||
@Test | @Test | ||||
public void test_new_bugs() { | |||||
void test_new_bugs() { | |||||
withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_BUGS, 0.0); | withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_BUGS, 0.0); | ||||
with( | with( | ||||
} | } | ||||
@Test | @Test | ||||
public void test_new_code_smells() { | |||||
void test_new_code_smells() { | |||||
withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_CODE_SMELLS, 0.0); | withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_CODE_SMELLS, 0.0); | ||||
with( | with( | ||||
} | } | ||||
@Test | @Test | ||||
public void test_new_vulnerabilities() { | |||||
void test_new_vulnerabilities() { | |||||
withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_VULNERABILITIES, 0.0); | withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_VULNERABILITIES, 0.0); | ||||
with( | with( | ||||
} | } | ||||
@Test | @Test | ||||
public void test_new_security_hotspots() { | |||||
void test_new_security_hotspots() { | |||||
withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS, 0); | withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS, 0); | ||||
with( | with( | ||||
} | } | ||||
@Test | @Test | ||||
public void test_new_violations() { | |||||
void test_new_violations() { | |||||
withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_VIOLATIONS, 0.0); | withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_VIOLATIONS, 0.0); | ||||
with( | with( | ||||
} | } | ||||
@Test | @Test | ||||
public void test_new_blocker_violations() { | |||||
void test_new_blocker_violations() { | |||||
withNoIssues() | withNoIssues() | ||||
.assertThatLeakValueIs(CoreMetrics.NEW_BLOCKER_VIOLATIONS, 0.0); | .assertThatLeakValueIs(CoreMetrics.NEW_BLOCKER_VIOLATIONS, 0.0); | ||||
} | } | ||||
@Test | @Test | ||||
public void test_new_critical_violations() { | |||||
void test_new_critical_violations() { | |||||
withNoIssues() | withNoIssues() | ||||
.assertThatLeakValueIs(CoreMetrics.NEW_CRITICAL_VIOLATIONS, 0.0); | .assertThatLeakValueIs(CoreMetrics.NEW_CRITICAL_VIOLATIONS, 0.0); | ||||
} | } | ||||
@Test | @Test | ||||
public void test_new_major_violations() { | |||||
void test_new_major_violations() { | |||||
withNoIssues() | withNoIssues() | ||||
.assertThatLeakValueIs(CoreMetrics.NEW_MAJOR_VIOLATIONS, 0.0); | .assertThatLeakValueIs(CoreMetrics.NEW_MAJOR_VIOLATIONS, 0.0); | ||||
} | } | ||||
@Test | @Test | ||||
public void test_new_minor_violations() { | |||||
void test_new_minor_violations() { | |||||
withNoIssues() | withNoIssues() | ||||
.assertThatLeakValueIs(CoreMetrics.NEW_MINOR_VIOLATIONS, 0.0); | .assertThatLeakValueIs(CoreMetrics.NEW_MINOR_VIOLATIONS, 0.0); | ||||
} | } | ||||
@Test | @Test | ||||
public void test_new_info_violations() { | |||||
void test_new_info_violations() { | |||||
withNoIssues() | withNoIssues() | ||||
.assertThatLeakValueIs(CoreMetrics.NEW_INFO_VIOLATIONS, 0.0); | .assertThatLeakValueIs(CoreMetrics.NEW_INFO_VIOLATIONS, 0.0); | ||||
} | } | ||||
@Test | @Test | ||||
public void test_new_accepted_issues() { | |||||
void test_new_accepted_issues() { | |||||
withNoIssues() | withNoIssues() | ||||
.assertThatLeakValueIs(CoreMetrics.NEW_ACCEPTED_ISSUES, 0); | .assertThatLeakValueIs(CoreMetrics.NEW_ACCEPTED_ISSUES, 0); | ||||
} | } | ||||
@Test | @Test | ||||
public void test_new_technical_debt() { | |||||
void test_new_technical_debt() { | |||||
withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_TECHNICAL_DEBT, 0.0); | withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_TECHNICAL_DEBT, 0.0); | ||||
with( | with( | ||||
} | } | ||||
@Test | @Test | ||||
public void test_new_reliability_remediation_effort() { | |||||
void test_new_reliability_remediation_effort() { | |||||
withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_RELIABILITY_REMEDIATION_EFFORT, 0.0); | withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_RELIABILITY_REMEDIATION_EFFORT, 0.0); | ||||
with( | with( | ||||
} | } | ||||
@Test | @Test | ||||
public void test_new_security_remediation_effort() { | |||||
void test_new_security_remediation_effort() { | |||||
withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_REMEDIATION_EFFORT, 0.0); | withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_REMEDIATION_EFFORT, 0.0); | ||||
with( | with( | ||||
} | } | ||||
@Test | @Test | ||||
public void test_new_reliability_rating() { | |||||
void test_new_reliability_rating() { | |||||
withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_RELIABILITY_RATING, Rating.A); | withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_RELIABILITY_RATING, Rating.A); | ||||
with( | with( | ||||
} | } | ||||
@Test | @Test | ||||
public void test_new_security_rating() { | |||||
void test_new_security_rating() { | |||||
withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_RATING, Rating.A); | withNoIssues().assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_RATING, Rating.A); | ||||
with( | with( | ||||
} | } | ||||
@Test | @Test | ||||
public void test_new_security_review_rating() { | |||||
void test_new_security_review_rating() { | |||||
with( | with( | ||||
newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3).setInLeak(true), | newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3).setInLeak(true), | ||||
newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1).setInLeak(true), | newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1).setInLeak(true), | ||||
} | } | ||||
@Test | @Test | ||||
public void test_new_security_hotspots_reviewed() { | |||||
void test_new_security_hotspots_reviewed() { | |||||
with( | with( | ||||
newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3).setInLeak(true), | newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3).setInLeak(true), | ||||
newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1).setInLeak(true), | newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1).setInLeak(true), | ||||
} | } | ||||
@Test | @Test | ||||
public void test_new_security_hotspots_reviewed_status() { | |||||
void test_new_security_hotspots_reviewed_status() { | |||||
with( | with( | ||||
newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3).setInLeak(true), | newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3).setInLeak(true), | ||||
newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1).setInLeak(true), | newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1).setInLeak(true), | ||||
} | } | ||||
@Test | @Test | ||||
public void test_new_security_hotspots_to_review_status() { | |||||
void test_new_security_hotspots_to_review_status() { | |||||
with( | with( | ||||
newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3).setInLeak(true), | newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3).setInLeak(true), | ||||
newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1).setInLeak(true), | newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1).setInLeak(true), | ||||
} | } | ||||
@Test | @Test | ||||
public void test_new_sqale_debt_ratio_and_new_maintainability_rating() { | |||||
void test_new_sqale_debt_ratio_and_new_maintainability_rating() { | |||||
withNoIssues() | withNoIssues() | ||||
.assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0) | .assertThatLeakValueIs(CoreMetrics.NEW_SQALE_DEBT_RATIO, 0) | ||||
.assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A); | .assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A); | ||||
} | } | ||||
@Test | @Test | ||||
public void compute_shouldComputeHighImpactAcceptedIssues() { | |||||
void compute_shouldComputeHighImpactAcceptedIssues() { | |||||
withNoIssues() | withNoIssues() | ||||
.assertThatValueIs(CoreMetrics.HIGH_IMPACT_ACCEPTED_ISSUES, 0); | .assertThatValueIs(CoreMetrics.HIGH_IMPACT_ACCEPTED_ISSUES, 0); | ||||
} | } | ||||
@Test | @Test | ||||
public void computeHierarchy_shouldComputeImpactMeasures() { | |||||
void computeHierarchy_shouldComputeImpactMeasures() { | |||||
new HierarchyTester(CoreMetrics.RELIABILITY_ISSUES) | new HierarchyTester(CoreMetrics.RELIABILITY_ISSUES) | ||||
.withValue(impactMeasureToJson(6, 1, 2, 3)) | .withValue(impactMeasureToJson(6, 1, 2, 3)) | ||||
.withChildrenValues(impactMeasureToJson(6, 1, 2, 3), impactMeasureToJson(10, 5, 3, 2)) | .withChildrenValues(impactMeasureToJson(6, 1, 2, 3), impactMeasureToJson(10, 5, 3, 2)) | ||||
} | } | ||||
@Test | @Test | ||||
public void compute_shouldComputeImpactMeasures() { | |||||
void compute_shouldComputeImpactMeasures() { | |||||
with( | with( | ||||
newImpactGroup(RELIABILITY, HIGH, 3), | newImpactGroup(RELIABILITY, HIGH, 3), | ||||
newImpactGroup(RELIABILITY, MEDIUM, 4), | newImpactGroup(RELIABILITY, MEDIUM, 4), | ||||
} | } | ||||
@Test | @Test | ||||
public void compute_whenNoIssues_shouldComputeImpactMeasures() { | |||||
void compute_whenNoIssues_shouldComputeImpactMeasures() { | |||||
withNoIssues() | withNoIssues() | ||||
.assertThatJsonValueIs(CoreMetrics.RELIABILITY_ISSUES, impactMeasureToJson(0, 0, 0, 0)) | .assertThatJsonValueIs(CoreMetrics.RELIABILITY_ISSUES, impactMeasureToJson(0, 0, 0, 0)) | ||||
.assertThatJsonValueIs(CoreMetrics.MAINTAINABILITY_ISSUES, impactMeasureToJson(0, 0, 0, 0)) | .assertThatJsonValueIs(CoreMetrics.MAINTAINABILITY_ISSUES, impactMeasureToJson(0, 0, 0, 0)) | ||||
.assertThatJsonValueIs(CoreMetrics.SECURITY_ISSUES, impactMeasureToJson(0, 0, 0, 0)); | |||||
.assertThatJsonValueIs(CoreMetrics.SECURITY_ISSUES, impactMeasureToJson(0, 0, 0, 0)) | |||||
.assertThatLeakValueIs(CoreMetrics.NEW_RELIABILITY_ISSUES, impactMeasureToJson(0, 0, 0, 0)) | |||||
.assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_ISSUES, impactMeasureToJson(0, 0, 0, 0)) | |||||
.assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_ISSUES, impactMeasureToJson(0, 0, 0, 0)); | |||||
} | } | ||||
private static String impactMeasureToJson(long total, long high, long medium, long low) { | private static String impactMeasureToJson(long total, long high, long medium, long low) { | ||||
return this; | return this; | ||||
} | } | ||||
Verifier assertThatLeakValueIs(Metric metric, String expectedValue) { | |||||
TestContext context = run(metric, true); | |||||
assertJson(context.stringValue).isSimilarTo(expectedValue); | |||||
return this; | |||||
} | |||||
Verifier assertNoLeakValue(Metric metric) { | Verifier assertNoLeakValue(Metric metric) { | ||||
TestContext context = run(metric, true); | TestContext context = run(metric, true); | ||||
assertThat(context.ratingValue).isNull(); | assertThat(context.ratingValue).isNull(); |
metric.security_issues.name=Security Issues | metric.security_issues.name=Security Issues | ||||
metric.security_issues.description=Security issues | metric.security_issues.description=Security issues | ||||
metric.security_issues.short_name=Security | metric.security_issues.short_name=Security | ||||
metric.new_maintainability_issues.name=New Maintainability Issues | |||||
metric.new_maintainability_issues.description=New maintainability issues | |||||
metric.new_maintainability_issues.short_name=New Maintainability | |||||
metric.new_reliability_issues.name=New Reliability Issues | |||||
metric.new_reliability_issues.description=New reliability issues | |||||
metric.new_reliability_issues.short_name=New Reliability | |||||
metric.new_security_issues.name=New Security Issues | |||||
metric.new_security_issues.description=New security issues | |||||
metric.new_security_issues.short_name=New Security | |||||
#------------------------------------------------------------------------------ | #------------------------------------------------------------------------------ | ||||
# | # |