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