2 * Sonar, open source software quality management tool.
3 * Copyright (C) 2008-2012 SonarSource
4 * mailto:contact AT sonarsource DOT com
6 * Sonar is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 3 of the License, or (at your option) any later version.
11 * Sonar is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with Sonar; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
20 package org.sonar.plugins.core.timemachine;
22 import static org.hamcrest.Matchers.is;
23 import static org.junit.Assert.assertThat;
24 import static org.mockito.Matchers.any;
25 import static org.mockito.Matchers.argThat;
26 import static org.mockito.Matchers.eq;
27 import static org.mockito.Mockito.mock;
28 import static org.mockito.Mockito.never;
29 import static org.mockito.Mockito.times;
30 import static org.mockito.Mockito.verify;
31 import static org.mockito.Mockito.when;
33 import java.text.DateFormat;
34 import java.text.SimpleDateFormat;
35 import java.util.Arrays;
36 import java.util.Calendar;
37 import java.util.Date;
38 import java.util.GregorianCalendar;
39 import java.util.List;
41 import org.apache.commons.lang.ObjectUtils;
42 import org.apache.commons.lang.time.DateUtils;
43 import org.hamcrest.BaseMatcher;
44 import org.hamcrest.Description;
45 import org.junit.Before;
46 import org.junit.Test;
47 import org.sonar.api.batch.DecoratorContext;
48 import org.sonar.api.measures.CoreMetrics;
49 import org.sonar.api.measures.Measure;
50 import org.sonar.api.measures.Metric;
51 import org.sonar.api.measures.RuleMeasure;
52 import org.sonar.api.notifications.Notification;
53 import org.sonar.api.notifications.NotificationManager;
54 import org.sonar.api.resources.File;
55 import org.sonar.api.resources.Project;
56 import org.sonar.api.resources.Qualifiers;
57 import org.sonar.api.resources.Resource;
58 import org.sonar.api.rules.Rule;
59 import org.sonar.api.rules.RulePriority;
60 import org.sonar.api.rules.Violation;
61 import org.sonar.batch.components.PastSnapshot;
62 import org.sonar.batch.components.TimeMachineConfiguration;
64 import com.google.common.collect.Lists;
66 public class NewViolationsDecoratorTest {
71 private NewViolationsDecorator decorator;
72 private DecoratorContext context;
73 private Resource resource;
74 private NotificationManager notificationManager;
76 private Date rightNow;
77 private Date tenDaysAgo;
78 private Date fiveDaysAgo;
79 private TimeMachineConfiguration timeMachineConfiguration;
83 rightNow = new Date();
84 tenDaysAgo = DateUtils.addDays(rightNow, -10);
85 fiveDaysAgo = DateUtils.addDays(rightNow, -5);
87 PastSnapshot pastSnapshot = mock(PastSnapshot.class);
88 when(pastSnapshot.getIndex()).thenReturn(1);
89 when(pastSnapshot.getTargetDate()).thenReturn(fiveDaysAgo);
91 PastSnapshot pastSnapshot2 = mock(PastSnapshot.class);
92 when(pastSnapshot2.getIndex()).thenReturn(2);
93 when(pastSnapshot2.getTargetDate()).thenReturn(tenDaysAgo);
95 timeMachineConfiguration = mock(TimeMachineConfiguration.class);
96 when(timeMachineConfiguration.getProjectPastSnapshots()).thenReturn(Arrays.asList(pastSnapshot, pastSnapshot2));
98 context = mock(DecoratorContext.class);
99 resource = new File("com/foo/bar");
100 when(context.getResource()).thenReturn(resource);
102 notificationManager = mock(NotificationManager.class);
103 decorator = new NewViolationsDecorator(timeMachineConfiguration, notificationManager);
105 rule1 = Rule.create().setRepositoryKey("rule1").setKey("rule1").setName("name1");
106 rule2 = Rule.create().setRepositoryKey("rule2").setKey("rule2").setName("name2");
107 rule3 = Rule.create().setRepositoryKey("rule3").setKey("rule3").setName("name3");
111 public void shouldExecuteIfLastAnalysis() {
112 Project project = mock(Project.class);
114 when(project.isLatestAnalysis()).thenReturn(false);
115 assertThat(decorator.shouldExecuteOnProject(project), is(false));
117 when(project.isLatestAnalysis()).thenReturn(true);
118 assertThat(decorator.shouldExecuteOnProject(project), is(true));
122 public void shouldBeDependedUponMetric() {
123 assertThat(decorator.generatesMetric().size(), is(6));
127 public void shouldCountViolationsAfterDate() {
128 List<Violation> violations = createViolations();
130 assertThat(decorator.countViolations(null, fiveDaysAgo), is(0));
131 assertThat(decorator.countViolations(violations, fiveDaysAgo), is(1)); // 1 rightNow
132 assertThat(decorator.countViolations(violations, tenDaysAgo), is(3)); // 1 rightNow + 2 fiveDaysAgo
136 public void shouldClearCacheAfterExecution() {
137 Violation violation1 = Violation.create(rule1, resource).setSeverity(RulePriority.CRITICAL).setCreatedAt(rightNow);
138 Violation violation2 = Violation.create(rule2, resource).setSeverity(RulePriority.CRITICAL).setCreatedAt(rightNow);
139 when(context.getViolations()).thenReturn(Arrays.asList(violation1)).thenReturn(Arrays.asList(violation2));
141 decorator.decorate(resource, context);
142 decorator.decorate(resource, context);
144 verify(context, times(2)).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_CRITICAL_VIOLATIONS, 1.0, 1.0)));
145 verify(context, never()).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_CRITICAL_VIOLATIONS, 2.0, 2.0)));
149 public void severityViolations() {
150 when(context.getViolations()).thenReturn(createViolations());
152 decorator.decorate(resource, context);
154 // remember : period1 is 5daysAgo, period2 is 10daysAgo
155 verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_BLOCKER_VIOLATIONS, 0.0, 0.0)));
156 verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_CRITICAL_VIOLATIONS, 1.0, 1.0)));
157 verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_MAJOR_VIOLATIONS, 0.0, 1.0)));
158 verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_MINOR_VIOLATIONS, 0.0, 1.0)));
159 verify(context).saveMeasure(argThat(new IsVariationMeasure(CoreMetrics.NEW_INFO_VIOLATIONS, 0.0, 0.0)));
163 public void ruleViolations() {
164 when(context.getViolations()).thenReturn(createViolations());
166 decorator.decorate(resource, context);
168 // remember : period1 is 5daysAgo, period2 is 10daysAgo
169 verify(context).saveMeasure(argThat(new IsVariationRuleMeasure(CoreMetrics.NEW_CRITICAL_VIOLATIONS, rule1, 1.0, 1.0)));
170 verify(context).saveMeasure(argThat(new IsVariationRuleMeasure(CoreMetrics.NEW_MAJOR_VIOLATIONS, rule2, 0.0, 1.0)));
171 verify(context).saveMeasure(argThat(new IsVariationRuleMeasure(CoreMetrics.NEW_MINOR_VIOLATIONS, rule3, 0.0, 1.0)));
175 public void shouldNotNotifyIfNotLastestAnalysis() {
176 Project project = mock(Project.class);
177 when(project.isLatestAnalysis()).thenReturn(false);
178 assertThat(decorator.shouldExecuteOnProject(project), is(false));
182 public void shouldNotNotifyIfNotRootProject() throws Exception {
183 Project project = mock(Project.class);
184 when(project.getQualifier()).thenReturn(Qualifiers.MODULE);
186 decorator.decorate(project, context);
188 verify(notificationManager, never()).scheduleForSending(any(Notification.class));
192 public void shouldNotNotifyIfNoPeriodForLastAnalysis() throws Exception {
193 Project project = new Project("key");
194 when(timeMachineConfiguration.getLastAnalysisPeriodIndex()).thenReturn(null);
196 decorator.notifyNewViolations(project, context);
198 verify(notificationManager, never()).scheduleForSending(any(Notification.class));
202 public void shouldNotNotifyIfNoNewViolations() throws Exception {
203 Project project = new Project("key");
204 when(timeMachineConfiguration.getLastAnalysisPeriodIndex()).thenReturn(1);
205 Measure m = new Measure(CoreMetrics.NEW_VIOLATIONS);
206 when(context.getMeasure(CoreMetrics.NEW_VIOLATIONS)).thenReturn(m);
208 // NULL is returned here
209 decorator.notifyNewViolations(project, context);
210 verify(notificationManager, never()).scheduleForSending(any(Notification.class));
212 // 0 will be returned now
213 m.setVariation1(0.0);
214 decorator.notifyNewViolations(project, context);
215 verify(notificationManager, never()).scheduleForSending(any(Notification.class));
219 public void shouldNotifyUserAboutNewViolations() throws Exception {
220 Project project = new Project("key").setName("LongName");
222 when(timeMachineConfiguration.getLastAnalysisPeriodIndex()).thenReturn(2);
223 Calendar pastDate = new GregorianCalendar(2011, 10, 25);
224 PastSnapshot pastSnapshot = new PastSnapshot("", pastDate.getTime());
225 when(timeMachineConfiguration.getProjectPastSnapshots()).thenReturn(Lists.newArrayList(pastSnapshot, pastSnapshot));
226 Measure m = new Measure(CoreMetrics.NEW_VIOLATIONS).setVariation2(32.0);
227 when(context.getMeasure(CoreMetrics.NEW_VIOLATIONS)).thenReturn(m);
229 decorator.decorate(project, context);
231 DateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd");
232 Notification notification = new Notification("new-violations")
233 .setFieldValue("count", "32")
234 .setFieldValue("projectName", "LongName")
235 .setFieldValue("projectKey", "key")
236 .setFieldValue("projectId", "45")
237 .setFieldValue("period", "2")
238 .setFieldValue("fromDate", dateformat.format(pastDate.getTime()))
239 .setFieldValue("toDate", dateformat.format(new Date()));
240 verify(notificationManager, times(1)).scheduleForSending(eq(notification));
243 private List<Violation> createViolations() {
244 List<Violation> violations = Lists.newLinkedList();
245 violations.add(Violation.create(rule1, resource).setSeverity(RulePriority.CRITICAL).setCreatedAt(rightNow));
246 violations.add(Violation.create(rule1, resource).setSeverity(RulePriority.CRITICAL).setCreatedAt(tenDaysAgo));
247 violations.add(Violation.create(rule2, resource).setSeverity(RulePriority.MAJOR).setCreatedAt(fiveDaysAgo));
248 violations.add(Violation.create(rule2, resource).setSeverity(RulePriority.MAJOR).setCreatedAt(tenDaysAgo));
249 violations.add(Violation.create(rule3, resource).setSeverity(RulePriority.MINOR).setCreatedAt(fiveDaysAgo));
250 violations.add(Violation.create(rule3, resource).setSeverity(RulePriority.MINOR).setCreatedAt(tenDaysAgo));
254 private class IsVariationRuleMeasure extends BaseMatcher<Measure> {
255 private Metric metric = null;
256 private Rule rule = null;
257 private Double var1 = null;
258 private Double var2 = null;
260 public IsVariationRuleMeasure(Metric metric, Rule rule, Double var1, Double var2) {
261 this.metric = metric;
267 public boolean matches(Object o) {
268 if (!(o instanceof RuleMeasure)) {
271 RuleMeasure m = (RuleMeasure) o;
272 return ObjectUtils.equals(metric, m.getMetric()) &&
273 ObjectUtils.equals(rule, m.getRule()) &&
274 ObjectUtils.equals(var1, m.getVariation1()) &&
275 ObjectUtils.equals(var2, m.getVariation2());
278 public void describeTo(Description arg0) {
282 private class IsVariationMeasure extends BaseMatcher<Measure> {
283 private Metric metric = null;
284 private Double var1 = null;
285 private Double var2 = null;
287 public IsVariationMeasure(Metric metric, Double var1, Double var2) {
288 this.metric = metric;
293 public boolean matches(Object o) {
294 if (!(o instanceof Measure)) {
297 Measure m = (Measure) o;
298 return ObjectUtils.equals(metric, m.getMetric()) &&
299 ObjectUtils.equals(var1, m.getVariation1()) &&
300 ObjectUtils.equals(var2, m.getVariation2()) &&
301 !(m instanceof RuleMeasure);
304 public void describeTo(Description o) {