]> source.dussan.org Git - sonarqube.git/blob
0bb77e1239af3eadbfbd9c525ee50d3a3cff4f50
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2016 SonarSource SA
4  * mailto:contact AT sonarsource DOT com
5  *
6  * This program 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.
10  *
11  * This program 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.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  */
20 package org.sonar.server.computation.task.projectanalysis.formula;
21
22 import com.google.common.base.Optional;
23 import com.google.common.collect.ImmutableList;
24 import org.assertj.core.api.AbstractIterableAssert;
25 import org.junit.Rule;
26 import org.junit.Test;
27 import org.sonar.api.measures.CoreMetrics;
28 import org.sonar.server.computation.task.projectanalysis.component.PathAwareCrawler;
29 import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolderRule;
30 import org.sonar.server.computation.task.projectanalysis.component.ViewsComponent;
31 import org.sonar.server.computation.task.projectanalysis.formula.counter.IntVariationValue;
32 import org.sonar.server.computation.task.projectanalysis.measure.Measure;
33 import org.sonar.server.computation.task.projectanalysis.measure.MeasureRepoEntry;
34 import org.sonar.server.computation.task.projectanalysis.measure.MeasureRepositoryRule;
35 import org.sonar.server.computation.task.projectanalysis.measure.MeasureVariations;
36 import org.sonar.server.computation.task.projectanalysis.metric.Metric;
37 import org.sonar.server.computation.task.projectanalysis.metric.MetricRepositoryRule;
38 import org.sonar.server.computation.task.projectanalysis.period.Period;
39 import org.sonar.server.computation.task.projectanalysis.period.PeriodsHolderRule;
40
41 import static org.assertj.core.api.Assertions.assertThat;
42 import static org.assertj.guava.api.Assertions.assertThat;
43 import static org.sonar.api.measures.CoreMetrics.LINES_KEY;
44 import static org.sonar.api.measures.CoreMetrics.NCLOC_KEY;
45 import static org.sonar.api.measures.CoreMetrics.NEW_COVERAGE_KEY;
46 import static org.sonar.api.measures.CoreMetrics.NEW_LINES_TO_COVER_KEY;
47 import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.PROJECT_VIEW;
48 import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.SUBVIEW;
49 import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.VIEW;
50 import static org.sonar.server.computation.task.projectanalysis.component.ViewsComponent.builder;
51 import static org.sonar.server.computation.task.projectanalysis.measure.Measure.newMeasureBuilder;
52 import static org.sonar.server.computation.task.projectanalysis.measure.MeasureRepoEntry.entryOf;
53 import static org.sonar.server.computation.task.projectanalysis.measure.MeasureRepoEntry.toEntries;
54
55 public class ViewsFormulaExecutorComponentVisitorTest {
56   private static final int ROOT_REF = 1;
57   private static final int SUBVIEW_1_REF = 11;
58   private static final int SUB_SUBVIEW_REF = 111;
59   private static final int PROJECT_VIEW_1_REF = 1111;
60   private static final int PROJECT_VIEW_2_REF = 1113;
61   private static final int SUBVIEW_2_REF = 12;
62   private static final int PROJECT_VIEW_3_REF = 121;
63   private static final int PROJECT_VIEW_4_REF = 13;
64
65   private static final ViewsComponent BALANCED_COMPONENT_TREE = ViewsComponent.builder(VIEW, ROOT_REF)
66     .addChildren(
67       ViewsComponent.builder(SUBVIEW, SUBVIEW_1_REF)
68         .addChildren(
69           ViewsComponent.builder(SUBVIEW, SUB_SUBVIEW_REF)
70             .addChildren(
71               builder(PROJECT_VIEW, PROJECT_VIEW_1_REF).build(),
72               builder(PROJECT_VIEW, PROJECT_VIEW_2_REF).build())
73             .build())
74         .build(),
75       ViewsComponent.builder(SUBVIEW, SUBVIEW_2_REF)
76         .addChildren(
77           builder(PROJECT_VIEW, PROJECT_VIEW_3_REF).build())
78         .build(),
79       builder(PROJECT_VIEW, PROJECT_VIEW_4_REF).build())
80     .build();
81
82   @Rule
83   public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
84   @Rule
85   public MetricRepositoryRule metricRepository = new MetricRepositoryRule()
86     .add(CoreMetrics.LINES)
87     .add(CoreMetrics.NCLOC)
88     .add(CoreMetrics.NEW_LINES_TO_COVER)
89     .add(CoreMetrics.NEW_COVERAGE);
90   @Rule
91   public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository);
92   @Rule
93   public PeriodsHolderRule periodsHolder = new PeriodsHolderRule()
94     .setPeriods(new Period(2, "some mode", null, 95l, "u1"), new Period(5, "some other mode", null, 756L, "u2"));
95
96   @Test
97   public void verify_aggregation_on_value() throws Exception {
98     treeRootHolder.setRoot(BALANCED_COMPONENT_TREE);
99     addRawMeasure(PROJECT_VIEW_1_REF, 1, LINES_KEY);
100     addRawMeasure(PROJECT_VIEW_2_REF, 2, LINES_KEY);
101     addRawMeasure(PROJECT_VIEW_3_REF, 3, LINES_KEY);
102     addRawMeasure(PROJECT_VIEW_4_REF, 4, LINES_KEY);
103
104     new PathAwareCrawler<>(formulaExecutorComponentVisitor(new FakeFormula()))
105       .visit(BALANCED_COMPONENT_TREE);
106
107     verifyProjectViewsHasNoAddedRawMeasures();
108     verifySingleMetricValue(SUB_SUBVIEW_REF, 3);
109     verifySingleMetricValue(SUBVIEW_1_REF, 3);
110     verifySingleMetricValue(SUBVIEW_2_REF, 3);
111     verifySingleMetricValue(ROOT_REF, 10);
112   }
113
114   private MeasureRepositoryRule addRawMeasure(int componentRef, int value, String metricKey) {
115     return measureRepository.addRawMeasure(componentRef, metricKey, newMeasureBuilder().create(value));
116   }
117
118   @Test
119   public void verify_multi_metric_formula_support_and_aggregation() throws Exception {
120     treeRootHolder.setRoot(BALANCED_COMPONENT_TREE);
121     addRawMeasure(PROJECT_VIEW_1_REF, 1, LINES_KEY);
122     addRawMeasure(PROJECT_VIEW_2_REF, 2, LINES_KEY);
123     addRawMeasure(PROJECT_VIEW_3_REF, 5, LINES_KEY);
124     addRawMeasure(PROJECT_VIEW_4_REF, 4, LINES_KEY);
125
126     new PathAwareCrawler<>(formulaExecutorComponentVisitor(new FakeMultiMetricFormula()))
127       .visit(BALANCED_COMPONENT_TREE);
128
129     verifyProjectViewsHasNoAddedRawMeasures();
130     verifyMultiMetricValues(SUB_SUBVIEW_REF, 13, 103);
131     verifyMultiMetricValues(SUBVIEW_1_REF, 13, 103);
132     verifyMultiMetricValues(SUBVIEW_2_REF, 15, 105);
133     verifyMultiMetricValues(ROOT_REF, 22, 112);
134   }
135
136   @Test
137   public void verify_aggregation_on_variations() throws Exception {
138     treeRootHolder.setRoot(BALANCED_COMPONENT_TREE);
139
140     addRawMeasureWithVariation(PROJECT_VIEW_1_REF, NEW_LINES_TO_COVER_KEY, 10, 20);
141     addRawMeasureWithVariation(PROJECT_VIEW_2_REF, NEW_LINES_TO_COVER_KEY, 8, 16);
142     addRawMeasureWithVariation(PROJECT_VIEW_3_REF, NEW_LINES_TO_COVER_KEY, 2, 4);
143     addRawMeasureWithVariation(PROJECT_VIEW_4_REF, NEW_LINES_TO_COVER_KEY, 3, 7);
144
145     new PathAwareCrawler<>(formulaExecutorComponentVisitor(new FakeVariationFormula()))
146       .visit(BALANCED_COMPONENT_TREE);
147
148     verifyProjectViewsHasNoAddedRawMeasures();
149     verifySingleMetricWithVariations(SUB_SUBVIEW_REF, 18, 36);
150     verifySingleMetricWithVariations(SUBVIEW_1_REF, 18, 36);
151     verifySingleMetricWithVariations(SUBVIEW_2_REF, 2, 4);
152     verifySingleMetricWithVariations(ROOT_REF, 23, 47);
153   }
154
155   private AbstractIterableAssert<?, ? extends Iterable<? extends MeasureRepoEntry>, MeasureRepoEntry> verifySingleMetricWithVariations(int componentRef, int variation2Value,
156     int variation5Value) {
157     return assertThat(toEntries(measureRepository.getAddedRawMeasures(componentRef)))
158       .containsOnly(entryOf(NEW_COVERAGE_KEY, createMeasureWithVariation(variation2Value, variation5Value)));
159   }
160
161   private MeasureRepositoryRule addRawMeasureWithVariation(int componentRef, String metricKey, int variation2Value, int variation5Value) {
162     return measureRepository.addRawMeasure(componentRef, metricKey, createMeasureWithVariation(variation2Value, variation5Value));
163   }
164
165   private static Measure createMeasureWithVariation(double variation2Value, double variation5Value) {
166     return newMeasureBuilder().setVariations(new MeasureVariations(null, variation2Value, null, null, variation5Value)).createNoValue();
167   }
168
169   @Test
170   public void verify_no_measure_added_on_projectView() throws Exception {
171     ViewsComponent project = ViewsComponent.builder(VIEW, ROOT_REF)
172       .addChildren(
173         ViewsComponent.builder(SUBVIEW, SUBVIEW_1_REF)
174           .addChildren(
175             ViewsComponent.builder(SUBVIEW, SUB_SUBVIEW_REF)
176               .addChildren(
177                 builder(PROJECT_VIEW, PROJECT_VIEW_1_REF).build())
178               .build())
179           .build())
180       .build();
181     treeRootHolder.setRoot(project);
182
183     new PathAwareCrawler<>(formulaExecutorComponentVisitor(new FakeFormula()))
184       .visit(project);
185
186     assertNoAddedRawMeasure(PROJECT_VIEW_1_REF);
187     verifySingleMetricValue(SUB_SUBVIEW_REF, 0);
188     verifySingleMetricValue(SUBVIEW_1_REF, 0);
189     verifySingleMetricValue(ROOT_REF, 0);
190   }
191
192   @Test
193   public void add_measure_even_if_leaf_is_not_a_PROJECT_VIEW() throws Exception {
194     ViewsComponent project = ViewsComponent.builder(VIEW, ROOT_REF)
195       .addChildren(
196         ViewsComponent.builder(SUBVIEW, SUBVIEW_1_REF)
197           .addChildren(
198             ViewsComponent.builder(SUBVIEW, SUB_SUBVIEW_REF).build())
199           .build())
200       .build();
201     treeRootHolder.setRoot(project);
202
203     new PathAwareCrawler<>(formulaExecutorComponentVisitor(new FakeFormula()))
204       .visit(project);
205
206     verifySingleMetricValue(SUB_SUBVIEW_REF, 0);
207     verifySingleMetricValue(SUBVIEW_1_REF, 0);
208     verifySingleMetricValue(ROOT_REF, 0);
209   }
210
211   private class FakeFormula implements Formula<FakeCounter> {
212
213     @Override
214     public FakeCounter createNewCounter() {
215       return new FakeCounter();
216     }
217
218     @Override
219     public Optional<Measure> createMeasure(FakeCounter counter, CreateMeasureContext context) {
220       // verify the context which is passed to the method
221       assertThat(context.getPeriods()).isEqualTo(periodsHolder.getPeriods());
222       assertThat(context.getComponent()).isNotNull();
223       assertThat(context.getMetric()).isSameAs(metricRepository.getByKey(NCLOC_KEY));
224
225       return Optional.of(Measure.newMeasureBuilder().create(counter.value));
226     }
227
228     @Override
229     public String[] getOutputMetricKeys() {
230       return new String[] {NCLOC_KEY};
231     }
232   }
233
234   private class FakeMultiMetricFormula implements Formula<FakeCounter> {
235
236     @Override
237     public FakeCounter createNewCounter() {
238       return new FakeCounter();
239     }
240
241     @Override
242     public Optional<Measure> createMeasure(FakeCounter counter, CreateMeasureContext context) {
243       // verify the context which is passed to the method
244       assertThat(context.getPeriods()).isEqualTo(periodsHolder.getPeriods());
245       assertThat(context.getComponent()).isNotNull();
246       assertThat(context.getMetric())
247         .isIn(metricRepository.getByKey(NEW_LINES_TO_COVER_KEY), metricRepository.getByKey(NEW_COVERAGE_KEY));
248
249       return Optional.of(Measure.newMeasureBuilder().create(counter.value + metricOffset(context.getMetric())));
250     }
251
252     private int metricOffset(Metric metric) {
253       if (metric.getKey().equals(NEW_LINES_TO_COVER_KEY)) {
254         return 10;
255       }
256       if (metric.getKey().equals(NEW_COVERAGE_KEY)) {
257         return 100;
258       }
259       throw new IllegalArgumentException("Unsupported metric " + metric);
260     }
261
262     @Override
263     public String[] getOutputMetricKeys() {
264       return new String[] {NEW_LINES_TO_COVER_KEY, NEW_COVERAGE_KEY};
265     }
266   }
267
268   private class FakeCounter implements Counter<FakeCounter> {
269     private int value = 0;
270
271     @Override
272     public void aggregate(FakeCounter counter) {
273       this.value += counter.value;
274     }
275
276     @Override
277     public void initialize(CounterInitializationContext context) {
278       verifyLeafContext(context);
279
280       Optional<Measure> measureOptional = context.getMeasure(LINES_KEY);
281       if (measureOptional.isPresent()) {
282         value += measureOptional.get().getIntValue();
283       }
284     }
285   }
286
287   private class FakeVariationFormula implements Formula<FakeVariationCounter> {
288
289     @Override
290     public FakeVariationCounter createNewCounter() {
291       return new FakeVariationCounter();
292     }
293
294     @Override
295     public Optional<Measure> createMeasure(FakeVariationCounter counter, CreateMeasureContext context) {
296       // verify the context which is passed to the method
297       assertThat(context.getPeriods()).isEqualTo(periodsHolder.getPeriods());
298       assertThat(context.getComponent()).isNotNull();
299       assertThat(context.getMetric()).isSameAs(metricRepository.getByKey(NEW_COVERAGE_KEY));
300
301       Optional<MeasureVariations> measureVariations = counter.values.toMeasureVariations();
302       if (measureVariations.isPresent()) {
303         return Optional.of(
304           newMeasureBuilder()
305             .setVariations(measureVariations.get())
306             .createNoValue());
307       }
308       return Optional.absent();
309     }
310
311     @Override
312     public String[] getOutputMetricKeys() {
313       return new String[] {NEW_COVERAGE_KEY};
314     }
315   }
316
317   private class FakeVariationCounter implements Counter<FakeVariationCounter> {
318     private final IntVariationValue.Array values = IntVariationValue.newArray();
319
320     @Override
321     public void aggregate(FakeVariationCounter counter) {
322       values.incrementAll(counter.values);
323     }
324
325     @Override
326     public void initialize(CounterInitializationContext context) {
327       verifyLeafContext(context);
328
329       Optional<Measure> measureOptional = context.getMeasure(NEW_LINES_TO_COVER_KEY);
330       if (!measureOptional.isPresent()) {
331         return;
332       }
333       for (Period period : context.getPeriods()) {
334         this.values.increment(
335           period,
336           (int) measureOptional.get().getVariations().getVariation(period.getIndex()));
337       }
338     }
339   }
340
341   private FormulaExecutorComponentVisitor formulaExecutorComponentVisitor(Formula formula) {
342     return FormulaExecutorComponentVisitor.newBuilder(metricRepository, measureRepository)
343       .withVariationSupport(periodsHolder)
344       .buildFor(ImmutableList.of(formula));
345   }
346
347   private void verifyProjectViewsHasNoAddedRawMeasures() {
348     assertNoAddedRawMeasure(PROJECT_VIEW_1_REF);
349     assertNoAddedRawMeasure(PROJECT_VIEW_2_REF);
350     assertNoAddedRawMeasure(PROJECT_VIEW_3_REF);
351     assertNoAddedRawMeasure(PROJECT_VIEW_4_REF);
352   }
353
354   private void assertNoAddedRawMeasure(int componentRef) {
355     assertThat(measureRepository.getAddedRawMeasures(componentRef)).isEmpty();
356   }
357
358   private void verifySingleMetricValue(int componentRef, int measureValue) {
359     assertThat(toEntries(measureRepository.getAddedRawMeasures(componentRef)))
360       .containsOnly(entryOf(NCLOC_KEY, newMeasureBuilder().create(measureValue)));
361   }
362
363   private void verifyMultiMetricValues(int componentRef, int valueLinesToCover, int valueItCoverage) {
364     assertThat(toEntries(measureRepository.getAddedRawMeasures(componentRef)))
365       .containsOnly(
366         entryOf(NEW_LINES_TO_COVER_KEY, newMeasureBuilder().create(valueLinesToCover)),
367         entryOf(NEW_COVERAGE_KEY, newMeasureBuilder().create(valueItCoverage)));
368   }
369
370   private void verifyLeafContext(CounterInitializationContext context) {
371     assertThat(context.getLeaf().getChildren()).isEmpty();
372     assertThat(context.getPeriods()).isEqualTo(periodsHolder.getPeriods());
373   }
374
375 }