ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(project));
RuleDto rule = db.rules().insert();
db.issues().insert(rule, project, file,
- i -> i.setStatus("RESOLVED").setResolution("FALSE-POSITIVE").setSeverity("MAJOR").setType(RuleType.BUG).setIssueCreationTime(1_500L)
- .replaceAllImpacts(List.of(createImpact(SECURITY, HIGH), createImpact(MAINTAINABILITY, LOW))));
+ i -> i.setStatus("RESOLVED").setResolution("FALSE-POSITIVE").setSeverity("MAJOR").setType(RuleType.BUG).setIssueCreationTime(1_500L));
db.issues().insert(rule, project, file,
- i -> i.setStatus("OPEN").setResolution(null).setSeverity("CRITICAL").setType(RuleType.BUG).setIssueCreationTime(1_600L)
- .replaceAllImpacts(List.of(createImpact(SECURITY, HIGH), createImpact(MAINTAINABILITY, HIGH))));
+ i -> i.setStatus("OPEN").setResolution(null).setSeverity("CRITICAL").setType(RuleType.BUG).setIssueCreationTime(1_600L));
IssueDto criticalBug2 = db.issues().insert(rule, project, file,
- i -> i.setStatus("OPEN").setResolution(null).setSeverity("CRITICAL").setType(RuleType.BUG).setIssueCreationTime(1_700L)
- .replaceAllImpacts(List.of(createImpact(SECURITY, MEDIUM), createImpact(MAINTAINABILITY, LOW))));
+ i -> i.setStatus("OPEN").setResolution(null).setSeverity("CRITICAL").setType(RuleType.BUG).setIssueCreationTime(1_700L));
// closed issues are ignored
db.issues().insert(rule, project, file,
- i -> i.setStatus("CLOSED").setResolution("REMOVED").setSeverity("CRITICAL").setType(RuleType.BUG).setIssueCreationTime(1_700L)
- .replaceAllImpacts(List.of(createImpact(SECURITY, HIGH))));
+ i -> i.setStatus("CLOSED").setResolution("REMOVED").setSeverity("CRITICAL").setType(RuleType.BUG).setIssueCreationTime(1_700L));
Collection<IssueGroupDto> result = underTest.selectIssueGroupsByComponent(db.getSession(), file, 1_000L);
- assertThat(result).hasSize(3);
assertThat(result.stream().mapToLong(IssueGroupDto::getCount).sum()).isEqualTo(3);
assertThat(result.stream().filter(g -> g.getRuleType() == RuleType.BUG.getDbConstant()).mapToLong(IssueGroupDto::getCount).sum()).isEqualTo(3);
assertThat(result.stream().filter(g -> g.getSeverity().equals("CRITICAL")).mapToLong(IssueGroupDto::getCount).sum()).isEqualTo(2);
assertThat(result.stream().filter(g -> g.getSeverity().equals("MAJOR")).mapToLong(IssueGroupDto::getCount).sum()).isOne();
assertThat(result.stream().filter(g -> g.getSeverity().equals("MINOR")).mapToLong(IssueGroupDto::getCount).sum()).isZero();
- assertThat(result.stream().filter(IssueGroupDto::hasHighImpactSeverity).mapToLong(IssueGroupDto::getCount).sum()).isEqualTo(2);
assertThat(result.stream().filter(g -> g.getStatus().equals("OPEN")).mapToLong(IssueGroupDto::getCount).sum()).isEqualTo(2);
assertThat(result.stream().filter(g -> g.getStatus().equals("RESOLVED")).mapToLong(IssueGroupDto::getCount).sum()).isOne();
assertThat(result.stream().filter(g -> !g.isInLeak()).mapToLong(IssueGroupDto::getCount).sum()).isEqualTo(3);
}
- @NotNull
- private static ImpactDto createImpact(SoftwareQuality softwareQuality, Severity high) {
- return new ImpactDto().setUuid(UuidFactoryFast.getInstance().create()).setSoftwareQuality(softwareQuality).setSeverity(high);
- }
-
@Test
public void selectGroupsOfComponentTreeOnLeak_on_file_new_code_reference_branch() {
ComponentDto project = db.components().insertPublicProject().getMainBranchComponent();
RuleDto rule = db.rules().insert();
IssueDto fpBug = db.issues().insert(rule, project, file,
i -> i.setStatus("RESOLVED").setResolution("FALSE-POSITIVE").setSeverity("MAJOR").setType(RuleType.BUG));
- IssueDto acceptedBug = db.issues().insert(rule, project, file,
- i -> i.setStatus("RESOLVED").setResolution("WONTFIX").setSeverity("MAJOR").setType(RuleType.BUG));
IssueDto criticalBug1 = db.issues().insert(rule, project, file,
i -> i.setStatus("OPEN").setResolution(null).setSeverity("CRITICAL").setType(RuleType.BUG));
IssueDto criticalBug2 = db.issues().insert(rule, project, file,
// two issues part of new code period on reference branch
db.issues().insertNewCodeReferenceIssue(fpBug);
- db.issues().insertNewCodeReferenceIssue(acceptedBug);
db.issues().insertNewCodeReferenceIssue(criticalBug1);
db.issues().insertNewCodeReferenceIssue(criticalBug2);
Collection<IssueGroupDto> result = underTest.selectIssueGroupsByComponent(db.getSession(), file, -1);
- assertThat(result.stream().mapToLong(IssueGroupDto::getCount).sum()).isEqualTo(5);
+ assertThat(result.stream().mapToLong(IssueGroupDto::getCount).sum()).isEqualTo(4);
- assertThat(result.stream().filter(g -> g.getRuleType() == RuleType.BUG.getDbConstant()).mapToLong(IssueGroupDto::getCount).sum()).isEqualTo(5);
+ assertThat(result.stream().filter(g -> g.getRuleType() == RuleType.BUG.getDbConstant()).mapToLong(IssueGroupDto::getCount).sum()).isEqualTo(4);
assertThat(result.stream().filter(g -> g.getRuleType() == RuleType.CODE_SMELL.getDbConstant()).mapToLong(IssueGroupDto::getCount).sum()).isZero();
assertThat(result.stream().filter(g -> g.getRuleType() == RuleType.VULNERABILITY.getDbConstant()).mapToLong(IssueGroupDto::getCount).sum()).isZero();
assertThat(result.stream().filter(g -> g.getSeverity().equals("CRITICAL")).mapToLong(IssueGroupDto::getCount).sum()).isEqualTo(3);
- assertThat(result.stream().filter(g -> g.getSeverity().equals("MAJOR")).mapToLong(IssueGroupDto::getCount).sum()).isEqualTo(2);
+ assertThat(result.stream().filter(g -> g.getSeverity().equals("MAJOR")).mapToLong(IssueGroupDto::getCount).sum()).isOne();
assertThat(result.stream().filter(g -> g.getSeverity().equals("MINOR")).mapToLong(IssueGroupDto::getCount).sum()).isZero();
assertThat(result.stream().filter(g -> g.getStatus().equals("OPEN")).mapToLong(IssueGroupDto::getCount).sum()).isEqualTo(3);
- assertThat(result.stream().filter(g -> g.getStatus().equals("RESOLVED")).mapToLong(IssueGroupDto::getCount).sum()).isEqualTo(2);
+ assertThat(result.stream().filter(g -> g.getStatus().equals("RESOLVED")).mapToLong(IssueGroupDto::getCount).sum()).isOne();
assertThat(result.stream().filter(g -> g.getStatus().equals("CLOSED")).mapToLong(IssueGroupDto::getCount).sum()).isZero();
assertThat(result.stream().filter(g -> "FALSE-POSITIVE".equals(g.getResolution())).mapToLong(IssueGroupDto::getCount).sum()).isOne();
- assertThat(result.stream().filter(g -> "WONTFIX".equals(g.getResolution())).mapToLong(IssueGroupDto::getCount).sum()).isOne();
assertThat(result.stream().filter(g -> g.getResolution() == null).mapToLong(IssueGroupDto::getCount).sum()).isEqualTo(3);
- assertThat(result.stream().filter(IssueGroupDto::isInLeak).mapToLong(IssueGroupDto::getCount).sum()).isEqualTo(4);
+ assertThat(result.stream().filter(IssueGroupDto::isInLeak).mapToLong(IssueGroupDto::getCount).sum()).isEqualTo(3);
assertThat(result.stream().filter(g -> !g.isInLeak()).mapToLong(IssueGroupDto::getCount).sum()).isOne();
}
ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(project));
RuleDto rule = db.rules().insert();
db.issues().insert(rule, project, file,
- i -> i.replaceAllImpacts(List.of(createImpact(SECURITY, HIGH), createImpact(MAINTAINABILITY, LOW))));
+ i -> i.setStatus(STATUS_OPEN).replaceAllImpacts(List.of(createImpact(SECURITY, HIGH), createImpact(MAINTAINABILITY, LOW))));
db.issues().insert(rule, project, file,
- i -> i.replaceAllImpacts(List.of(createImpact(SECURITY, HIGH), createImpact(MAINTAINABILITY, HIGH))));
+ i -> i.setStatus(STATUS_OPEN).replaceAllImpacts(List.of(createImpact(SECURITY, HIGH), createImpact(MAINTAINABILITY, HIGH))));
db.issues().insert(rule, project, file,
- i -> i.replaceAllImpacts(List.of(createImpact(SECURITY, HIGH))));
- // closed issues are ignored
+ i -> i.setStatus(STATUS_REOPENED).replaceAllImpacts(List.of(createImpact(SECURITY, HIGH))));
+ db.issues().insert(rule, project, file,
+ i -> i.setStatus(STATUS_RESOLVED).setResolution(RESOLUTION_WONT_FIX).replaceAllImpacts(List.of(createImpact(SECURITY, HIGH))));
+ // issues in ignored status
db.issues().insert(rule, project, file,
i -> i.setStatus(Issue.STATUS_CLOSED).replaceAllImpacts(List.of(createImpact(SECURITY, HIGH))));
+ db.issues().insert(rule, project, file,
+ i -> i.setStatus(STATUS_RESOLVED).setResolution(RESOLUTION_FALSE_POSITIVE).replaceAllImpacts(List.of(createImpact(SECURITY, HIGH))));
Collection<IssueImpactGroupDto> result = underTest.selectIssueImpactGroupsByComponent(db.getSession(), file);
- assertThat(result).hasSize(3);
- assertThat(result.stream().mapToLong(IssueImpactGroupDto::getCount).sum()).isEqualTo(5);
+ assertThat(result).hasSize(5);
+ 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() == MAINTAINABILITY).mapToLong(IssueImpactGroupDto::getCount).sum()).isEqualTo(2);
+
+ assertThat(result.stream().filter(g -> g.getSeverity() == HIGH).mapToLong(IssueImpactGroupDto::getCount).sum()).isEqualTo(5);
+ 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(4);
+ assertThat(result.stream().filter(g -> STATUS_REOPENED.equals(g.getStatus())).mapToLong(IssueImpactGroupDto::getCount).sum()).isOne();
+ 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(g -> g.getResolution() == null).mapToLong(IssueImpactGroupDto::getCount).sum()).isEqualTo(5);
- assertThat(result.stream().filter(g -> MAINTAINABILITY == g.getSoftwareQuality()).mapToLong(IssueImpactGroupDto::getCount).sum()).isEqualTo(2);
- assertThat(result.stream().filter(g -> SECURITY == g.getSoftwareQuality()).mapToLong(IssueImpactGroupDto::getCount).sum()).isEqualTo(3);
- assertThat(result.stream().filter(g -> SECURITY == g.getSoftwareQuality() && HIGH == g.getSeverity()).mapToLong(IssueImpactGroupDto::getCount).sum()).isEqualTo(3);
- assertThat(result.stream().filter(g -> HIGH == g.getSeverity()).mapToLong(IssueImpactGroupDto::getCount).sum()).isEqualTo(4);
- assertThat(result.stream().filter(g -> LOW == g.getSeverity()).mapToLong(IssueImpactGroupDto::getCount).sum()).isEqualTo(1);
+ assertThat(result.stream().noneMatch(g -> STATUS_CLOSED.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 -> MEDIUM == g.getSeverity())).isTrue();
+ }
+
+ @NotNull
+ private static ImpactDto createImpact(SoftwareQuality softwareQuality, Severity high) {
+ return new ImpactDto().setUuid(UuidFactoryFast.getInstance().create()).setSoftwareQuality(softwareQuality).setSeverity(high);
}
@Test
</select>
<select id="selectIssueGroupsByComponent" resultType="org.sonar.db.issue.IssueGroupDto" parameterType="map">
- <include refid="withHighImpactSeverityIssues"/>
select
i.issue_type as ruleType,
i.severity as severity,
- exists(select 1 from high_impact_severity_issues hisi where hisi.kee = i.kee) as hasHighImpactSeverity,
i.resolution as resolution,
i.status as status, sum(i.effort) as effort,
count(i.issue_type) as "count",
</if>
where i.status <> 'CLOSED'
and i.component_uuid = #{component.uuid,jdbcType=VARCHAR}
- group by i.issue_type, i.severity, hasHighImpactSeverity, i.resolution, i.status, inLeak
+ group by i.issue_type, i.severity, i.resolution, i.status, inLeak
</select>
- <sql id="withHighImpactSeverityIssues">
- with high_impact_severity_issues as (
- select distinct kee
- from issues i
- inner join issues_impacts ii on ii.issue_key = i.kee
- where i.status <> 'CLOSED'
- and i.component_uuid = #{component.uuid,jdbcType=VARCHAR}
- and ii.severity = 'HIGH'
- )
- </sql>
-
<select id="selectIssueGroupsByComponent" resultType="org.sonar.db.issue.IssueGroupDto" parameterType="map" databaseId="oracle">
<include refid="selectIssueGroupsByComponentVendorSpecific"/>
</select>
</select>
<sql id="selectIssueGroupsByComponentVendorSpecific">
- <include refid="withHighImpactSeverityIssues"/>
select
i2.issue_type as ruleType,
i2.severity as severity,
- i2.hasHighImpactSeverity as hasHighImpactSeverity,
i2.resolution as resolution,
i2.status as status,
sum(i2.effort) as effort,
select
i.issue_type,
i.severity,
- case when exists(select 1 from high_impact_severity_issues hisi where hisi.kee = i.kee) then 1 else 0 end as hasHighImpactSeverity,
i.resolution,
i.status,
i.effort,
where i.status <> 'CLOSED'
and i.component_uuid = #{component.uuid,jdbcType=VARCHAR}
) i2
- group by i2.issue_type, i2.severity, i2.hasHighImpactSeverity, i2.resolution, i2.status, i2.inLeak
+ group by i2.issue_type, i2.severity, i2.resolution, i2.status, i2.inLeak
</sql>
<select id="selectIssueImpactGroupsByComponent" resultType="org.sonar.db.issue.IssueImpactGroupDto" parameterType="map">
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
- left join issues_impacts ii on i.kee = ii.issue_key
- where 1=1
- and i.status in ('OPEN', 'REOPENED', 'CONFIRMED')
- and i.issue_type != 4
+ 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 ii.software_quality, ii.severity
+ group by i.status, i.resolution, ii.software_quality, ii.severity
</select>
<select id="selectIssueKeysByComponentUuid" parameterType="string" resultType="string">
.assertThatValueIs(CoreMetrics.REOPENED_ISSUES, 7);
}
- @Test
- public void test_high_impact_accepted_issues() {
- withNoIssues()
- .assertThatValueIs(CoreMetrics.HIGH_IMPACT_ACCEPTED_ISSUES, 0);
-
- with(
- newGroup(RuleType.CODE_SMELL).setStatus(Issue.STATUS_RESOLVED).setResolution(Issue.RESOLUTION_FALSE_POSITIVE)
- .setHasHighImpactSeverity(true).setCount(3),
- newGroup(RuleType.CODE_SMELL).setStatus(Issue.STATUS_RESOLVED).setResolution(Issue.RESOLUTION_WONT_FIX)
- .setHasHighImpactSeverity(true).setCount(4),
- newGroup(RuleType.CODE_SMELL).setStatus(Issue.STATUS_RESOLVED).setResolution(Issue.RESOLUTION_WONT_FIX)
- .setHasHighImpactSeverity(false).setCount(5),
- newGroup(RuleType.BUG).setStatus(Issue.STATUS_RESOLVED).setResolution(Issue.RESOLUTION_FALSE_POSITIVE)
- .setHasHighImpactSeverity(true).setCount(30),
- newGroup(RuleType.BUG).setStatus(Issue.STATUS_RESOLVED).setResolution(Issue.RESOLUTION_WONT_FIX)
- .setHasHighImpactSeverity(true).setCount(40),
- newGroup(RuleType.BUG).setStatus(Issue.STATUS_RESOLVED).setResolution(Issue.RESOLUTION_WONT_FIX)
- .setHasHighImpactSeverity(false).setCount(50),
- // exclude security hotspot
- newGroup(RuleType.SECURITY_HOTSPOT).setResolution(Issue.RESOLUTION_WONT_FIX).setHasHighImpactSeverity(true).setCount(40))
- .assertThatValueIs(CoreMetrics.HIGH_IMPACT_ACCEPTED_ISSUES, 4 + 40);
- }
-
@Test
public void test_technical_debt() {
withNoIssues().assertThatValueIs(CoreMetrics.TECHNICAL_DEBT, 0);
.assertThatLeakValueIs(CoreMetrics.NEW_MAINTAINABILITY_RATING, Rating.A);
}
+ @Test
+ public void compute_shouldComputeHighImpactAcceptedIssues() {
+ withNoIssues()
+ .assertThatValueIs(CoreMetrics.HIGH_IMPACT_ACCEPTED_ISSUES, 0);
+
+ with(
+ newImpactGroup(RELIABILITY, HIGH, 3),
+ newImpactGroup(RELIABILITY, MEDIUM, 4),
+ newImpactGroup(RELIABILITY, LOW, 1),
+ newImpactGroup(SECURITY, HIGH, 3),
+ newImpactGroup(SECURITY, HIGH, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 4),
+ newImpactGroup(SECURITY, MEDIUM, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 5),
+ newImpactGroup(SECURITY, LOW, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 6),
+ newImpactGroup(SECURITY, HIGH, Issue.STATUS_RESOLVED, Issue.RESOLUTION_FALSE_POSITIVE, 7),
+ newImpactGroup(RELIABILITY, HIGH, Issue.STATUS_RESOLVED, Issue.RESOLUTION_WONT_FIX, 8))
+ .assertThatValueIs(CoreMetrics.HIGH_IMPACT_ACCEPTED_ISSUES, 4 + 8);
+ }
+
@Test
public void computeHierarchy_shouldComputeImpactMeasures() {
new HierarchyTester(CoreMetrics.RELIABILITY_ISSUES)
return dto;
}
- private static IssueImpactGroupDto newImpactGroup(SoftwareQuality softwareQuality, org.sonar.api.issue.impact.Severity severity, long count) {
+ private static IssueImpactGroupDto newImpactGroup(SoftwareQuality softwareQuality, org.sonar.api.issue.impact.Severity severity,
+ String status, @Nullable String resolution, long count) {
IssueImpactGroupDto dto = new IssueImpactGroupDto();
dto.setSoftwareQuality(softwareQuality);
dto.setSeverity(severity);
+ dto.setStatus(status);
+ dto.setResolution(resolution);
dto.setCount(count);
return dto;
}
+ private static IssueImpactGroupDto newImpactGroup(SoftwareQuality softwareQuality, org.sonar.api.issue.impact.Severity severity, long count) {
+ return newImpactGroup(softwareQuality, severity, Issue.STATUS_OPEN, null, count);
+ }
+
private static IssueGroupDto newResolvedGroup(RuleType ruleType) {
return newGroup(ruleType).setResolution(Issue.RESOLUTION_FALSE_POSITIVE).setStatus(Issue.STATUS_CLOSED);
}