]> source.dussan.org Git - sonarqube.git/blob
3437d47c9bd20b2563e52f13e716f2948b5621f6
[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.junit.Rule;
25 import org.junit.Test;
26 import org.sonar.api.measures.CoreMetrics;
27 import org.sonar.server.computation.task.projectanalysis.component.Component;
28 import org.sonar.server.computation.task.projectanalysis.component.PathAwareCrawler;
29 import org.sonar.server.computation.task.projectanalysis.component.ReportComponent;
30 import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolderRule;
31 import org.sonar.server.computation.task.projectanalysis.formula.counter.IntValue;
32 import org.sonar.server.computation.task.projectanalysis.measure.Measure;
33 import org.sonar.server.computation.task.projectanalysis.measure.MeasureRepositoryRule;
34 import org.sonar.server.computation.task.projectanalysis.metric.Metric;
35 import org.sonar.server.computation.task.projectanalysis.metric.MetricRepositoryRule;
36 import org.sonar.server.computation.task.projectanalysis.period.Period;
37 import org.sonar.server.computation.task.projectanalysis.period.PeriodsHolderRule;
38
39 import static org.assertj.core.api.Assertions.assertThat;
40 import static org.sonar.api.measures.CoreMetrics.LINES_KEY;
41 import static org.sonar.api.measures.CoreMetrics.NCLOC_KEY;
42 import static org.sonar.api.measures.CoreMetrics.NEW_COVERAGE_KEY;
43 import static org.sonar.api.measures.CoreMetrics.NEW_LINES_TO_COVER_KEY;
44 import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.DIRECTORY;
45 import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.MODULE;
46 import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.PROJECT;
47 import static org.sonar.server.computation.task.projectanalysis.component.ReportComponent.builder;
48 import static org.sonar.server.computation.task.projectanalysis.measure.Measure.newMeasureBuilder;
49 import static org.sonar.server.computation.task.projectanalysis.measure.MeasureRepoEntry.entryOf;
50 import static org.sonar.server.computation.task.projectanalysis.measure.MeasureRepoEntry.toEntries;
51
52 public class ReportFormulaExecutorComponentVisitorTest {
53   private static final int ROOT_REF = 1;
54   private static final int MODULE_1_REF = 11;
55   private static final int DIRECTORY_1_REF = 111;
56   private static final int FILE_1_REF = 1111;
57   private static final int FILE_2_REF = 1112;
58   private static final int MODULE_2_REF = 12;
59   private static final int DIRECTORY_2_REF = 121;
60   private static final int FILE_3_REF = 1211;
61
62   private static final ReportComponent BALANCED_COMPONENT_TREE = ReportComponent.builder(PROJECT, ROOT_REF)
63     .addChildren(
64       ReportComponent.builder(MODULE, MODULE_1_REF)
65         .addChildren(
66           ReportComponent.builder(DIRECTORY, DIRECTORY_1_REF)
67             .addChildren(
68               builder(Component.Type.FILE, FILE_1_REF).build(),
69               builder(Component.Type.FILE, FILE_2_REF).build())
70             .build())
71         .build(),
72       ReportComponent.builder(MODULE, MODULE_2_REF)
73         .addChildren(
74           ReportComponent.builder(DIRECTORY, DIRECTORY_2_REF)
75             .addChildren(
76               builder(Component.Type.FILE, FILE_3_REF).build())
77             .build())
78         .build())
79     .build();
80
81   @Rule
82   public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
83   @Rule
84   public MetricRepositoryRule metricRepository = new MetricRepositoryRule()
85     .add(CoreMetrics.LINES)
86     .add(CoreMetrics.NCLOC)
87     .add(CoreMetrics.NEW_LINES_TO_COVER)
88     .add(CoreMetrics.NEW_COVERAGE);
89   @Rule
90   public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository);
91   @Rule
92   public PeriodsHolderRule periodsHolder = new PeriodsHolderRule().setPeriod(new Period("some mode", null, 95l, "756l"));
93
94   @Test
95   public void verify_aggregation_on_value() throws Exception {
96     treeRootHolder.setRoot(BALANCED_COMPONENT_TREE);
97
98     measureRepository.addRawMeasure(FILE_1_REF, LINES_KEY, newMeasureBuilder().create(10));
99     measureRepository.addRawMeasure(FILE_2_REF, LINES_KEY, newMeasureBuilder().create(8));
100     measureRepository.addRawMeasure(FILE_3_REF, LINES_KEY, newMeasureBuilder().create(2));
101
102     new PathAwareCrawler<>(formulaExecutorComponentVisitor(new FakeFormula()))
103       .visit(BALANCED_COMPONENT_TREE);
104
105     assertAddedRawMeasure(ROOT_REF, 20);
106     assertAddedRawMeasure(MODULE_1_REF, 18);
107     assertAddedRawMeasure(111, 18);
108     assertAddedRawMeasure(FILE_1_REF, 10);
109     assertAddedRawMeasure(FILE_2_REF, 8);
110     assertAddedRawMeasure(MODULE_2_REF, 2);
111     assertAddedRawMeasure(DIRECTORY_2_REF, 2);
112     assertAddedRawMeasure(FILE_3_REF, 2);
113   }
114
115   @Test
116   public void verify_multi_metric_formula_support_and_aggregation() throws Exception {
117     treeRootHolder.setRoot(BALANCED_COMPONENT_TREE);
118
119     measureRepository.addRawMeasure(FILE_1_REF, LINES_KEY, newMeasureBuilder().create(10));
120     measureRepository.addRawMeasure(FILE_2_REF, LINES_KEY, newMeasureBuilder().create(8));
121     measureRepository.addRawMeasure(FILE_3_REF, LINES_KEY, newMeasureBuilder().create(2));
122
123     new PathAwareCrawler<>(formulaExecutorComponentVisitor(new FakeMultiMetricFormula()))
124       .visit(BALANCED_COMPONENT_TREE);
125
126     assertThat(toEntries(measureRepository.getAddedRawMeasures(ROOT_REF))).containsOnly(
127       entryOf(NEW_LINES_TO_COVER_KEY, newMeasureBuilder().create(30)),
128       entryOf(NEW_COVERAGE_KEY, newMeasureBuilder().create(120)));
129     assertThat(toEntries(measureRepository.getAddedRawMeasures(MODULE_1_REF))).containsOnly(
130       entryOf(NEW_LINES_TO_COVER_KEY, newMeasureBuilder().create(28)),
131       entryOf(NEW_COVERAGE_KEY, newMeasureBuilder().create(118)));
132     assertThat(toEntries(measureRepository.getAddedRawMeasures(111))).containsOnly(
133       entryOf(NEW_LINES_TO_COVER_KEY, newMeasureBuilder().create(28)),
134       entryOf(NEW_COVERAGE_KEY, newMeasureBuilder().create(118)));
135     assertThat(toEntries(measureRepository.getAddedRawMeasures(FILE_1_REF))).containsOnly(
136       entryOf(NEW_LINES_TO_COVER_KEY, newMeasureBuilder().create(20)),
137       entryOf(NEW_COVERAGE_KEY, newMeasureBuilder().create(110)));
138     assertThat(toEntries(measureRepository.getAddedRawMeasures(FILE_2_REF))).containsOnly(
139       entryOf(NEW_LINES_TO_COVER_KEY, newMeasureBuilder().create(18)),
140       entryOf(NEW_COVERAGE_KEY, newMeasureBuilder().create(108)));
141     assertThat(toEntries(measureRepository.getAddedRawMeasures(MODULE_2_REF))).containsOnly(
142       entryOf(NEW_LINES_TO_COVER_KEY, newMeasureBuilder().create(MODULE_2_REF)),
143       entryOf(NEW_COVERAGE_KEY, newMeasureBuilder().create(102)));
144     assertThat(toEntries(measureRepository.getAddedRawMeasures(DIRECTORY_2_REF))).containsOnly(
145       entryOf(NEW_LINES_TO_COVER_KEY, newMeasureBuilder().create(MODULE_2_REF)),
146       entryOf(NEW_COVERAGE_KEY, newMeasureBuilder().create(102)));
147     assertThat(toEntries(measureRepository.getAddedRawMeasures(FILE_3_REF))).containsOnly(
148       entryOf(NEW_LINES_TO_COVER_KEY, newMeasureBuilder().create(MODULE_2_REF)),
149       entryOf(NEW_COVERAGE_KEY, newMeasureBuilder().create(102)));
150   }
151
152   @Test
153   public void verify_aggregation_on_variation() throws Exception {
154     treeRootHolder.setRoot(BALANCED_COMPONENT_TREE);
155
156     measureRepository.addRawMeasure(FILE_1_REF, NEW_LINES_TO_COVER_KEY, createMeasureWithVariation(10));
157     measureRepository.addRawMeasure(FILE_2_REF, NEW_LINES_TO_COVER_KEY, createMeasureWithVariation(8));
158     measureRepository.addRawMeasure(FILE_3_REF, NEW_LINES_TO_COVER_KEY, createMeasureWithVariation(2));
159
160     new PathAwareCrawler<>(formulaExecutorComponentVisitor(new FakeVariationFormula()))
161       .visit(BALANCED_COMPONENT_TREE);
162
163     assertAddedRawMeasureVariation(ROOT_REF, 20);
164     assertAddedRawMeasureVariation(MODULE_1_REF, 18);
165     assertAddedRawMeasureVariation(DIRECTORY_1_REF, 18);
166     assertAddedRawMeasureVariation(FILE_1_REF, 10);
167     assertAddedRawMeasureVariation(FILE_2_REF, 8);
168     assertAddedRawMeasureVariation(MODULE_2_REF, 2);
169     assertAddedRawMeasureVariation(DIRECTORY_2_REF, 2);
170     assertAddedRawMeasureVariation(FILE_3_REF, 2);
171   }
172
173   @Test
174   public void measures_are_0_when_there_is_no_input_measure() throws Exception {
175     ReportComponent project = ReportComponent.builder(PROJECT, ROOT_REF)
176       .addChildren(
177         ReportComponent.builder(MODULE, MODULE_1_REF)
178           .addChildren(
179             ReportComponent.builder(DIRECTORY, DIRECTORY_1_REF)
180               .addChildren(
181                 builder(Component.Type.FILE, FILE_1_REF).build())
182               .build())
183           .build())
184       .build();
185     treeRootHolder.setRoot(project);
186
187     new PathAwareCrawler<>(formulaExecutorComponentVisitor(new FakeFormula()))
188       .visit(project);
189
190     assertAddedRawMeasure(ROOT_REF, 0);
191     assertAddedRawMeasure(MODULE_1_REF, 0);
192     assertAddedRawMeasure(DIRECTORY_1_REF, 0);
193     assertAddedRawMeasure(FILE_1_REF, 0);
194   }
195
196   @Test
197   public void add_measure_even_when_leaf_is_not_FILE() throws Exception {
198     ReportComponent project = ReportComponent.builder(PROJECT, ROOT_REF)
199       .addChildren(
200         ReportComponent.builder(MODULE, MODULE_1_REF)
201           .addChildren(
202             ReportComponent.builder(DIRECTORY, 111).build())
203           .build())
204       .build();
205     treeRootHolder.setRoot(project);
206
207     new PathAwareCrawler<>(formulaExecutorComponentVisitor(new FakeFormula()))
208       .visit(project);
209
210     assertAddedRawMeasure(MODULE_1_REF, 0);
211     assertAddedRawMeasure(DIRECTORY_1_REF, 0);
212   }
213
214   private FormulaExecutorComponentVisitor formulaExecutorComponentVisitor(Formula formula) {
215     return FormulaExecutorComponentVisitor.newBuilder(metricRepository, measureRepository)
216       .withVariationSupport(periodsHolder)
217       .buildFor(ImmutableList.of(formula));
218   }
219
220   private static Measure createMeasureWithVariation(double variation) {
221     return newMeasureBuilder().setVariation(variation).createNoValue();
222   }
223
224   private void assertAddedRawMeasure(int componentRef, int expectedValue) {
225     assertThat(toEntries(measureRepository.getAddedRawMeasures(componentRef))).containsOnly(entryOf(NCLOC_KEY, newMeasureBuilder().create(expectedValue)));
226   }
227
228   private void assertAddedRawMeasureVariation(int componentRef, int variation) {
229     assertThat(toEntries(measureRepository.getAddedRawMeasures(componentRef)))
230       .containsOnly(entryOf(NEW_COVERAGE_KEY, createMeasureWithVariation(variation)));
231   }
232
233   private class FakeFormula implements Formula<FakeCounter> {
234
235     @Override
236     public FakeCounter createNewCounter() {
237       return new FakeCounter();
238     }
239
240     @Override
241     public Optional<Measure> createMeasure(FakeCounter counter, CreateMeasureContext context) {
242       // verify the context which is passed to the method
243       assertThat(context.getPeriods()).isEqualTo(periodsHolder.getPeriods());
244       assertThat(context.getComponent()).isNotNull();
245       assertThat(context.getMetric()).isSameAs(metricRepository.getByKey(NCLOC_KEY));
246
247       return Optional.of(Measure.newMeasureBuilder().create(counter.value));
248     }
249
250     @Override
251     public String[] getOutputMetricKeys() {
252       return new String[] {NCLOC_KEY};
253     }
254   }
255
256   private class FakeMultiMetricFormula implements Formula<FakeCounter> {
257
258     @Override
259     public FakeCounter createNewCounter() {
260       return new FakeCounter();
261     }
262
263     @Override
264     public Optional<Measure> createMeasure(FakeCounter counter, CreateMeasureContext context) {
265       // verify the context which is passed to the method
266       assertThat(context.getPeriod()).isEqualTo(periodsHolder.getPeriod());
267       assertThat(context.getComponent()).isNotNull();
268       assertThat(context.getMetric())
269         .isIn(metricRepository.getByKey(NEW_LINES_TO_COVER_KEY), metricRepository.getByKey(NEW_COVERAGE_KEY));
270
271       return Optional.of(Measure.newMeasureBuilder().create(counter.value + metricOffset(context.getMetric())));
272     }
273
274     private int metricOffset(Metric metric) {
275       if (metric.getKey().equals(NEW_LINES_TO_COVER_KEY)) {
276         return 10;
277       }
278       if (metric.getKey().equals(NEW_COVERAGE_KEY)) {
279         return 100;
280       }
281       throw new IllegalArgumentException("Unsupported metric " + metric);
282     }
283
284     @Override
285     public String[] getOutputMetricKeys() {
286       return new String[] {NEW_LINES_TO_COVER_KEY, NEW_COVERAGE_KEY};
287     }
288   }
289
290   private class FakeCounter implements Counter<FakeCounter> {
291     private int value = 0;
292
293     @Override
294     public void aggregate(FakeCounter counter) {
295       this.value += counter.value;
296     }
297
298     @Override
299     public void initialize(CounterInitializationContext context) {
300       // verify the context which is passed to the method
301       assertThat(context.getLeaf().getChildren()).isEmpty();
302       assertThat(context.getPeriod()).isEqualTo(periodsHolder.getPeriod());
303
304       Optional<Measure> measureOptional = context.getMeasure(LINES_KEY);
305       if (measureOptional.isPresent()) {
306         value += measureOptional.get().getIntValue();
307       }
308     }
309   }
310
311   private class FakeVariationFormula implements Formula<FakeVariationCounter> {
312
313     @Override
314     public FakeVariationCounter createNewCounter() {
315       return new FakeVariationCounter();
316     }
317
318     @Override
319     public Optional<Measure> createMeasure(FakeVariationCounter counter, CreateMeasureContext context) {
320       // verify the context which is passed to the method
321       assertThat(context.getPeriod()).isEqualTo(periodsHolder.getPeriod());
322       assertThat(context.getComponent()).isNotNull();
323       assertThat(context.getMetric()).isSameAs(metricRepository.getByKey(NEW_COVERAGE_KEY));
324
325       IntValue measureVariations = counter.values;
326       if (measureVariations.isSet()) {
327         return Optional.of(
328           newMeasureBuilder()
329             .setVariation(measureVariations.getValue())
330             .createNoValue());
331       }
332       return Optional.absent();
333     }
334
335     @Override
336     public String[] getOutputMetricKeys() {
337       return new String[] {NEW_COVERAGE_KEY};
338     }
339   }
340
341   private class FakeVariationCounter implements Counter<FakeVariationCounter> {
342     private final IntValue values = new IntValue();
343
344     @Override
345     public void aggregate(FakeVariationCounter counter) {
346       values.increment(counter.values);
347     }
348
349     @Override
350     public void initialize(CounterInitializationContext context) {
351       // verify the context which is passed to the method
352       assertThat(context.getLeaf().getChildren()).isEmpty();
353       assertThat(context.getPeriod()).isEqualTo(periodsHolder.getPeriod());
354
355       Optional<Measure> measureOptional = context.getMeasure(NEW_LINES_TO_COVER_KEY);
356       if (!measureOptional.isPresent() || !context.hasPeriod()) {
357         return;
358       }
359       this.values.increment((int) measureOptional.get().getVariation());
360     }
361   }
362
363 }