import org.sonar.ce.task.projectanalysis.period.PeriodHolder;
import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED_KEY;
+import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS_KEY;
+import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS_KEY;
import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_REVIEW_RATING_KEY;
import static org.sonar.api.rules.RuleType.SECURITY_HOTSPOT;
import static org.sonar.ce.task.projectanalysis.component.ComponentVisitor.Order.POST_ORDER;
private final AnalysisMetadataHolder analysisMetadataHolder;
private final Metric newSecurityReviewRatingMetric;
private final Metric newSecurityHotspotsReviewedMetric;
+ private final Metric newSecurityHotspotsReviewedStatusMetric;
+ private final Metric newSecurityHotspotsToReviewStatusMetric;
public NewSecurityReviewMeasuresVisitor(ComponentIssuesRepository componentIssuesRepository, MeasureRepository measureRepository, PeriodHolder periodHolder,
AnalysisMetadataHolder analysisMetadataHolder, MetricRepository metricRepository) {
this.analysisMetadataHolder = analysisMetadataHolder;
this.newSecurityReviewRatingMetric = metricRepository.getByKey(NEW_SECURITY_REVIEW_RATING_KEY);
this.newSecurityHotspotsReviewedMetric = metricRepository.getByKey(NEW_SECURITY_HOTSPOTS_REVIEWED_KEY);
+ this.newSecurityHotspotsReviewedStatusMetric = metricRepository.getByKey(NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS_KEY);
+ this.newSecurityHotspotsToReviewStatusMetric = metricRepository.getByKey(NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS_KEY);
}
@Override
public void visitProject(Component project, Path<SecurityReviewCounter> path) {
computeMeasure(project, path);
+ if (!periodHolder.hasPeriod() && !analysisMetadataHolder.isPullRequest()) {
+ return;
+ }
+ // The following measures are only computed on projects level as they are required to compute the others measures on applications
+ measureRepository.add(project, newSecurityHotspotsReviewedStatusMetric, Measure.newMeasureBuilder().setVariation(path.current().getHotspotsReviewed()).createNoValue());
+ measureRepository.add(project, newSecurityHotspotsToReviewStatusMetric, Measure.newMeasureBuilder().setVariation(path.current().getHotspotsToReview()).createNoValue());
}
@Override
componentIssuesRepository.getIssues(component)
.stream()
.filter(issue -> issue.type().equals(SECURITY_HOTSPOT))
- .filter(issue -> analysisMetadataHolder.isPullRequest() || periodHolder.getPeriod().isOnPeriod(issue.creationDate()) )
+ .filter(issue -> analysisMetadataHolder.isPullRequest() || periodHolder.getPeriod().isOnPeriod(issue.creationDate()))
.forEach(issue -> path.current().processHotspot(issue));
- Double percent = computePercent(path.current().getHotspotsToReview(), path.current().getHotspotsReviewed());
+ double percent = computePercent(path.current().getHotspotsToReview(), path.current().getHotspotsReviewed());
measureRepository.add(component, newSecurityHotspotsReviewedMetric, Measure.newMeasureBuilder().setVariation(percent).createNoValue());
measureRepository.add(component, newSecurityReviewRatingMetric, Measure.newMeasureBuilder().setVariation(computeRating(percent).getIndex()).createNoValue());
import static org.sonar.api.issue.Issue.STATUS_TO_REVIEW;
final class SecurityReviewCounter {
- private long hotspotsReviewed;
- private long hotspotsToReview;
+ private int hotspotsReviewed;
+ private int hotspotsToReview;
SecurityReviewCounter() {
// prevents instantiation
hotspotsToReview += otherCounter.hotspotsToReview;
}
- public long getHotspotsReviewed() {
+ public int getHotspotsReviewed() {
return hotspotsReviewed;
}
- public long getHotspotsToReview() {
+ public int getHotspotsToReview() {
return hotspotsToReview;
}
}
import org.sonar.ce.task.projectanalysis.metric.MetricRepository;
import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_REVIEWED_KEY;
+import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_REVIEWED_STATUS_KEY;
+import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_TO_REVIEW_STATUS_KEY;
import static org.sonar.api.measures.CoreMetrics.SECURITY_REVIEW_RATING_KEY;
import static org.sonar.api.rules.RuleType.SECURITY_HOTSPOT;
import static org.sonar.ce.task.projectanalysis.component.ComponentVisitor.Order.POST_ORDER;
private final MeasureRepository measureRepository;
private final Metric securityReviewRatingMetric;
private final Metric securityHotspotsReviewedMetric;
+ private final Metric securityHotspotsReviewedStatusMetric;
+ private final Metric securityHotspotsToReviewStatusMetric;
public SecurityReviewMeasuresVisitor(ComponentIssuesRepository componentIssuesRepository, MeasureRepository measureRepository, MetricRepository metricRepository) {
super(FILE, POST_ORDER, SecurityReviewMeasuresVisitor.CounterFactory.INSTANCE);
this.measureRepository = measureRepository;
this.securityReviewRatingMetric = metricRepository.getByKey(SECURITY_REVIEW_RATING_KEY);
this.securityHotspotsReviewedMetric = metricRepository.getByKey(SECURITY_HOTSPOTS_REVIEWED_KEY);
+ this.securityHotspotsReviewedStatusMetric = metricRepository.getByKey(SECURITY_HOTSPOTS_REVIEWED_STATUS_KEY);
+ this.securityHotspotsToReviewStatusMetric = metricRepository.getByKey(SECURITY_HOTSPOTS_TO_REVIEW_STATUS_KEY);
}
@Override
public void visitProject(Component project, Path<SecurityReviewCounter> path) {
computeMeasure(project, path);
+ // The following measures are only computed on projects level as they are required to compute the others measures on applications
+ measureRepository.add(project, securityHotspotsReviewedStatusMetric, Measure.newMeasureBuilder().create(path.current().getHotspotsReviewed()));
+ measureRepository.add(project, securityHotspotsToReviewStatusMetric, Measure.newMeasureBuilder().create(path.current().getHotspotsToReview()));
}
@Override
.filter(issue -> issue.type().equals(SECURITY_HOTSPOT))
.forEach(issue -> path.current().processHotspot(issue));
- Double percent = computePercent(path.current().getHotspotsToReview(), path.current().getHotspotsReviewed());
+ double percent = computePercent(path.current().getHotspotsToReview(), path.current().getHotspotsReviewed());
measureRepository.add(component, securityHotspotsReviewedMetric, Measure.newMeasureBuilder().create(percent, securityHotspotsReviewedMetric.getDecimalScale()));
measureRepository.add(component, securityReviewRatingMetric, RatingMeasures.get(computeRating(percent)));
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.ce.task.projectanalysis.qualitymodel;
+
+import java.util.Optional;
+import org.sonar.ce.task.projectanalysis.component.Component;
+import org.sonar.ce.task.projectanalysis.component.CrawlerDepthLimit;
+import org.sonar.ce.task.projectanalysis.component.TypeAwareVisitorAdapter;
+import org.sonar.ce.task.projectanalysis.measure.Measure;
+import org.sonar.ce.task.projectanalysis.measure.MeasureRepository;
+import org.sonar.ce.task.projectanalysis.measure.RatingMeasures;
+import org.sonar.ce.task.projectanalysis.metric.Metric;
+import org.sonar.ce.task.projectanalysis.metric.MetricRepository;
+import org.sonar.server.measure.Rating;
+import org.sonar.server.security.SecurityReviewRating;
+
+import static org.sonar.api.measures.CoreMetrics.NCLOC_KEY;
+import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_KEY;
+import static org.sonar.api.measures.CoreMetrics.SECURITY_REVIEW_RATING_KEY;
+import static org.sonar.ce.task.projectanalysis.component.ViewAttributes.Type.APPLICATION;
+
+public class SecurityReviewRatingVisitorForPortfolios extends TypeAwareVisitorAdapter {
+
+ private final MeasureRepository measureRepository;
+ private final Metric nclocMetric;
+ private final Metric securityHostspotsMetric;
+ private final Metric securityReviewRatingMetric;
+
+ public SecurityReviewRatingVisitorForPortfolios(MeasureRepository measureRepository, MetricRepository metricRepository) {
+ super(CrawlerDepthLimit.SUBVIEW, Order.POST_ORDER);
+ this.measureRepository = measureRepository;
+ this.nclocMetric = metricRepository.getByKey(NCLOC_KEY);
+ this.securityHostspotsMetric = metricRepository.getByKey(SECURITY_HOTSPOTS_KEY);
+ this.securityReviewRatingMetric = metricRepository.getByKey(SECURITY_REVIEW_RATING_KEY);
+ }
+
+ @Override
+ public void visitView(Component view) {
+ if (view.getViewAttributes().getType().equals(APPLICATION)) {
+ return;
+ }
+ computeMeasure(view);
+ }
+
+ @Override
+ public void visitSubView(Component subView) {
+ computeMeasure(subView);
+ }
+
+ private void computeMeasure(Component component) {
+ Optional<Measure> nclocMeasure = measureRepository.getRawMeasure(component, nclocMetric);
+ Optional<Measure> securityHostspotsMeasure = measureRepository.getRawMeasure(component, securityHostspotsMetric);
+ if (!nclocMeasure.isPresent() || !securityHostspotsMeasure.isPresent()) {
+ return;
+ }
+ int ncloc = nclocMeasure.get().getIntValue();
+ int securityHotspots = securityHostspotsMeasure.get().getIntValue();
+ Rating rating = SecurityReviewRating.computeForPortfolios(ncloc, securityHotspots);
+ measureRepository.add(component, securityReviewRatingMetric, RatingMeasures.get(rating));
+ }
+
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.ce.task.projectanalysis.qualitymodel;
-
-import java.util.Optional;
-import org.sonar.ce.task.projectanalysis.component.Component;
-import org.sonar.ce.task.projectanalysis.component.CrawlerDepthLimit;
-import org.sonar.ce.task.projectanalysis.component.TypeAwareVisitorAdapter;
-import org.sonar.ce.task.projectanalysis.measure.Measure;
-import org.sonar.ce.task.projectanalysis.measure.MeasureRepository;
-import org.sonar.ce.task.projectanalysis.measure.RatingMeasures;
-import org.sonar.ce.task.projectanalysis.metric.Metric;
-import org.sonar.ce.task.projectanalysis.metric.MetricRepository;
-import org.sonar.server.measure.Rating;
-import org.sonar.server.security.SecurityReviewRating;
-
-import static org.sonar.api.measures.CoreMetrics.NCLOC_KEY;
-import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_KEY;
-import static org.sonar.api.measures.CoreMetrics.SECURITY_REVIEW_RATING_KEY;
-
-public class SecurityReviewRatingVisitorForPortfoliosAndApplications extends TypeAwareVisitorAdapter {
-
- private final MeasureRepository measureRepository;
- private final Metric nclocMetric;
- private final Metric securityHostspotsMetric;
- private final Metric securityReviewRatingMetric;
-
- public SecurityReviewRatingVisitorForPortfoliosAndApplications(MeasureRepository measureRepository, MetricRepository metricRepository) {
- super(CrawlerDepthLimit.SUBVIEW, Order.POST_ORDER);
- this.measureRepository = measureRepository;
- this.nclocMetric = metricRepository.getByKey(NCLOC_KEY);
- this.securityHostspotsMetric = metricRepository.getByKey(SECURITY_HOTSPOTS_KEY);
- this.securityReviewRatingMetric = metricRepository.getByKey(SECURITY_REVIEW_RATING_KEY);
- }
-
- @Override
- public void visitProject(Component project) {
- // Do nothing
- }
-
- @Override
- public void visitView(Component view) {
- computeMeasure(view);
- }
-
- @Override
- public void visitSubView(Component subView) {
- computeMeasure(subView);
- }
-
- private void computeMeasure(Component component) {
- Optional<Measure> nclocMeasure = measureRepository.getRawMeasure(component, nclocMetric);
- Optional<Measure> securityHostspotsMeasure = measureRepository.getRawMeasure(component, securityHostspotsMetric);
- if (!nclocMeasure.isPresent() || !securityHostspotsMeasure.isPresent()) {
- return;
- }
- int ncloc = nclocMeasure.get().getIntValue();
- int securityHotspots = securityHostspotsMeasure.get().getIntValue();
- Rating rating = SecurityReviewRating.computeForPortfolios(ncloc, securityHotspots);
- measureRepository.add(component, securityReviewRatingMetric, RatingMeasures.get(rating));
- }
-
-}
import java.util.Arrays;
import java.util.Date;
import javax.annotation.Nullable;
+import org.assertj.core.api.Assertions;
import org.assertj.core.data.Offset;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.ce.task.projectanalysis.component.VisitorsCrawler;
import org.sonar.ce.task.projectanalysis.issue.ComponentIssuesRepositoryRule;
import org.sonar.ce.task.projectanalysis.issue.FillComponentIssuesVisitorRule;
-import org.sonar.ce.task.projectanalysis.measure.MeasureAssert;
import org.sonar.ce.task.projectanalysis.measure.MeasureRepositoryRule;
import org.sonar.ce.task.projectanalysis.metric.MetricRepositoryRule;
import org.sonar.ce.task.projectanalysis.period.Period;
import static org.sonar.api.issue.Issue.STATUS_TO_REVIEW;
import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED;
import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED_KEY;
+import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS;
+import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS_KEY;
+import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS;
+import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS_KEY;
import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_REVIEW_RATING;
import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_REVIEW_RATING_KEY;
import static org.sonar.api.rule.Severity.MAJOR;
import static org.sonar.ce.task.projectanalysis.component.Component.Type.DIRECTORY;
import static org.sonar.ce.task.projectanalysis.component.Component.Type.FILE;
import static org.sonar.ce.task.projectanalysis.component.ReportComponent.builder;
+import static org.sonar.ce.task.projectanalysis.measure.MeasureAssert.assertThat;
import static org.sonar.server.measure.Rating.A;
import static org.sonar.server.measure.Rating.B;
import static org.sonar.server.measure.Rating.C;
@Rule
public MetricRepositoryRule metricRepository = new MetricRepositoryRule()
.add(NEW_SECURITY_REVIEW_RATING)
- .add(NEW_SECURITY_HOTSPOTS_REVIEWED);
+ .add(NEW_SECURITY_HOTSPOTS_REVIEWED)
+ .add(NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS)
+ .add(NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS);
@Rule
public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository);
@Rule
underTest.visit(ROOT_PROJECT);
- verifyMeasures(FILE_1_REF, A, 100.0);
- verifyMeasures(FILE_2_REF, A, 100.0);
- verifyMeasures(DIRECTORY_REF, A, 100.0);
- verifyMeasures(ROOT_DIR_REF, A, 100.0);
- verifyMeasures(PROJECT_REF, A, 100.0);
+ verifyRatingAndReviewedMeasures(FILE_1_REF, A, 100.0);
+ verifyRatingAndReviewedMeasures(FILE_2_REF, A, 100.0);
+ verifyRatingAndReviewedMeasures(DIRECTORY_REF, A, 100.0);
+ verifyRatingAndReviewedMeasures(ROOT_DIR_REF, A, 100.0);
+ verifyRatingAndReviewedMeasures(PROJECT_REF, A, 100.0);
}
@Test
underTest.visit(ROOT_PROJECT);
- verifyMeasures(FILE_1_REF, A, 100.0);
- verifyMeasures(FILE_2_REF, A, 80.0);
- verifyMeasures(DIRECTORY_REF, A, 87.5);
- verifyMeasures(ROOT_DIR_REF, A, 87.5);
- verifyMeasures(PROJECT_REF, A, 87.5);
+ verifyRatingAndReviewedMeasures(FILE_1_REF, A, 100.0);
+ verifyRatingAndReviewedMeasures(FILE_2_REF, A, 80.0);
+ verifyRatingAndReviewedMeasures(DIRECTORY_REF, A, 87.5);
+ verifyRatingAndReviewedMeasures(ROOT_DIR_REF, A, 87.5);
+ verifyRatingAndReviewedMeasures(PROJECT_REF, A, 87.5);
}
@Test
underTest.visit(ROOT_PROJECT);
- verifyMeasures(FILE_1_REF, A, 100.0);
- verifyMeasures(FILE_2_REF, B, 71.42);
- verifyMeasures(DIRECTORY_REF, B, 75.0);
- verifyMeasures(ROOT_DIR_REF, B, 75.0);
- verifyMeasures(PROJECT_REF, B, 75.0);
+ verifyRatingAndReviewedMeasures(FILE_1_REF, A, 100.0);
+ verifyRatingAndReviewedMeasures(FILE_2_REF, B, 71.42);
+ verifyRatingAndReviewedMeasures(DIRECTORY_REF, B, 75.0);
+ verifyRatingAndReviewedMeasures(ROOT_DIR_REF, B, 75.0);
+ verifyRatingAndReviewedMeasures(PROJECT_REF, B, 75.0);
}
@Test
underTest.visit(ROOT_PROJECT);
- verifyMeasures(FILE_1_REF, C, 50.0);
- verifyMeasures(FILE_2_REF, C, 60.0);
- verifyMeasures(DIRECTORY_REF, C, 57.14);
- verifyMeasures(ROOT_DIR_REF, C, 57.14);
- verifyMeasures(PROJECT_REF, C, 57.14);
+ verifyRatingAndReviewedMeasures(FILE_1_REF, C, 50.0);
+ verifyRatingAndReviewedMeasures(FILE_2_REF, C, 60.0);
+ verifyRatingAndReviewedMeasures(DIRECTORY_REF, C, 57.14);
+ verifyRatingAndReviewedMeasures(ROOT_DIR_REF, C, 57.14);
+ verifyRatingAndReviewedMeasures(PROJECT_REF, C, 57.14);
}
@Test
underTest.visit(ROOT_PROJECT);
- verifyMeasures(FILE_1_REF, D, 33.33);
- verifyMeasures(FILE_2_REF, D, 40.0);
- verifyMeasures(DIRECTORY_REF, D, 37.5);
- verifyMeasures(ROOT_DIR_REF, D, 37.5);
- verifyMeasures(PROJECT_REF, D, 37.5);
+ verifyRatingAndReviewedMeasures(FILE_1_REF, D, 33.33);
+ verifyRatingAndReviewedMeasures(FILE_2_REF, D, 40.0);
+ verifyRatingAndReviewedMeasures(DIRECTORY_REF, D, 37.5);
+ verifyRatingAndReviewedMeasures(ROOT_DIR_REF, D, 37.5);
+ verifyRatingAndReviewedMeasures(PROJECT_REF, D, 37.5);
}
@Test
underTest.visit(ROOT_PROJECT);
- verifyMeasures(FILE_1_REF, D, 33.33);
- verifyMeasures(FILE_2_REF, E, 0.0);
- verifyMeasures(DIRECTORY_REF, E, 16.66);
- verifyMeasures(ROOT_DIR_REF, E, 16.66);
- verifyMeasures(PROJECT_REF, E, 16.66);
+ verifyRatingAndReviewedMeasures(FILE_1_REF, D, 33.33);
+ verifyRatingAndReviewedMeasures(FILE_2_REF, E, 0.0);
+ verifyRatingAndReviewedMeasures(DIRECTORY_REF, E, 16.66);
+ verifyRatingAndReviewedMeasures(ROOT_DIR_REF, E, 16.66);
+ verifyRatingAndReviewedMeasures(PROJECT_REF, E, 16.66);
}
@Test
underTest.visit(ROOT_PROJECT);
- verifyMeasures(PROJECT_REF, A, 100.0);
+ verifyRatingAndReviewedMeasures(PROJECT_REF, A, 100.0);
}
@Test
underTest.visit(ROOT_PROJECT);
- verifyMeasures(FILE_1_REF, C, 50.0);
- verifyMeasures(FILE_2_REF, C, 57.14);
- verifyMeasures(DIRECTORY_REF, C, 55.55);
- verifyMeasures(ROOT_DIR_REF, C, 55.55);
- verifyMeasures(PROJECT_REF, C, 55.55);
+ verifyRatingAndReviewedMeasures(FILE_1_REF, C, 50.0);
+ verifyRatingAndReviewedMeasures(FILE_2_REF, C, 57.14);
+ verifyRatingAndReviewedMeasures(DIRECTORY_REF, C, 55.55);
+ verifyRatingAndReviewedMeasures(ROOT_DIR_REF, C, 55.55);
+ verifyRatingAndReviewedMeasures(PROJECT_REF, C, 55.55);
+ }
+
+ @Test
+ public void compute_status_related_measures() {
+ treeRootHolder.setRoot(ROOT_PROJECT);
+ fillComponentIssuesVisitorRule.setIssues(FILE_1_REF,
+ newHotspot(STATUS_TO_REVIEW, null).setCreationDate(AFTER_LEAK_PERIOD_DATE),
+ newHotspot(STATUS_REVIEWED, RESOLUTION_FIXED).setCreationDate(AFTER_LEAK_PERIOD_DATE),
+ // Should not be taken into account
+ newIssue());
+ fillComponentIssuesVisitorRule.setIssues(FILE_2_REF,
+ newHotspot(STATUS_TO_REVIEW, null).setCreationDate(AFTER_LEAK_PERIOD_DATE),
+ newHotspot(STATUS_TO_REVIEW, null).setCreationDate(AFTER_LEAK_PERIOD_DATE),
+ newHotspot(STATUS_REVIEWED, RESOLUTION_FIXED).setCreationDate(AFTER_LEAK_PERIOD_DATE),
+ newHotspot(STATUS_REVIEWED, RESOLUTION_FIXED).setCreationDate(AFTER_LEAK_PERIOD_DATE),
+ newHotspot(STATUS_REVIEWED, RESOLUTION_FIXED).setCreationDate(AFTER_LEAK_PERIOD_DATE),
+ newIssue());
+
+ underTest.visit(ROOT_PROJECT);
+
+ verifyHotspotStatusMeasures(FILE_1_REF, null, null);
+ verifyHotspotStatusMeasures(FILE_2_REF, null, null);
+ verifyHotspotStatusMeasures(DIRECTORY_REF, null, null);
+ verifyHotspotStatusMeasures(ROOT_DIR_REF, null, null);
+ verifyHotspotStatusMeasures(PROJECT_REF, 4, 3);
+ }
+
+ @Test
+ public void compute_0_status_related_measures_when_no_hotspot() {
+ treeRootHolder.setRoot(ROOT_PROJECT);
+
+ underTest.visit(ROOT_PROJECT);
+
+ verifyHotspotStatusMeasures(PROJECT_REF, 0, 0);
}
@Test
assertThat(measureRepository.getAddedRawMeasures(PROJECT_REF).values()).isEmpty();
}
- private void verifyMeasures(int componentRef, Rating expectedReviewRating, double expectedHotspotsReviewed) {
- MeasureAssert.assertThat(measureRepository.getAddedRawMeasure(componentRef, NEW_SECURITY_REVIEW_RATING_KEY)).hasVariation(expectedReviewRating.getIndex());
- MeasureAssert.assertThat(measureRepository.getAddedRawMeasure(componentRef, NEW_SECURITY_HOTSPOTS_REVIEWED_KEY)).hasVariation(expectedHotspotsReviewed,
+ private void verifyRatingAndReviewedMeasures(int componentRef, Rating expectedReviewRating, double expectedHotspotsReviewed) {
+ assertThat(measureRepository.getAddedRawMeasure(componentRef, NEW_SECURITY_REVIEW_RATING_KEY)).hasVariation(expectedReviewRating.getIndex());
+ assertThat(measureRepository.getAddedRawMeasure(componentRef, NEW_SECURITY_HOTSPOTS_REVIEWED_KEY)).hasVariation(expectedHotspotsReviewed,
VARIATION_COMPARISON_OFFSET);
}
+ private void verifyHotspotStatusMeasures(int componentRef, @Nullable Integer hotspotsReviewed, @Nullable Integer hotspotsToReview) {
+ if (hotspotsReviewed == null) {
+ Assertions.assertThat(measureRepository.getAddedRawMeasure(componentRef, NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS_KEY)).isEmpty();
+ } else {
+ assertThat(measureRepository.getAddedRawMeasure(componentRef, NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS_KEY)).hasVariation(hotspotsReviewed);
+ }
+ if (hotspotsReviewed == null) {
+ Assertions.assertThat(measureRepository.getAddedRawMeasure(componentRef, NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS_KEY)).isEmpty();
+ } else {
+ assertThat(measureRepository.getAddedRawMeasure(componentRef, NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS_KEY)).hasVariation(hotspotsToReview);
+ }
+ }
+
private static DefaultIssue newHotspot(String status, @Nullable String resolution) {
return new DefaultIssue()
.setKey(Uuids.create())
import static org.sonar.api.issue.Issue.RESOLUTION_SAFE;
import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_REVIEWED;
import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_REVIEWED_KEY;
+import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_REVIEWED_STATUS;
+import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_REVIEWED_STATUS_KEY;
+import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_TO_REVIEW_STATUS;
+import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_TO_REVIEW_STATUS_KEY;
import static org.sonar.api.measures.CoreMetrics.SECURITY_REVIEW_RATING;
import static org.sonar.api.measures.CoreMetrics.SECURITY_REVIEW_RATING_KEY;
import static org.sonar.api.rule.Severity.MAJOR;
@Rule
public MetricRepositoryRule metricRepository = new MetricRepositoryRule()
.add(SECURITY_REVIEW_RATING)
- .add(SECURITY_HOTSPOTS_REVIEWED);
+ .add(SECURITY_HOTSPOTS_REVIEWED)
+ .add(SECURITY_HOTSPOTS_REVIEWED_STATUS)
+ .add(SECURITY_HOTSPOTS_TO_REVIEW_STATUS);
@Rule
public ComponentIssuesRepositoryRule componentIssuesRepositoryRule = new ComponentIssuesRepositoryRule(treeRootHolder);
@Rule
new SecurityReviewMeasuresVisitor(componentIssuesRepositoryRule, measureRepository, metricRepository)));
@Test
- public void compute_measures_when_100_percent_hotspots_reviewed() {
+ public void compute_rating_and_reviewed_measures_when_100_percent_hotspots_reviewed() {
treeRootHolder.setRoot(ROOT_PROJECT);
fillComponentIssuesVisitorRule.setIssues(FILE_1_REF,
newHotspot(STATUS_REVIEWED, RESOLUTION_FIXED),
underTest.visit(ROOT_PROJECT);
- verifyMeasures(FILE_1_REF, A, 100.0);
- verifyMeasures(FILE_2_REF, A, 100.0);
- verifyMeasures(DIRECTORY_REF, A, 100.0);
- verifyMeasures(ROOT_DIR_REF, A, 100.0);
- verifyMeasures(PROJECT_REF, A, 100.0);
+ verifyRatingAndReviewedMeasures(FILE_1_REF, A, 100.0);
+ verifyRatingAndReviewedMeasures(FILE_2_REF, A, 100.0);
+ verifyRatingAndReviewedMeasures(DIRECTORY_REF, A, 100.0);
+ verifyRatingAndReviewedMeasures(ROOT_DIR_REF, A, 100.0);
+ verifyRatingAndReviewedMeasures(PROJECT_REF, A, 100.0);
}
@Test
- public void compute_measures_when_more_than_80_percent_hotspots_reviewed() {
+ public void compute_rating_and_reviewed__measures_when_more_than_80_percent_hotspots_reviewed() {
treeRootHolder.setRoot(ROOT_PROJECT);
fillComponentIssuesVisitorRule.setIssues(FILE_1_REF,
newHotspot(STATUS_REVIEWED, RESOLUTION_FIXED),
underTest.visit(ROOT_PROJECT);
- verifyMeasures(FILE_1_REF, A, 100.0);
- verifyMeasures(FILE_2_REF, A, 80.0);
- verifyMeasures(DIRECTORY_REF, A, 87.5);
- verifyMeasures(ROOT_DIR_REF, A, 87.5);
- verifyMeasures(PROJECT_REF, A, 87.5);
+ verifyRatingAndReviewedMeasures(FILE_1_REF, A, 100.0);
+ verifyRatingAndReviewedMeasures(FILE_2_REF, A, 80.0);
+ verifyRatingAndReviewedMeasures(DIRECTORY_REF, A, 87.5);
+ verifyRatingAndReviewedMeasures(ROOT_DIR_REF, A, 87.5);
+ verifyRatingAndReviewedMeasures(PROJECT_REF, A, 87.5);
}
@Test
- public void compute_measures_when_more_than_70_percent_hotspots_reviewed() {
+ public void compute_rating_and_reviewed__measures_when_more_than_70_percent_hotspots_reviewed() {
treeRootHolder.setRoot(ROOT_PROJECT);
fillComponentIssuesVisitorRule.setIssues(FILE_1_REF,
newHotspot(STATUS_REVIEWED, RESOLUTION_FIXED),
underTest.visit(ROOT_PROJECT);
- verifyMeasures(FILE_1_REF, A, 100.0);
- verifyMeasures(FILE_2_REF, B, 71.4);
- verifyMeasures(DIRECTORY_REF, B, 75.0);
- verifyMeasures(ROOT_DIR_REF, B, 75.0);
- verifyMeasures(PROJECT_REF, B, 75.0);
+ verifyRatingAndReviewedMeasures(FILE_1_REF, A, 100.0);
+ verifyRatingAndReviewedMeasures(FILE_2_REF, B, 71.4);
+ verifyRatingAndReviewedMeasures(DIRECTORY_REF, B, 75.0);
+ verifyRatingAndReviewedMeasures(ROOT_DIR_REF, B, 75.0);
+ verifyRatingAndReviewedMeasures(PROJECT_REF, B, 75.0);
}
@Test
- public void compute_measures_when_more_than_50_percent_hotspots_reviewed() {
+ public void compute_rating_and_reviewed__measures_when_more_than_50_percent_hotspots_reviewed() {
treeRootHolder.setRoot(ROOT_PROJECT);
fillComponentIssuesVisitorRule.setIssues(FILE_1_REF,
newHotspot(STATUS_TO_REVIEW, null),
underTest.visit(ROOT_PROJECT);
- verifyMeasures(FILE_1_REF, C, 50.0);
- verifyMeasures(FILE_2_REF, C, 60.0);
- verifyMeasures(DIRECTORY_REF, C, 57.1);
- verifyMeasures(ROOT_DIR_REF, C, 57.1);
- verifyMeasures(PROJECT_REF, C, 57.1);
+ verifyRatingAndReviewedMeasures(FILE_1_REF, C, 50.0);
+ verifyRatingAndReviewedMeasures(FILE_2_REF, C, 60.0);
+ verifyRatingAndReviewedMeasures(DIRECTORY_REF, C, 57.1);
+ verifyRatingAndReviewedMeasures(ROOT_DIR_REF, C, 57.1);
+ verifyRatingAndReviewedMeasures(PROJECT_REF, C, 57.1);
}
@Test
- public void compute_measures_when_more_30_than_percent_hotspots_reviewed() {
+ public void compute_rating_and_reviewed__measures_when_more_30_than_percent_hotspots_reviewed() {
treeRootHolder.setRoot(ROOT_PROJECT);
fillComponentIssuesVisitorRule.setIssues(FILE_1_REF,
newHotspot(STATUS_TO_REVIEW, null),
underTest.visit(ROOT_PROJECT);
- verifyMeasures(FILE_1_REF, D, 33.3);
- verifyMeasures(FILE_2_REF, D, 40.0);
- verifyMeasures(DIRECTORY_REF, D, 37.5);
- verifyMeasures(ROOT_DIR_REF, D, 37.5);
- verifyMeasures(PROJECT_REF, D, 37.5);
+ verifyRatingAndReviewedMeasures(FILE_1_REF, D, 33.3);
+ verifyRatingAndReviewedMeasures(FILE_2_REF, D, 40.0);
+ verifyRatingAndReviewedMeasures(DIRECTORY_REF, D, 37.5);
+ verifyRatingAndReviewedMeasures(ROOT_DIR_REF, D, 37.5);
+ verifyRatingAndReviewedMeasures(PROJECT_REF, D, 37.5);
}
@Test
- public void compute_measures_when_less_than_30_percent_hotspots_reviewed() {
+ public void compute_rating_and_reviewed__measures_when_less_than_30_percent_hotspots_reviewed() {
treeRootHolder.setRoot(ROOT_PROJECT);
fillComponentIssuesVisitorRule.setIssues(FILE_1_REF,
newHotspot(STATUS_TO_REVIEW, null),
underTest.visit(ROOT_PROJECT);
- verifyMeasures(FILE_1_REF, D, 33.3);
- verifyMeasures(FILE_2_REF, E, 0.0);
- verifyMeasures(DIRECTORY_REF, E, 16.7);
- verifyMeasures(ROOT_DIR_REF, E, 16.7);
- verifyMeasures(PROJECT_REF, E, 16.7);
+ verifyRatingAndReviewedMeasures(FILE_1_REF, D, 33.3);
+ verifyRatingAndReviewedMeasures(FILE_2_REF, E, 0.0);
+ verifyRatingAndReviewedMeasures(DIRECTORY_REF, E, 16.7);
+ verifyRatingAndReviewedMeasures(ROOT_DIR_REF, E, 16.7);
+ verifyRatingAndReviewedMeasures(PROJECT_REF, E, 16.7);
}
@Test
underTest.visit(ROOT_PROJECT);
- verifyMeasures(PROJECT_REF, A, 100.0);
+ verifyRatingAndReviewedMeasures(PROJECT_REF, A, 100.0);
}
- private void verifyMeasures(int componentRef, Rating expectedReviewRating, double expectedHotspotsReviewed) {
+ @Test
+ public void compute_status_related_measures() {
+ treeRootHolder.setRoot(ROOT_PROJECT);
+ fillComponentIssuesVisitorRule.setIssues(FILE_1_REF,
+ newHotspot(STATUS_TO_REVIEW, null),
+ newHotspot(STATUS_REVIEWED, RESOLUTION_FIXED),
+ // Should not be taken into account
+ newIssue());
+ fillComponentIssuesVisitorRule.setIssues(FILE_2_REF,
+ newHotspot(STATUS_TO_REVIEW, null),
+ newHotspot(STATUS_TO_REVIEW, null),
+ newHotspot(STATUS_REVIEWED, RESOLUTION_FIXED),
+ newHotspot(STATUS_REVIEWED, RESOLUTION_FIXED),
+ newHotspot(STATUS_REVIEWED, RESOLUTION_FIXED),
+ newIssue());
+
+ underTest.visit(ROOT_PROJECT);
+
+ verifyHotspotStatusMeasures(FILE_1_REF, null, null);
+ verifyHotspotStatusMeasures(FILE_2_REF, null, null);
+ verifyHotspotStatusMeasures(DIRECTORY_REF, null, null);
+ verifyHotspotStatusMeasures(ROOT_DIR_REF, null, null);
+ verifyHotspotStatusMeasures(PROJECT_REF, 4, 3);
+ }
+
+ @Test
+ public void compute_0_status_related_measures_when_no_hotspot() {
+ treeRootHolder.setRoot(ROOT_PROJECT);
+
+ underTest.visit(ROOT_PROJECT);
+
+ verifyHotspotStatusMeasures(PROJECT_REF, 0, 0);
+ }
+
+ private void verifyRatingAndReviewedMeasures(int componentRef, Rating expectedReviewRating, double expectedHotspotsReviewed) {
verifySecurityReviewRating(componentRef, expectedReviewRating);
verifySecurityHotspotsReviewed(componentRef, expectedHotspotsReviewed);
}
assertThat(measureRepository.getAddedRawMeasure(componentRef, SECURITY_HOTSPOTS_REVIEWED_KEY).get().getDoubleValue()).isEqualTo(percent);
}
+ private void verifyHotspotStatusMeasures(int componentRef, @Nullable Integer hotspotsReviewed, @Nullable Integer hotspotsToReview) {
+ if (hotspotsReviewed == null){
+ assertThat(measureRepository.getAddedRawMeasure(componentRef, SECURITY_HOTSPOTS_REVIEWED_STATUS_KEY)).isEmpty();
+ } else {
+ assertThat(measureRepository.getAddedRawMeasure(componentRef, SECURITY_HOTSPOTS_REVIEWED_STATUS_KEY).get().getIntValue()).isEqualTo(hotspotsReviewed);
+ }
+ if (hotspotsReviewed == null){
+ assertThat(measureRepository.getAddedRawMeasure(componentRef, SECURITY_HOTSPOTS_TO_REVIEW_STATUS_KEY)).isEmpty();
+ } else {
+ assertThat(measureRepository.getAddedRawMeasure(componentRef, SECURITY_HOTSPOTS_TO_REVIEW_STATUS_KEY).get().getIntValue()).isEqualTo(hotspotsToReview);
+ }
+ }
+
private static DefaultIssue newHotspot(String status, @Nullable String resolution) {
return new DefaultIssue()
.setKey(Uuids.create())
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.ce.task.projectanalysis.qualitymodel;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.sonar.ce.task.projectanalysis.component.Component;
-import org.sonar.ce.task.projectanalysis.component.TreeRootHolderRule;
-import org.sonar.ce.task.projectanalysis.component.ViewAttributes;
-import org.sonar.ce.task.projectanalysis.component.ViewsComponent;
-import org.sonar.ce.task.projectanalysis.component.VisitorsCrawler;
-import org.sonar.ce.task.projectanalysis.measure.Measure;
-import org.sonar.ce.task.projectanalysis.measure.MeasureRepositoryRule;
-import org.sonar.ce.task.projectanalysis.metric.MetricRepositoryRule;
-
-import static java.util.Collections.singletonList;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.api.measures.CoreMetrics.NCLOC;
-import static org.sonar.api.measures.CoreMetrics.NCLOC_KEY;
-import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS;
-import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_KEY;
-import static org.sonar.api.measures.CoreMetrics.SECURITY_REVIEW_RATING;
-import static org.sonar.api.measures.CoreMetrics.SECURITY_REVIEW_RATING_KEY;
-import static org.sonar.ce.task.projectanalysis.measure.Measure.newMeasureBuilder;
-import static org.sonar.server.measure.Rating.B;
-import static org.sonar.server.measure.Rating.C;
-
-public class SecurityReviewRatingVisitorForPortfoliosAndApplicationsTest {
-
- private static final int PORTFOLIO_REF = 10;
- private static final int SUB_PORTFOLIO_1_REF = 11;
- private static final int SUB_PORTFOLIO_2_REF = 12;
- private static final Component PORTFOLIO = ViewsComponent.builder(Component.Type.VIEW, Integer.toString(PORTFOLIO_REF))
- .addChildren(
- ViewsComponent.builder(Component.Type.SUBVIEW, Integer.toString(SUB_PORTFOLIO_1_REF)).build(),
- ViewsComponent.builder(Component.Type.SUBVIEW, Integer.toString(SUB_PORTFOLIO_2_REF)).build())
- .build();
-
- private static final int APPLICATION_REF = 20;
- private static final Component APPLICATION = ViewsComponent.builder(Component.Type.VIEW, Integer.toString(APPLICATION_REF))
- .setViewAttributes(new ViewAttributes(ViewAttributes.Type.APPLICATION))
- .build();
-
- @Rule
- public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
-
- @Rule
- public MetricRepositoryRule metricRepository = new MetricRepositoryRule()
- .add(NCLOC)
- .add(SECURITY_HOTSPOTS)
- .add(SECURITY_REVIEW_RATING);
-
- @Rule
- public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository);
-
- private VisitorsCrawler underTest = new VisitorsCrawler(singletonList(new SecurityReviewRatingVisitorForPortfoliosAndApplications(measureRepository, metricRepository)));
-
- @Test
- public void compute_security_review_rating_on_portfolio() {
- treeRootHolder.setRoot(PORTFOLIO);
- measureRepository.addRawMeasure(PORTFOLIO_REF, NCLOC_KEY, newMeasureBuilder().create(2000));
- measureRepository.addRawMeasure(PORTFOLIO_REF, SECURITY_HOTSPOTS_KEY, newMeasureBuilder().create(20));
- measureRepository.addRawMeasure(SUB_PORTFOLIO_1_REF, NCLOC_KEY, newMeasureBuilder().create(1000));
- measureRepository.addRawMeasure(SUB_PORTFOLIO_1_REF, SECURITY_HOTSPOTS_KEY, newMeasureBuilder().create(5));
- measureRepository.addRawMeasure(SUB_PORTFOLIO_2_REF, NCLOC_KEY, newMeasureBuilder().create(1000));
- measureRepository.addRawMeasure(SUB_PORTFOLIO_2_REF, SECURITY_HOTSPOTS_KEY, newMeasureBuilder().create(15));
-
- underTest.visit(PORTFOLIO);
-
- assertThat(measureRepository.getAddedRawMeasure(SUB_PORTFOLIO_1_REF, SECURITY_REVIEW_RATING_KEY).get().getIntValue()).isEqualTo(B.getIndex());
- assertThat(measureRepository.getAddedRawMeasure(SUB_PORTFOLIO_2_REF, SECURITY_REVIEW_RATING_KEY).get().getIntValue()).isEqualTo(C.getIndex());
- assertThat(measureRepository.getAddedRawMeasure(PORTFOLIO_REF, SECURITY_REVIEW_RATING_KEY).get().getIntValue()).isEqualTo(B.getIndex());
- }
-
- @Test
- public void compute_security_review_rating_on_application() {
- treeRootHolder.setRoot(APPLICATION);
- measureRepository.addRawMeasure(APPLICATION_REF, NCLOC_KEY, newMeasureBuilder().create(1000));
- measureRepository.addRawMeasure(APPLICATION_REF, SECURITY_HOTSPOTS_KEY, newMeasureBuilder().create(12));
-
- underTest.visit(APPLICATION);
-
- Measure measure = measureRepository.getAddedRawMeasure(APPLICATION_REF, SECURITY_REVIEW_RATING_KEY).get();
- assertThat(measure.getIntValue()).isEqualTo(C.getIndex());
- assertThat(measure.getData()).isEqualTo(C.name());
- }
-
- @Test
- public void compute_nothing_when_no_ncloc() {
- treeRootHolder.setRoot(PORTFOLIO);
- measureRepository.addRawMeasure(PORTFOLIO_REF, SECURITY_HOTSPOTS_KEY, newMeasureBuilder().create(2));
-
- underTest.visit(PORTFOLIO);
-
- assertThat(measureRepository.getAddedRawMeasure(PORTFOLIO_REF, SECURITY_REVIEW_RATING_KEY)).isEmpty();
- }
-
- @Test
- public void compute_nothing_when_no_security_hotspot() {
- treeRootHolder.setRoot(PORTFOLIO);
- measureRepository.addRawMeasure(PORTFOLIO_REF, NCLOC_KEY, newMeasureBuilder().create(1000));
-
- underTest.visit(PORTFOLIO);
-
- assertThat(measureRepository.getAddedRawMeasure(PORTFOLIO_REF, SECURITY_REVIEW_RATING_KEY)).isEmpty();
- }
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.ce.task.projectanalysis.qualitymodel;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.ce.task.projectanalysis.component.Component;
+import org.sonar.ce.task.projectanalysis.component.TreeRootHolderRule;
+import org.sonar.ce.task.projectanalysis.component.ViewAttributes;
+import org.sonar.ce.task.projectanalysis.component.ViewsComponent;
+import org.sonar.ce.task.projectanalysis.component.VisitorsCrawler;
+import org.sonar.ce.task.projectanalysis.measure.MeasureRepositoryRule;
+import org.sonar.ce.task.projectanalysis.metric.MetricRepositoryRule;
+
+import static java.util.Collections.singletonList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.api.measures.CoreMetrics.NCLOC;
+import static org.sonar.api.measures.CoreMetrics.NCLOC_KEY;
+import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS;
+import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_KEY;
+import static org.sonar.api.measures.CoreMetrics.SECURITY_REVIEW_RATING;
+import static org.sonar.api.measures.CoreMetrics.SECURITY_REVIEW_RATING_KEY;
+import static org.sonar.ce.task.projectanalysis.measure.Measure.newMeasureBuilder;
+import static org.sonar.server.measure.Rating.B;
+import static org.sonar.server.measure.Rating.C;
+
+public class SecurityReviewRatingVisitorForPortfoliosTest {
+
+ private static final int PORTFOLIO_REF = 10;
+ private static final int SUB_PORTFOLIO_1_REF = 11;
+ private static final int SUB_PORTFOLIO_2_REF = 12;
+ private static final Component PORTFOLIO = ViewsComponent.builder(Component.Type.VIEW, Integer.toString(PORTFOLIO_REF))
+ .setViewAttributes(new ViewAttributes(ViewAttributes.Type.PORTFOLIO))
+ .addChildren(
+ ViewsComponent.builder(Component.Type.SUBVIEW, Integer.toString(SUB_PORTFOLIO_1_REF)).build(),
+ ViewsComponent.builder(Component.Type.SUBVIEW, Integer.toString(SUB_PORTFOLIO_2_REF)).build())
+ .build();
+
+ @Rule
+ public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
+
+ @Rule
+ public MetricRepositoryRule metricRepository = new MetricRepositoryRule()
+ .add(NCLOC)
+ .add(SECURITY_HOTSPOTS)
+ .add(SECURITY_REVIEW_RATING);
+
+ @Rule
+ public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository);
+
+ private VisitorsCrawler underTest = new VisitorsCrawler(singletonList(new SecurityReviewRatingVisitorForPortfolios(measureRepository, metricRepository)));
+
+ @Test
+ public void compute_security_review_rating_on_portfolio() {
+ treeRootHolder.setRoot(PORTFOLIO);
+ measureRepository.addRawMeasure(PORTFOLIO_REF, NCLOC_KEY, newMeasureBuilder().create(2000));
+ measureRepository.addRawMeasure(PORTFOLIO_REF, SECURITY_HOTSPOTS_KEY, newMeasureBuilder().create(20));
+ measureRepository.addRawMeasure(SUB_PORTFOLIO_1_REF, NCLOC_KEY, newMeasureBuilder().create(1000));
+ measureRepository.addRawMeasure(SUB_PORTFOLIO_1_REF, SECURITY_HOTSPOTS_KEY, newMeasureBuilder().create(5));
+ measureRepository.addRawMeasure(SUB_PORTFOLIO_2_REF, NCLOC_KEY, newMeasureBuilder().create(1000));
+ measureRepository.addRawMeasure(SUB_PORTFOLIO_2_REF, SECURITY_HOTSPOTS_KEY, newMeasureBuilder().create(15));
+
+ underTest.visit(PORTFOLIO);
+
+ assertThat(measureRepository.getAddedRawMeasure(SUB_PORTFOLIO_1_REF, SECURITY_REVIEW_RATING_KEY).get().getIntValue()).isEqualTo(B.getIndex());
+ assertThat(measureRepository.getAddedRawMeasure(SUB_PORTFOLIO_2_REF, SECURITY_REVIEW_RATING_KEY).get().getIntValue()).isEqualTo(C.getIndex());
+ assertThat(measureRepository.getAddedRawMeasure(PORTFOLIO_REF, SECURITY_REVIEW_RATING_KEY).get().getIntValue()).isEqualTo(B.getIndex());
+ }
+
+ @Test
+ public void compute_nothing_when_no_ncloc() {
+ treeRootHolder.setRoot(PORTFOLIO);
+ measureRepository.addRawMeasure(PORTFOLIO_REF, SECURITY_HOTSPOTS_KEY, newMeasureBuilder().create(2));
+
+ underTest.visit(PORTFOLIO);
+
+ assertThat(measureRepository.getAddedRawMeasure(PORTFOLIO_REF, SECURITY_REVIEW_RATING_KEY)).isEmpty();
+ }
+
+ @Test
+ public void compute_nothing_when_no_security_hotspot() {
+ treeRootHolder.setRoot(PORTFOLIO);
+ measureRepository.addRawMeasure(PORTFOLIO_REF, NCLOC_KEY, newMeasureBuilder().create(1000));
+
+ underTest.visit(PORTFOLIO);
+
+ assertThat(measureRepository.getAddedRawMeasure(PORTFOLIO_REF, SECURITY_REVIEW_RATING_KEY)).isEmpty();
+ }
+}
}
}
- public static Double computePercent(long hotspotsToReview, long hotspotsReviewed) {
+ public static double computePercent(long hotspotsToReview, long hotspotsReviewed) {
long total = hotspotsToReview + hotspotsReviewed;
if (total == 0) {
return 100.0;
(context, issues) -> context
.setValue(computePercent(issues.countHotspotsByStatus(Issue.STATUS_TO_REVIEW, false), issues.countHotspotsByStatus(Issue.STATUS_REVIEWED, false)))),
+ new IssueMetricFormula(CoreMetrics.SECURITY_HOTSPOTS_REVIEWED_STATUS, false,
+ (context, issues) -> context.setValue(issues.countHotspotsByStatus(Issue.STATUS_REVIEWED, false))),
+
+ new IssueMetricFormula(CoreMetrics.SECURITY_HOTSPOTS_TO_REVIEW_STATUS, false,
+ (context, issues) -> context.setValue(issues.countHotspotsByStatus(Issue.STATUS_TO_REVIEW, false))),
+
new IssueMetricFormula(CoreMetrics.NEW_CODE_SMELLS, true,
(context, issues) -> context.setLeakValue(issues.countUnresolvedByType(RuleType.CODE_SMELL, true))),
context.setLeakValue(percent);
}),
+ new IssueMetricFormula(CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS, true,
+ (context, issues) -> context.setLeakValue(issues.countHotspotsByStatus(Issue.STATUS_REVIEWED, true))),
+
+ new IssueMetricFormula(CoreMetrics.NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS, true,
+ (context, issues) -> context.setLeakValue(issues.countHotspotsByStatus(Issue.STATUS_TO_REVIEW, true))),
+
new IssueMetricFormula(CoreMetrics.NEW_SQALE_DEBT_RATIO, true,
(context, issues) -> context.setLeakValue(100.0 * newDebtDensity(context)),
asList(CoreMetrics.NEW_TECHNICAL_DEBT, CoreMetrics.NEW_DEVELOPMENT_COST)),
with(
newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3),
newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1))
- .assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS_REVIEWED, 75.0);
+ .assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS_REVIEWED, 75.0);
withNoIssues()
.assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS_REVIEWED, 100.0);
}
+ @Test
+ public void test_security_hotspots_reviewed_status() {
+ with(
+ newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3),
+ newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1))
+ .assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS_REVIEWED_STATUS, 3.0);
+
+ withNoIssues()
+ .assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS_REVIEWED_STATUS, 0.0);
+ }
+
+ @Test
+ public void test_security_hotspots_to_review_status() {
+ with(
+ newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_REVIEWED).setCount(3),
+ newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(1))
+ .assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 1.0);
+
+ withNoIssues()
+ .assertThatValueIs(CoreMetrics.SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 0.0);
+ }
+
@Test
public void count_unresolved_by_severity() {
withNoIssues()
.assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED, 100.0);
}
+ @Test
+ public void test_new_security_hotspots_reviewed_status() {
+ with(
+ 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),
+ // not in leak
+ newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(5).setInLeak(false))
+ .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS, 3.0);
+
+ withNoIssues()
+ .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS, 0.0);
+ }
+
+ @Test
+ public void test_new_security_hotspots_to_review_status() {
+ with(
+ 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),
+ // not in leak
+ newGroup(RuleType.SECURITY_HOTSPOT).setStatus(Issue.STATUS_TO_REVIEW).setCount(5).setInLeak(false))
+ .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 1.0);
+
+ withNoIssues()
+ .assertThatLeakValueIs(CoreMetrics.NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS, 0.0);
+ }
+
@Test
public void test_new_sqale_debt_ratio_and_new_maintainability_rating() {
withNoIssues()
metric.new_security_hotspots_reviewed.description=Percentage of Security Hotspots Reviewed on New Code
metric.new_security_hotspots_reviewed.name=Security Hotspots Reviewed on New Code
metric.new_security_hotspots_reviewed.short_name=Security Hotspots Reviewed
+metric.new_security_hotspots_reviewed_status.description=Security Review Reviewed Status on New Code
+metric.new_security_hotspots_reviewed_status.name=Security Review Reviewed Status on New Code
+metric.new_security_hotspots_to_review_status.description=Security Review To Review Status on New Code
+metric.new_security_hotspots_to_review_status.name=Security Review To Review Status on New Code
metric.new_security_rating.description=Security rating on new code
metric.new_security_rating.name=Security Rating on New Code
metric.new_security_rating.extra_short_name=Rating
-metric.new_security_review_rating.description=Security Review rating on new code
-metric.new_security_review_rating.name=Security Review Rating on New Code
metric.new_security_remediation_effort.description=Security remediation effort on new code
metric.new_security_remediation_effort.name=Security Remediation Effort on New Code
metric.new_security_remediation_effort.extra_short_name=Remediation Effort
.setBestValue(100.0)
.create();
+ /**
+ * @since 8.2
+ */
+ public static final String SECURITY_HOTSPOTS_REVIEWED_STATUS_KEY = "security_hotspots_reviewed_status";
+
+ /**
+ * @since 8.2
+ *
+ * This hidden metric is only needed to compute 'security_review_rating' and 'security_hotspots_reviewed' on Applications.
+ */
+ public static final Metric<Integer> SECURITY_HOTSPOTS_REVIEWED_STATUS = new Metric.Builder(SECURITY_HOTSPOTS_REVIEWED_STATUS_KEY, "Security Review Reviewed Status",
+ Metric.ValueType.INT)
+ .setDescription("Security Review Reviewed Status")
+ .setDirection(Metric.DIRECTION_WORST)
+ .setQualitative(false)
+ .setDomain(DOMAIN_SECURITY_REVIEW)
+ .setBestValue(0.0)
+ .setOptimizedBestValue(true)
+ .setDeleteHistoricalData(true)
+ .setHidden(true)
+ .create();
+
+ /**
+ * @since 8.2
+ */
+ public static final String SECURITY_HOTSPOTS_TO_REVIEW_STATUS_KEY = "security_hotspots_to_review_status";
+
+ /**
+ * @since 8.2
+ *
+ * This hidden metric is only needed to compute 'security_review_rating' and 'security_hotspots_reviewed' on Applications.
+ */
+ public static final Metric<Integer> SECURITY_HOTSPOTS_TO_REVIEW_STATUS = new Metric.Builder(SECURITY_HOTSPOTS_TO_REVIEW_STATUS_KEY, "Security Review To Review Status",
+ Metric.ValueType.INT)
+ .setDescription("Security Review To Review Status")
+ .setDirection(Metric.DIRECTION_WORST)
+ .setQualitative(false)
+ .setDomain(DOMAIN_SECURITY_REVIEW)
+ .setBestValue(0.0)
+ .setOptimizedBestValue(true)
+ .setDeleteHistoricalData(true)
+ .setHidden(true)
+ .create();
+
+ /**
+ * @since 8.2
+ */
+ public static final String NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS_KEY = "new_security_hotspots_reviewed_status";
+
+ /**
+ * @since 8.2
+ *
+ * This hidden metric is only needed to compute 'new_security_review_rating' and 'new_security_hotspots_reviewed' on Applications.
+ */
+ public static final Metric<Integer> NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS = new Metric.Builder(NEW_SECURITY_HOTSPOTS_REVIEWED_STATUS_KEY,
+ "Security Review Reviewed Status on New Code", Metric.ValueType.INT)
+ .setDescription("Security Review Reviewed Status on New Code")
+ .setDirection(Metric.DIRECTION_WORST)
+ .setQualitative(false)
+ .setDomain(DOMAIN_SECURITY_REVIEW)
+ .setBestValue(0.0)
+ .setOptimizedBestValue(true)
+ .setDeleteHistoricalData(true)
+ .setHidden(true)
+ .create();
+
+ /**
+ * @since 8.2
+ */
+ public static final String NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS_KEY = "new_security_hotspots_to_review_status";
+
+ /**
+ * @since 8.2
+ *
+ * This hidden metric is only needed to compute 'new_security_review_rating' and 'new_security_hotspots_reviewed' on Applications.
+ */
+ public static final Metric<Integer> NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS = new Metric.Builder(NEW_SECURITY_HOTSPOTS_TO_REVIEW_STATUS_KEY,
+ "Security Review To Review Status on New Code", Metric.ValueType.INT)
+ .setDescription("Security Review To Review Status on New Code")
+ .setDirection(Metric.DIRECTION_WORST)
+ .setQualitative(false)
+ .setDomain(DOMAIN_SECURITY_REVIEW)
+ .setBestValue(0.0)
+ .setOptimizedBestValue(true)
+ .setDeleteHistoricalData(true)
+ .setHidden(true)
+ .create();
+
// --------------------------------------------------------------------------------------------------------------------
//
// FILE DATA