diff options
author | Fabrice Bellingard <bellingard@gmail.com> | 2012-01-17 08:38:01 +0100 |
---|---|---|
committer | Fabrice Bellingard <bellingard@gmail.com> | 2012-01-17 08:40:29 +0100 |
commit | 09c1adf791f2296fde7f12fa4d92532f3f1229a7 (patch) | |
tree | ba8a04d3b66ab0a019f1302f406f3f09cc2eaaf0 /plugins | |
parent | d30b0e381a451abaf2ff5aef3978d595c521bde5 (diff) | |
download | sonarqube-09c1adf791f2296fde7f12fa4d92532f3f1229a7.tar.gz sonarqube-09c1adf791f2296fde7f12fa4d92532f3f1229a7.zip |
SONAR-3012 Add new_unreviewed_violations metric
In order to more easily track incoming violations without a review
Diffstat (limited to 'plugins')
5 files changed, 215 insertions, 75 deletions
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/ReviewsMeasuresDecorator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/ReviewsMeasuresDecorator.java index c581fce39c8..a2bce1fa64c 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/ReviewsMeasuresDecorator.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/sensors/ReviewsMeasuresDecorator.java @@ -19,20 +19,31 @@ */ package org.sonar.plugins.core.sensors; +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.Map; + import org.sonar.api.batch.Decorator; import org.sonar.api.batch.DecoratorContext; import org.sonar.api.batch.DependsUpon; import org.sonar.api.measures.CoreMetrics; +import org.sonar.api.measures.Measure; import org.sonar.api.measures.MeasureUtils; import org.sonar.api.measures.Metric; import org.sonar.api.resources.Project; import org.sonar.api.resources.Resource; import org.sonar.api.resources.ResourceUtils; +import org.sonar.api.rules.Violation; +import org.sonar.batch.components.PastSnapshot; +import org.sonar.batch.components.TimeMachineConfiguration; import org.sonar.core.review.ReviewDao; import org.sonar.core.review.ReviewDto; import org.sonar.core.review.ReviewQuery; import org.sonar.plugins.core.timemachine.ViolationTrackingDecorator; +import com.google.common.collect.Maps; + /** * Decorator that creates measures related to reviews. * @@ -42,9 +53,11 @@ import org.sonar.plugins.core.timemachine.ViolationTrackingDecorator; public class ReviewsMeasuresDecorator implements Decorator { private ReviewDao reviewDao; + private TimeMachineConfiguration timeMachineConfiguration; - public ReviewsMeasuresDecorator(ReviewDao reviewDao) { + public ReviewsMeasuresDecorator(ReviewDao reviewDao, TimeMachineConfiguration timeMachineConfiguration) { this.reviewDao = reviewDao; + this.timeMachineConfiguration = timeMachineConfiguration; } public boolean shouldExecuteOnProject(Project project) { @@ -64,28 +77,35 @@ public class ReviewsMeasuresDecorator implements Decorator { return; } - // Open reviews + // Load open reviews (used for counting and also for tracking new violations without a review) ReviewQuery openReviewQuery = ReviewQuery.create().setResourceId(resource.getId()).addStatus(ReviewDto.STATUS_OPEN) .addStatus(ReviewDto.STATUS_REOPENED); - Double resourceOpenReviewsCount = reviewDao.countByQuery(openReviewQuery).doubleValue(); + List<ReviewDto> openReviews = reviewDao.selectByQuery(openReviewQuery); + Map<Integer, ReviewDto> openReviewsByViolationPermanentIds = Maps.newHashMap(); + for (ReviewDto reviewDto : openReviews) { + openReviewsByViolationPermanentIds.put(reviewDto.getViolationPermanentId(), reviewDto); + } + + // Count open reviews + Double resourceOpenReviewsCount = (double) openReviewsByViolationPermanentIds.size(); Double totalOpenReviewsCount = resourceOpenReviewsCount + getChildrenSum(resource, context, CoreMetrics.ACTIVE_REVIEWS); context.saveMeasure(CoreMetrics.ACTIVE_REVIEWS, totalOpenReviewsCount); - // Unassigned reviews + // Count unassigned reviews ReviewQuery unassignedReviewQuery = ReviewQuery.copy(openReviewQuery).setNoAssignee(); Double ressourceUnassignedReviewsCount = reviewDao.countByQuery(unassignedReviewQuery).doubleValue(); Double totalUnassignedReviewsCount = ressourceUnassignedReviewsCount + getChildrenSum(resource, context, CoreMetrics.UNASSIGNED_REVIEWS); context.saveMeasure(CoreMetrics.UNASSIGNED_REVIEWS, totalUnassignedReviewsCount); - // Unplanned reviews + // Count unplanned reviews ReviewQuery plannedReviewQuery = ReviewQuery.copy(openReviewQuery).setPlanned(); Double resourcePlannedReviewsCount = reviewDao.countByQuery(plannedReviewQuery).doubleValue(); Double childrenUnplannedReviewsCount = getChildrenSum(resource, context, CoreMetrics.UNPLANNED_REVIEWS); context.saveMeasure(CoreMetrics.UNPLANNED_REVIEWS, (resourceOpenReviewsCount - resourcePlannedReviewsCount) + childrenUnplannedReviewsCount); - // False positive reviews + // Count false positive reviews ReviewQuery falsePositiveReviewQuery = ReviewQuery.create().setResourceId(resource.getId()) .addResolution(ReviewDto.RESOLUTION_FALSE_POSITIVE); Double resourceFalsePositiveReviewsCount = reviewDao.countByQuery(falsePositiveReviewQuery).doubleValue(); @@ -93,9 +113,42 @@ public class ReviewsMeasuresDecorator implements Decorator { + getChildrenSum(resource, context, CoreMetrics.FALSE_POSITIVE_REVIEWS); context.saveMeasure(CoreMetrics.FALSE_POSITIVE_REVIEWS, totalFalsePositiveReviewsCount); - // Violations without a review + // Count violations without a review Double violationsCount = MeasureUtils.getValue(context.getMeasure(CoreMetrics.VIOLATIONS), 0.0); context.saveMeasure(CoreMetrics.VIOLATIONS_WITHOUT_REVIEW, violationsCount - totalOpenReviewsCount); + + // And finally track new violations without a review + trackNewViolationsWithoutReview(context, openReviewsByViolationPermanentIds); + } + + protected void trackNewViolationsWithoutReview(DecoratorContext context, Map<Integer, ReviewDto> openReviewsByViolationPermanentIds) { + List<Violation> violations = context.getViolations(); + Measure measure = new Measure(CoreMetrics.NEW_VIOLATIONS_WITHOUT_REVIEW); + for (PastSnapshot pastSnapshot : timeMachineConfiguration.getProjectPastSnapshots()) { + int newUnreviewedViolations = countNewUnreviewedViolationsForSnapshot(pastSnapshot, violations, openReviewsByViolationPermanentIds); + int variationIndex = pastSnapshot.getIndex(); + Collection<Measure> children = context.getChildrenMeasures(CoreMetrics.NEW_VIOLATIONS_WITHOUT_REVIEW); + double sumNewUnreviewedViolations = MeasureUtils.sumOnVariation(true, variationIndex, children) + newUnreviewedViolations; + measure.setVariation(variationIndex, sumNewUnreviewedViolations); + } + context.saveMeasure(measure); + } + + protected int countNewUnreviewedViolationsForSnapshot(PastSnapshot pastSnapshot, List<Violation> violations, + Map<Integer, ReviewDto> openReviewsByViolationPermanentIds) { + Date targetDate = pastSnapshot.getTargetDate(); + int newViolationCount = 0; + int newReviewedViolationCount = 0; + for (Violation violation : violations) { + if (isAfter(violation, targetDate)) { + newViolationCount += 1; + if (openReviewsByViolationPermanentIds.get(violation.getPermanentId()) != null) { + newReviewedViolationCount += 1; + } + } + } + int newUnreviewedViolations = newViolationCount - newReviewedViolationCount; + return newUnreviewedViolations; } private Double getChildrenSum(Resource<?> resource, DecoratorContext context, Metric metric) { @@ -106,4 +159,11 @@ public class ReviewsMeasuresDecorator implements Decorator { return sum; } + private boolean isAfter(Violation violation, Date date) { + if (date == null) { + return true; + } + return violation.getCreatedAt() != null && violation.getCreatedAt().after(date); + } + } diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewViolationsDecorator.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewViolationsDecorator.java index b54529a6019..64005d358bd 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewViolationsDecorator.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/timemachine/NewViolationsDecorator.java @@ -19,12 +19,24 @@ */ package org.sonar.plugins.core.timemachine; -import com.google.common.collect.ArrayListMultimap; -import com.google.common.collect.ListMultimap; -import com.google.common.collect.Sets; +import java.util.Arrays; +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.Set; + import org.apache.commons.lang.StringUtils; -import org.sonar.api.batch.*; -import org.sonar.api.measures.*; +import org.sonar.api.batch.Decorator; +import org.sonar.api.batch.DecoratorBarriers; +import org.sonar.api.batch.DecoratorContext; +import org.sonar.api.batch.DependedUpon; +import org.sonar.api.batch.DependsUpon; +import org.sonar.api.measures.CoreMetrics; +import org.sonar.api.measures.Measure; +import org.sonar.api.measures.MeasureUtils; +import org.sonar.api.measures.MeasuresFilters; +import org.sonar.api.measures.Metric; +import org.sonar.api.measures.RuleMeasure; import org.sonar.api.resources.Project; import org.sonar.api.resources.Resource; import org.sonar.api.resources.ResourceUtils; @@ -35,7 +47,9 @@ import org.sonar.api.rules.Violation; import org.sonar.batch.components.PastSnapshot; import org.sonar.batch.components.TimeMachineConfiguration; -import java.util.*; +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.ListMultimap; +import com.google.common.collect.Sets; @DependsUpon(DecoratorBarriers.END_OF_VIOLATION_TRACKING) public class NewViolationsDecorator implements Decorator { @@ -53,12 +67,12 @@ public class NewViolationsDecorator implements Decorator { @DependedUpon public List<Metric> generatesMetric() { return Arrays.asList( - CoreMetrics.NEW_VIOLATIONS, - CoreMetrics.NEW_BLOCKER_VIOLATIONS, - CoreMetrics.NEW_CRITICAL_VIOLATIONS, - CoreMetrics.NEW_MAJOR_VIOLATIONS, - CoreMetrics.NEW_MINOR_VIOLATIONS, - CoreMetrics.NEW_INFO_VIOLATIONS); + CoreMetrics.NEW_VIOLATIONS, + CoreMetrics.NEW_BLOCKER_VIOLATIONS, + CoreMetrics.NEW_CRITICAL_VIOLATIONS, + CoreMetrics.NEW_MAJOR_VIOLATIONS, + CoreMetrics.NEW_MINOR_VIOLATIONS, + CoreMetrics.NEW_INFO_VIOLATIONS); } public void decorate(Resource resource, DecoratorContext context) { @@ -70,10 +84,10 @@ public class NewViolationsDecorator implements Decorator { } private boolean shouldDecorateResource(Resource resource, DecoratorContext context) { - return - (StringUtils.equals(Scopes.PROJECT, resource.getScope()) || StringUtils.equals(Scopes.DIRECTORY, resource.getScope()) || StringUtils.equals(Scopes.FILE, resource.getScope())) - && !ResourceUtils.isUnitTestClass(resource) - && context.getMeasure(CoreMetrics.NEW_VIOLATIONS) == null; + return (StringUtils.equals(Scopes.PROJECT, resource.getScope()) || StringUtils.equals(Scopes.DIRECTORY, resource.getScope()) || StringUtils + .equals(Scopes.FILE, resource.getScope())) + && !ResourceUtils.isUnitTestClass(resource) + && context.getMeasure(CoreMetrics.NEW_VIOLATIONS) == null; } private void computeNewViolations(DecoratorContext context) { @@ -82,7 +96,7 @@ public class NewViolationsDecorator implements Decorator { int variationIndex = pastSnapshot.getIndex(); Collection<Measure> children = context.getChildrenMeasures(CoreMetrics.NEW_VIOLATIONS); int count = countViolations(context.getViolations(), pastSnapshot.getTargetDate()); - double sum = sumChildren(variationIndex, children) + count; + double sum = MeasureUtils.sumOnVariation(true, variationIndex, children) + count; measure.setVariation(variationIndex, sum); } context.saveMeasure(measure); @@ -101,7 +115,7 @@ public class NewViolationsDecorator implements Decorator { int variationIndex = pastSnapshot.getIndex(); int count = countViolations(violationsPerSeverities.get(severity), pastSnapshot.getTargetDate()); Collection<Measure> children = context.getChildrenMeasures(MeasuresFilters.metric(metric)); - double sum = sumChildren(variationIndex, children) + count; + double sum = MeasureUtils.sumOnVariation(true, variationIndex, children) + count; measure.setVariation(variationIndex, sum); } context.saveMeasure(measure); @@ -138,7 +152,7 @@ public class NewViolationsDecorator implements Decorator { for (PastSnapshot pastSnapshot : timeMachineConfiguration.getProjectPastSnapshots()) { int variationIndex = pastSnapshot.getIndex(); int count = countViolations(violationsPerRule.get(rule), pastSnapshot.getTargetDate()); - double sum = sumChildren(variationIndex, childMeasuresPerRule.get(rule)) + count; + double sum = MeasureUtils.sumOnVariation(true, variationIndex, childMeasuresPerRule.get(rule)) + count; measure.setVariation(variationIndex, sum); } context.saveMeasure(measure); @@ -146,17 +160,6 @@ public class NewViolationsDecorator implements Decorator { } } - int sumChildren(int variationIndex, Collection<Measure> measures) { - int sum = 0; - for (Measure measure : measures) { - Double var = measure.getVariation(variationIndex); - if (var != null) { - sum += var.intValue(); - } - } - return sum; - } - int countViolations(Collection<Violation> violations, Date targetDate) { if (violations == null) { return 0; diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/ReviewsMeasuresDecoratorTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/ReviewsMeasuresDecoratorTest.java index 21938e80a44..533be2b0ae6 100644 --- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/ReviewsMeasuresDecoratorTest.java +++ b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/sensors/ReviewsMeasuresDecoratorTest.java @@ -30,36 +30,86 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang.ObjectUtils; +import org.apache.commons.lang.time.DateUtils; import org.hamcrest.BaseMatcher; import org.hamcrest.Description; +import org.junit.Before; import org.junit.Test; import org.sonar.api.batch.DecoratorContext; import org.sonar.api.measures.CoreMetrics; import org.sonar.api.measures.Measure; import org.sonar.api.measures.Metric; +import org.sonar.api.measures.RuleMeasure; import org.sonar.api.resources.File; import org.sonar.api.resources.Project; import org.sonar.api.resources.Qualifiers; import org.sonar.api.resources.Resource; import org.sonar.api.resources.Scopes; +import org.sonar.api.rules.Rule; +import org.sonar.api.rules.Violation; +import org.sonar.batch.components.PastSnapshot; +import org.sonar.batch.components.TimeMachineConfiguration; import org.sonar.core.review.ReviewDao; import org.sonar.core.review.ReviewDto; import org.sonar.core.review.ReviewQuery; import org.sonar.plugins.core.timemachine.ViolationTrackingDecorator; import com.google.common.collect.Lists; +import com.google.common.collect.Maps; public class ReviewsMeasuresDecoratorTest { + private ReviewDao reviewDao; + private ReviewsMeasuresDecorator decorator; + private DecoratorContext context; + + private Date rightNow; + private Date tenDaysAgo; + private Date fiveDaysAgo; + + @Before + public void setUp() { + reviewDao = mock(ReviewDao.class); + when(reviewDao.selectByQuery(argThat(openReviewQueryMatcher()))).thenReturn(createListOf10Reviews()); + when(reviewDao.countByQuery(argThat(unassignedReviewQueryMatcher()))).thenReturn(2); + when(reviewDao.countByQuery(argThat(plannedReviewQueryMatcher()))).thenReturn(3); + when(reviewDao.countByQuery(argThat(falsePositiveReviewQueryMatcher()))).thenReturn(4); + + rightNow = new Date(); + tenDaysAgo = DateUtils.addDays(rightNow, -10); + fiveDaysAgo = DateUtils.addDays(rightNow, -5); + + PastSnapshot pastSnapshot = mock(PastSnapshot.class); + when(pastSnapshot.getIndex()).thenReturn(1); + when(pastSnapshot.getTargetDate()).thenReturn(fiveDaysAgo); + + PastSnapshot pastSnapshot2 = mock(PastSnapshot.class); + when(pastSnapshot2.getIndex()).thenReturn(2); + when(pastSnapshot2.getTargetDate()).thenReturn(tenDaysAgo); + + TimeMachineConfiguration timeMachineConfiguration = mock(TimeMachineConfiguration.class); + when(timeMachineConfiguration.getProjectPastSnapshots()).thenReturn(Arrays.asList(pastSnapshot, pastSnapshot2)); + + decorator = new ReviewsMeasuresDecorator(reviewDao, timeMachineConfiguration); + context = mock(DecoratorContext.class); + when(context.getMeasure(CoreMetrics.VIOLATIONS)).thenReturn(new Measure(CoreMetrics.VIOLATIONS, 35d)); + } + @Test public void testDependsUponViolationTracking() throws Exception { - ReviewsMeasuresDecorator decorator = new ReviewsMeasuresDecorator(null); + ReviewsMeasuresDecorator decorator = new ReviewsMeasuresDecorator(null, null); assertEquals(decorator.dependsUponViolationTracking(), ViolationTrackingDecorator.class); } @Test public void shouldExecuteOnProject() throws Exception { - ReviewsMeasuresDecorator decorator = new ReviewsMeasuresDecorator(null); + ReviewsMeasuresDecorator decorator = new ReviewsMeasuresDecorator(null, null); Project project = new Project("foo"); project.setLatestAnalysis(true); assertThat(decorator.shouldExecuteOnProject(project), is(true)); @@ -67,7 +117,7 @@ public class ReviewsMeasuresDecoratorTest { @Test public void shouldDecoratePersistableResource() throws Exception { - ReviewsMeasuresDecorator decorator = new ReviewsMeasuresDecorator(null); + ReviewsMeasuresDecorator decorator = new ReviewsMeasuresDecorator(null, null); DecoratorContext context = mock(DecoratorContext.class); Resource<?> resource = mock(Resource.class); when(resource.getScope()).thenReturn(Scopes.BLOCK_UNIT); @@ -77,7 +127,7 @@ public class ReviewsMeasuresDecoratorTest { @Test public void shouldNotDecorateUnitTest() throws Exception { - ReviewsMeasuresDecorator decorator = new ReviewsMeasuresDecorator(null); + ReviewsMeasuresDecorator decorator = new ReviewsMeasuresDecorator(null, null); DecoratorContext context = mock(DecoratorContext.class); Resource<?> resource = mock(Resource.class); when(resource.getScope()).thenReturn(Scopes.FILE); @@ -87,17 +137,8 @@ public class ReviewsMeasuresDecoratorTest { } @Test - public void shouldComputeReviewMetricsOnFile() throws Exception { - ReviewDao reviewDao = mock(ReviewDao.class); - when(reviewDao.countByQuery(argThat(openReviewQueryMatcher()))).thenReturn(10); - when(reviewDao.countByQuery(argThat(unassignedReviewQueryMatcher()))).thenReturn(2); - when(reviewDao.countByQuery(argThat(plannedReviewQueryMatcher()))).thenReturn(3); - when(reviewDao.countByQuery(argThat(falsePositiveReviewQueryMatcher()))).thenReturn(4); - - ReviewsMeasuresDecorator decorator = new ReviewsMeasuresDecorator(reviewDao); + public void shouldComputeReviewsMetricsOnFile() throws Exception { Resource<?> resource = new File("foo").setId(1); - DecoratorContext context = mock(DecoratorContext.class); - when(context.getMeasure(CoreMetrics.VIOLATIONS)).thenReturn(new Measure(CoreMetrics.VIOLATIONS, 35d)); decorator.decorate(resource, context); verify(context).saveMeasure(CoreMetrics.ACTIVE_REVIEWS, 10d); @@ -108,18 +149,7 @@ public class ReviewsMeasuresDecoratorTest { } @Test - public void shouldComputeReviewMetricsOnProject() throws Exception { - ReviewDao reviewDao = mock(ReviewDao.class); - // Same 4 values used as for #shouldComputeReviewMetricsOnFile - when(reviewDao.countByQuery(argThat(openReviewQueryMatcher()))).thenReturn(10); - when(reviewDao.countByQuery(argThat(unassignedReviewQueryMatcher()))).thenReturn(2); - when(reviewDao.countByQuery(argThat(plannedReviewQueryMatcher()))).thenReturn(3); - when(reviewDao.countByQuery(argThat(falsePositiveReviewQueryMatcher()))).thenReturn(4); - - ReviewsMeasuresDecorator decorator = new ReviewsMeasuresDecorator(reviewDao); - Resource<?> resource = new Project("foo").setId(1); - DecoratorContext context = mock(DecoratorContext.class); - when(context.getMeasure(CoreMetrics.VIOLATIONS)).thenReturn(new Measure(CoreMetrics.VIOLATIONS, 35d)); + public void shouldComputeReviewsMetricsOnProject() throws Exception { when(context.getChildrenMeasures(CoreMetrics.ACTIVE_REVIEWS)).thenReturn( Lists.newArrayList(new Measure(CoreMetrics.ACTIVE_REVIEWS, 7d))); when(context.getChildrenMeasures(CoreMetrics.UNASSIGNED_REVIEWS)).thenReturn( @@ -128,6 +158,8 @@ public class ReviewsMeasuresDecoratorTest { Lists.newArrayList(new Measure(CoreMetrics.UNPLANNED_REVIEWS, 2d))); when(context.getChildrenMeasures(CoreMetrics.FALSE_POSITIVE_REVIEWS)).thenReturn( Lists.newArrayList(new Measure(CoreMetrics.FALSE_POSITIVE_REVIEWS, 2d))); + + Resource<?> resource = new Project("foo").setId(1); decorator.decorate(resource, context); // As same values used for #shouldComputeReviewMetricsOnFile, we just add the children measures to verify @@ -138,6 +170,33 @@ public class ReviewsMeasuresDecoratorTest { verify(context).saveMeasure(CoreMetrics.VIOLATIONS_WITHOUT_REVIEW, 35d - (10d + 7d)); } + @Test + public void shouldTrackNewViolationsWithoutReview() throws Exception { + Resource<?> resource = new File("foo").setId(1); + Violation v1 = Violation.create((Rule) null, resource).setPermanentId(1); // test the null case for the created_at date + Violation v2 = Violation.create((Rule) null, resource).setPermanentId(2).setCreatedAt(rightNow); + Violation v3 = Violation.create((Rule) null, resource).setPermanentId(3).setCreatedAt(fiveDaysAgo); + Violation v4 = Violation.create((Rule) null, resource).setPermanentId(4).setCreatedAt(fiveDaysAgo); + Violation v5 = Violation.create((Rule) null, resource).setPermanentId(5).setCreatedAt(fiveDaysAgo); + Violation v6 = Violation.create((Rule) null, resource).setPermanentId(6).setCreatedAt(tenDaysAgo); + when(context.getViolations()).thenReturn(Arrays.asList(v1, v2, v3, v4, v5, v6)); + + Map<Integer, ReviewDto> openReviewsByViolationPermanentIds = Maps.newHashMap(); + openReviewsByViolationPermanentIds.put(1, new ReviewDto()); + openReviewsByViolationPermanentIds.put(3, new ReviewDto()); + + decorator.trackNewViolationsWithoutReview(context, openReviewsByViolationPermanentIds); + verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_VIOLATIONS_WITHOUT_REVIEW, 1.0, 3.0))); + } + + private List<ReviewDto> createListOf10Reviews() { + List<ReviewDto> reviews = Lists.newArrayList(); + for (int i = 1; i < 11; i++) { + reviews.add(new ReviewDto().setViolationPermanentId(i)); + } + return reviews; + } + private BaseMatcher<ReviewQuery> openReviewQueryMatcher() { return new BaseMatcher<ReviewQuery>() { public boolean matches(Object o) { @@ -200,4 +259,30 @@ public class ReviewsMeasuresDecoratorTest { } }; } + + private class IsVariationMeasure extends BaseMatcher<Measure> { + private Metric metric = null; + private Double var1 = null; + private Double var2 = null; + + public IsVariationMeasure(Metric metric, Double var1, Double var2) { + this.metric = metric; + this.var1 = var1; + this.var2 = var2; + } + + public boolean matches(Object o) { + if (!(o instanceof Measure)) { + return false; + } + Measure m = (Measure) o; + return ObjectUtils.equals(metric, m.getMetric()) && + ObjectUtils.equals(var1, m.getVariation1()) && + ObjectUtils.equals(var2, m.getVariation2()) && + !(m instanceof RuleMeasure); + } + + public void describeTo(Description o) { + } + } } diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/NewViolationsDecoratorTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/NewViolationsDecoratorTest.java index 3587fb7f1c6..8dc10282cb3 100644 --- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/NewViolationsDecoratorTest.java +++ b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/timemachine/NewViolationsDecoratorTest.java @@ -116,17 +116,6 @@ public class NewViolationsDecoratorTest { } @Test - public void shouldSumChildren() { - Measure measure1 = new Measure(CoreMetrics.NEW_VIOLATIONS).setVariation1(1.0).setVariation2(1.0).setVariation3(3.0); - Measure measure2 = new Measure(CoreMetrics.NEW_VIOLATIONS).setVariation1(1.0).setVariation2(2.0).setVariation3(3.0); - List<Measure> children = Arrays.asList(measure1, measure2); - - assertThat(decorator.sumChildren(1, children), is(2)); - assertThat(decorator.sumChildren(2, children), is(3)); - assertThat(decorator.sumChildren(3, children), is(6)); - } - - @Test public void shouldClearCacheAfterExecution() { Violation violation1 = Violation.create(rule1, resource).setSeverity(RulePriority.CRITICAL).setCreatedAt(rightNow); Violation violation2 = Violation.create(rule2, resource).setSeverity(RulePriority.CRITICAL).setCreatedAt(rightNow); diff --git a/plugins/sonar-l10n-en-plugin/src/main/resources/org/sonar/l10n/core.properties b/plugins/sonar-l10n-en-plugin/src/main/resources/org/sonar/l10n/core.properties index 174815553b8..0952e5a769b 100644 --- a/plugins/sonar-l10n-en-plugin/src/main/resources/org/sonar/l10n/core.properties +++ b/plugins/sonar-l10n-en-plugin/src/main/resources/org/sonar/l10n/core.properties @@ -1417,7 +1417,7 @@ metric.minor_violations.description=Minor violations metric.info_violations.name=Info violations metric.info_violations.description=Info violations -metric.new_violations.name=New Violations +metric.new_violations.name=New violations metric.new_violations.description=New Violations metric.new_blocker_violations.name=New Blocker violations @@ -1561,6 +1561,9 @@ metric.team_size.description=Size of the project team metric.violations_without_review.name=Unreviewed violations metric.violations_without_review.description=Violations that have not been reviewed yet +metric.new_violations_without_review.name=New unreviewed violations +metric.new_violations_without_review.description=New violations that have not been reviewed yet + metric.false_positive_reviews.name=False-positive reviews metric.false_positive_reviews.description=Active false-positive reviews |