]> source.dussan.org Git - sonarqube.git/blob
5900f768b8be2626e2f34c44b57015bf235e54a9
[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.step;
21
22 import com.google.common.base.Optional;
23 import java.util.Collections;
24 import java.util.Map;
25 import java.util.Objects;
26 import javax.annotation.Nullable;
27 import org.assertj.core.api.AbstractAssert;
28 import org.junit.Before;
29 import org.junit.Rule;
30 import org.junit.Test;
31 import org.junit.rules.ExpectedException;
32 import org.mockito.invocation.InvocationOnMock;
33 import org.mockito.stubbing.Answer;
34 import org.sonar.api.measures.CoreMetrics;
35 import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolderRule;
36 import org.sonar.server.computation.task.projectanalysis.component.Component;
37 import org.sonar.server.computation.task.projectanalysis.component.ReportComponent;
38 import org.sonar.server.computation.task.projectanalysis.measure.Measure;
39 import org.sonar.server.computation.task.projectanalysis.measure.MeasureRepositoryRule;
40 import org.sonar.server.computation.task.projectanalysis.measure.qualitygatedetails.EvaluatedCondition;
41 import org.sonar.server.computation.task.projectanalysis.measure.qualitygatedetails.QualityGateDetailsData;
42 import org.sonar.server.computation.task.projectanalysis.metric.Metric;
43 import org.sonar.server.computation.task.projectanalysis.metric.MetricImpl;
44 import org.sonar.server.computation.task.projectanalysis.metric.MetricRepositoryRule;
45 import org.sonar.server.computation.task.projectanalysis.period.Period;
46 import org.sonar.server.computation.task.projectanalysis.qualitygate.Condition;
47 import org.sonar.server.computation.task.projectanalysis.qualitygate.ConditionStatus;
48 import org.sonar.server.computation.task.projectanalysis.qualitygate.EvaluationResult;
49 import org.sonar.server.computation.task.projectanalysis.qualitygate.EvaluationResultTextConverter;
50 import org.sonar.server.computation.task.projectanalysis.qualitygate.MutableQualityGateStatusHolderRule;
51 import org.sonar.server.computation.task.projectanalysis.qualitygate.QualityGate;
52 import org.sonar.server.computation.task.projectanalysis.qualitygate.QualityGateHolderRule;
53 import org.sonar.server.computation.task.projectanalysis.qualitygate.QualityGateStatus;
54 import org.sonar.server.computation.task.projectanalysis.qualitygate.QualityGateStatusHolder;
55
56 import static com.google.common.collect.ImmutableList.of;
57 import static org.mockito.Matchers.any;
58 import static org.mockito.Mockito.mock;
59 import static org.mockito.Mockito.when;
60 import static org.sonar.api.measures.CoreMetrics.ALERT_STATUS_KEY;
61 import static org.sonar.server.computation.task.projectanalysis.measure.Measure.Level.ERROR;
62 import static org.sonar.server.computation.task.projectanalysis.measure.Measure.Level.OK;
63 import static org.sonar.server.computation.task.projectanalysis.measure.Measure.Level.WARN;
64 import static org.sonar.server.computation.task.projectanalysis.measure.Measure.newMeasureBuilder;
65 import static org.sonar.server.computation.task.projectanalysis.measure.MeasureAssert.assertThat;
66 import static org.sonar.server.computation.task.projectanalysis.measure.MeasureVariations.newMeasureVariationsBuilder;
67
68 public class QualityGateMeasuresStepTest {
69   private static final MetricImpl INT_METRIC_1 = createIntMetric(1);
70   private static final String INT_METRIC_1_KEY = INT_METRIC_1.getKey();
71   private static final MetricImpl INT_METRIC_2 = createIntMetric(2);
72   private static final String INT_METRIC_2_KEY = INT_METRIC_2.getKey();
73
74   private static final int PROJECT_REF = 1;
75   private static final ReportComponent PROJECT_COMPONENT = ReportComponent.builder(Component.Type.PROJECT, PROJECT_REF).build();
76   private static final long SOME_QG_ID = 7521551;
77   private static final String SOME_QG_NAME = "name";
78
79   @Rule
80   public ExpectedException expectedException = ExpectedException.none();
81   @Rule
82   public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
83   @Rule
84   public QualityGateHolderRule qualityGateHolder = new QualityGateHolderRule();
85   @Rule
86   public MutableQualityGateStatusHolderRule qualityGateStatusHolder = new MutableQualityGateStatusHolderRule();
87   @Rule
88   public MetricRepositoryRule metricRepository = new MetricRepositoryRule();
89   @Rule
90   public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository);
91
92   private EvaluationResultTextConverter resultTextConverter = mock(EvaluationResultTextConverter.class);
93   private QualityGateMeasuresStep underTest = new QualityGateMeasuresStep(treeRootHolder, qualityGateHolder, qualityGateStatusHolder, measureRepository, metricRepository,
94     resultTextConverter);
95
96   @Before
97   public void setUp() {
98     metricRepository
99       .add(CoreMetrics.ALERT_STATUS)
100       .add(CoreMetrics.QUALITY_GATE_DETAILS)
101       .add(INT_METRIC_1)
102       .add(INT_METRIC_2);
103     treeRootHolder.setRoot(PROJECT_COMPONENT);
104
105     // mock response of asText to any argument to return the result of dumbResultTextAnswer method
106     when(resultTextConverter.asText(any(Condition.class), any(EvaluationResult.class))).thenAnswer(new Answer<String>() {
107       @Override
108       public String answer(InvocationOnMock invocation) throws Throwable {
109         Condition condition = (Condition) invocation.getArguments()[0];
110         EvaluationResult evaluationResult = (EvaluationResult) invocation.getArguments()[1];
111         return dumbResultTextAnswer(condition, evaluationResult.getLevel(), evaluationResult.getValue());
112       }
113     });
114   }
115
116   private static String dumbResultTextAnswer(Condition condition, Measure.Level level, Object value) {
117     return condition.toString() + level + value;
118   }
119
120   @Test
121   public void no_measure_if_tree_has_no_project() {
122     ReportComponent notAProjectComponent = ReportComponent.builder(Component.Type.MODULE, 1).build();
123
124     treeRootHolder.setRoot(notAProjectComponent);
125
126     underTest.execute();
127
128     measureRepository.getAddedRawMeasures(1).isEmpty();
129   }
130
131   @Test
132   public void no_measure_if_there_is_no_qualitygate() {
133     qualityGateHolder.setQualityGate(null);
134
135     underTest.execute();
136
137     measureRepository.getAddedRawMeasures(PROJECT_COMPONENT).isEmpty();
138   }
139
140   @Test
141   public void mutableQualityGateStatusHolder_is_not_populated_if_there_is_no_qualitygate() {
142     qualityGateHolder.setQualityGate(null);
143
144     underTest.execute();
145
146     expectedException.expect(IllegalStateException.class);
147     expectedException.expectMessage("Quality gate status has not been set yet");
148
149     qualityGateStatusHolder.getStatus();
150   }
151
152   @Test
153   public void new_measures_are_created_even_if_there_is_no_rawMeasure_for_metric_of_condition() {
154     Condition equals2Condition = createEqualsCondition(INT_METRIC_1, "2", null);
155     qualityGateHolder.setQualityGate(new QualityGate(SOME_QG_ID, SOME_QG_NAME, of(equals2Condition)));
156
157     underTest.execute();
158
159     Optional<Measure> addedRawMeasure = measureRepository.getAddedRawMeasure(PROJECT_COMPONENT, INT_METRIC_1_KEY);
160
161     assertThat(addedRawMeasure).isAbsent();
162     assertThat(getAlertStatusMeasure())
163       .hasQualityGateLevel(OK)
164       .hasQualityGateText("");
165     assertThat(getQGDetailsMeasure())
166       .hasValue(new QualityGateDetailsData(OK, Collections.<EvaluatedCondition>emptyList()).toJson());
167
168     QualityGateStatusHolderAssertions.assertThat(qualityGateStatusHolder)
169       .hasStatus(QualityGateStatus.OK)
170       .hasConditionCount(1)
171       .hasCondition(equals2Condition, ConditionStatus.EvaluationStatus.NO_VALUE, null);
172   }
173
174   @Test
175   public void rawMeasure_is_updated_if_present_and_new_measures_are_created_if_project_has_measure_for_metric_of_condition() {
176     int rawValue = 1;
177     Condition equals2Condition = createEqualsCondition(INT_METRIC_1, "2", null);
178     Measure rawMeasure = newMeasureBuilder().create(rawValue, null);
179
180     qualityGateHolder.setQualityGate(new QualityGate(SOME_QG_ID, SOME_QG_NAME, of(equals2Condition)));
181     measureRepository.addRawMeasure(PROJECT_REF, INT_METRIC_1_KEY, rawMeasure);
182
183     underTest.execute();
184
185     Optional<Measure> addedRawMeasure = measureRepository.getAddedRawMeasure(PROJECT_COMPONENT, INT_METRIC_1_KEY);
186
187     assertThat(addedRawMeasure)
188       .hasQualityGateLevel(OK)
189       .hasQualityGateText(dumbResultTextAnswer(equals2Condition, OK, rawValue));
190     assertThat(getAlertStatusMeasure())
191       .hasQualityGateLevel(OK)
192       .hasQualityGateText(dumbResultTextAnswer(equals2Condition, OK, rawValue));
193     assertThat(getQGDetailsMeasure().get())
194       .hasValue(new QualityGateDetailsData(OK, of(new EvaluatedCondition(equals2Condition, OK, rawValue))).toJson());
195
196     QualityGateStatusHolderAssertions.assertThat(qualityGateStatusHolder)
197       .hasStatus(QualityGateStatus.OK)
198       .hasConditionCount(1)
199       .hasCondition(equals2Condition, ConditionStatus.EvaluationStatus.OK, String.valueOf(rawValue));
200   }
201
202   @Test
203   public void new_measures_have_ERROR_level_if_at_least_one_updated_measure_has_ERROR_level() {
204     int rawValue = 1;
205     Condition equals1ErrorCondition = createEqualsCondition(INT_METRIC_1, "1", null);
206     Condition equals1WarningCondition = createEqualsCondition(INT_METRIC_2, null, "1");
207     Measure rawMeasure = newMeasureBuilder().create(rawValue, null);
208
209     qualityGateHolder.setQualityGate(new QualityGate(SOME_QG_ID, SOME_QG_NAME, of(equals1ErrorCondition, equals1WarningCondition)));
210     measureRepository.addRawMeasure(PROJECT_REF, INT_METRIC_1_KEY, rawMeasure);
211     measureRepository.addRawMeasure(PROJECT_REF, INT_METRIC_2_KEY, rawMeasure);
212
213     underTest.execute();
214
215     Optional<Measure> rawMeasure1 = measureRepository.getAddedRawMeasure(PROJECT_REF, INT_METRIC_1_KEY);
216     Optional<Measure> rawMeasure2 = measureRepository.getAddedRawMeasure(PROJECT_REF, INT_METRIC_2_KEY);
217
218     assertThat(rawMeasure1.get())
219       .hasQualityGateLevel(ERROR)
220       .hasQualityGateText(dumbResultTextAnswer(equals1ErrorCondition, ERROR, rawValue));
221     assertThat(rawMeasure2.get())
222       .hasQualityGateLevel(WARN)
223       .hasQualityGateText(dumbResultTextAnswer(equals1WarningCondition, WARN, rawValue));
224     assertThat(getAlertStatusMeasure())
225       .hasQualityGateLevel(ERROR)
226       .hasQualityGateText(dumbResultTextAnswer(equals1ErrorCondition, ERROR, rawValue) + ", "
227         + dumbResultTextAnswer(equals1WarningCondition, WARN, rawValue));
228     assertThat(getQGDetailsMeasure())
229       .hasValue(new QualityGateDetailsData(ERROR, of(
230         new EvaluatedCondition(equals1ErrorCondition, ERROR, rawValue),
231         new EvaluatedCondition(equals1WarningCondition, WARN, rawValue))).toJson());
232
233     QualityGateStatusHolderAssertions.assertThat(qualityGateStatusHolder)
234       .hasStatus(QualityGateStatus.ERROR)
235       .hasConditionCount(2)
236       .hasCondition(equals1ErrorCondition, ConditionStatus.EvaluationStatus.ERROR, String.valueOf(rawValue))
237       .hasCondition(equals1WarningCondition, ConditionStatus.EvaluationStatus.WARN, String.valueOf(rawValue));
238   }
239
240   @Test
241   public void new_measures_have_WARNING_level_if_no_updated_measure_has_ERROR_level() {
242     int rawValue = 1;
243     Condition equals2Condition = createEqualsCondition(INT_METRIC_1, "2", null);
244     Condition equals1WarningCondition = createEqualsCondition(INT_METRIC_2, null, "1");
245     Measure rawMeasure = newMeasureBuilder().create(rawValue, null);
246
247     qualityGateHolder.setQualityGate(new QualityGate(SOME_QG_ID, SOME_QG_NAME, of(equals2Condition, equals1WarningCondition)));
248     measureRepository.addRawMeasure(PROJECT_REF, INT_METRIC_1_KEY, rawMeasure);
249     measureRepository.addRawMeasure(PROJECT_REF, INT_METRIC_2_KEY, rawMeasure);
250
251     underTest.execute();
252
253     Optional<Measure> rawMeasure1 = measureRepository.getAddedRawMeasure(PROJECT_REF, INT_METRIC_1_KEY);
254     Optional<Measure> rawMeasure2 = measureRepository.getAddedRawMeasure(PROJECT_REF, INT_METRIC_2_KEY);
255
256     assertThat(rawMeasure1.get())
257       .hasQualityGateLevel(OK)
258       .hasQualityGateText(dumbResultTextAnswer(equals2Condition, OK, rawValue));
259     assertThat(rawMeasure2.get())
260       .hasQualityGateLevel(WARN)
261       .hasQualityGateText(dumbResultTextAnswer(equals1WarningCondition, WARN, rawValue));
262     assertThat(getAlertStatusMeasure())
263       .hasQualityGateLevel(WARN)
264       .hasQualityGateText(dumbResultTextAnswer(equals2Condition, OK, rawValue) + ", "
265         + dumbResultTextAnswer(equals1WarningCondition, WARN, rawValue));
266     assertThat(getQGDetailsMeasure())
267       .hasValue(new QualityGateDetailsData(WARN, of(
268         new EvaluatedCondition(equals2Condition, OK, rawValue),
269         new EvaluatedCondition(equals1WarningCondition, WARN, rawValue))).toJson());
270
271     QualityGateStatusHolderAssertions.assertThat(qualityGateStatusHolder)
272       .hasStatus(QualityGateStatus.WARN)
273       .hasConditionCount(2)
274       .hasCondition(equals2Condition, ConditionStatus.EvaluationStatus.OK, String.valueOf(rawValue))
275       .hasCondition(equals1WarningCondition, ConditionStatus.EvaluationStatus.WARN, String.valueOf(rawValue));
276   }
277
278   @Test
279   public void new_measure_has_ERROR_level_of_all_conditions_for_a_specific_metric_if_its_the_worst() {
280     int rawValue = 1;
281     Condition fixedCondition = createEqualsCondition(INT_METRIC_1, "1", null);
282     Condition periodCondition = createEqualsCondition(INT_METRIC_1, null, "2", 1);
283
284     qualityGateHolder.setQualityGate(new QualityGate(SOME_QG_ID, SOME_QG_NAME, of(fixedCondition, periodCondition)));
285     Measure measure = newMeasureBuilder().create(rawValue, null);
286     measureRepository.addRawMeasure(PROJECT_REF, INT_METRIC_1_KEY, measure);
287
288     underTest.execute();
289
290     Optional<Measure> rawMeasure1 = measureRepository.getAddedRawMeasure(PROJECT_REF, INT_METRIC_1_KEY);
291     assertThat(rawMeasure1.get())
292       .hasQualityGateLevel(ERROR)
293       .hasQualityGateText(dumbResultTextAnswer(fixedCondition, ERROR, rawValue));
294   }
295
296   @Test
297   public void new_measure_has_WARN_level_of_all_conditions_for_a_specific_metric_if_its_the_worst() {
298     int rawValue = 2;
299     Condition fixedCondition = createEqualsCondition(INT_METRIC_1, "1", null);
300     Condition periodCondition = createEqualsCondition(INT_METRIC_1, null, "2", 1);
301
302     qualityGateHolder.setQualityGate(new QualityGate(SOME_QG_ID, SOME_QG_NAME, of(fixedCondition, periodCondition)));
303     Measure measure = newMeasureBuilder()
304       .setVariations(newMeasureVariationsBuilder().setVariation(new Period(1, "mode", null, 1212, "u1"), rawValue).build())
305       .create(rawValue, null);
306     measureRepository.addRawMeasure(PROJECT_REF, INT_METRIC_1_KEY, measure);
307
308     underTest.execute();
309
310     Optional<Measure> rawMeasure1 = measureRepository.getAddedRawMeasure(PROJECT_REF, INT_METRIC_1_KEY);
311     assertThat(rawMeasure1.get())
312       .hasQualityGateLevel(WARN)
313       .hasQualityGateText(dumbResultTextAnswer(periodCondition, WARN, rawValue));
314   }
315
316   @Test
317   public void new_measure_has_condition_on_leak_period_when_all_conditions_on_specific_metric_has_same_QG_level() {
318     int rawValue = 1;
319     Condition fixedCondition = createEqualsCondition(INT_METRIC_1, "1", null);
320     Condition periodCondition = createEqualsCondition(INT_METRIC_1, "1", null, 1);
321
322     qualityGateHolder.setQualityGate(new QualityGate(SOME_QG_ID, SOME_QG_NAME, of(fixedCondition, periodCondition)));
323     Measure measure = newMeasureBuilder()
324         .setVariations(newMeasureVariationsBuilder().setVariation(new Period(1, "mode", null, 1212, "u1"), rawValue).build())
325         .create(rawValue, null);
326     measureRepository.addRawMeasure(PROJECT_REF, INT_METRIC_1_KEY, measure);
327
328     underTest.execute();
329
330     Optional<Measure> rawMeasure1 = measureRepository.getAddedRawMeasure(PROJECT_REF, INT_METRIC_1_KEY);
331     assertThat(rawMeasure1.get())
332         .hasQualityGateLevel(ERROR)
333         .hasQualityGateText(dumbResultTextAnswer(periodCondition, ERROR, rawValue));
334   }
335
336   private Measure getAlertStatusMeasure() {
337     return measureRepository.getAddedRawMeasure(PROJECT_REF, ALERT_STATUS_KEY).get();
338   }
339
340   private Optional<Measure> getQGDetailsMeasure() {
341     return measureRepository.getAddedRawMeasure(PROJECT_REF, CoreMetrics.QUALITY_GATE_DETAILS_KEY);
342   }
343
344   private static Condition createEqualsCondition(Metric metric, @Nullable String errorThreshold, @Nullable String warningThreshold) {
345     return new Condition(metric, Condition.Operator.EQUALS.getDbValue(), errorThreshold, warningThreshold, null);
346   }
347
348   private static Condition createEqualsCondition(Metric metric, @Nullable String errorThreshold, @Nullable String warningThreshold, @Nullable Integer period) {
349     return new Condition(metric, Condition.Operator.EQUALS.getDbValue(), errorThreshold, warningThreshold, period);
350   }
351
352   private static MetricImpl createIntMetric(int index) {
353     return new MetricImpl(index, "metricKey" + index, "metricName" + index, Metric.MetricType.INT);
354   }
355
356   private static class QualityGateStatusHolderAssertions extends AbstractAssert<QualityGateStatusHolderAssertions, QualityGateStatusHolder> {
357
358     private QualityGateStatusHolderAssertions(QualityGateStatusHolder actual) {
359       super(actual, QualityGateStatusHolderAssertions.class);
360     }
361
362     public static QualityGateStatusHolderAssertions assertThat(QualityGateStatusHolder holder) {
363       return new QualityGateStatusHolderAssertions(holder);
364     }
365
366     public QualityGateStatusHolderAssertions hasStatus(QualityGateStatus status) {
367       if (actual.getStatus() != status) {
368         failWithMessage(
369           "Expected QualityGateStatusHolder to have global status <%s> but was <%s>",
370           status, actual.getStatus());
371       }
372
373       return this;
374     }
375
376     public QualityGateStatusHolderAssertions hasConditionCount(int count) {
377       int conditionCount = actual.getStatusPerConditions().size();
378       if (conditionCount != count) {
379         failWithMessage(
380           "Expected QualityGateStatusHolder to have <%s> conditions but it has <%s>",
381           count, conditionCount);
382       }
383
384       return this;
385     }
386
387     public QualityGateStatusHolderAssertions hasCondition(Condition condition, ConditionStatus.EvaluationStatus evaluationStatus, @Nullable String expectedValue) {
388       for (Map.Entry<Condition, ConditionStatus> entry : actual.getStatusPerConditions().entrySet()) {
389         if (entry.getKey() == condition) {
390           ConditionStatus.EvaluationStatus actualStatus = entry.getValue().getStatus();
391           if (actualStatus != evaluationStatus) {
392             failWithMessage(
393               "Expected Status of condition <%s> in QualityGateStatusHolder to be <%s> but it was <%s>",
394               condition, evaluationStatus, actualStatus);
395           }
396           String actualValue = entry.getValue().getValue();
397           if (!Objects.equals(expectedValue, actualValue)) {
398             failWithMessage(
399               "Expected Value of condition <%s> in QualityGateStatusHolder to be <%s> but it was <%s>",
400               condition, expectedValue, actualValue);
401           }
402           return this;
403         }
404       }
405
406       failWithMessage(
407         "Expected QualityGateStatusHolder to have an entry for <%s> but none was found",
408         condition);
409
410       return this;
411     }
412   }
413
414 }