You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

QualityGateEventsStepTest.java 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2019 SonarSource SA
  4. * mailto:info 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.ce.task.projectanalysis.step;
  21. import java.util.Collection;
  22. import java.util.Optional;
  23. import org.junit.Before;
  24. import org.junit.Rule;
  25. import org.junit.Test;
  26. import org.mockito.ArgumentCaptor;
  27. import org.sonar.api.notifications.Notification;
  28. import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolderRule;
  29. import org.sonar.ce.task.projectanalysis.analysis.Branch;
  30. import org.sonar.ce.task.projectanalysis.component.Component;
  31. import org.sonar.ce.task.projectanalysis.component.DefaultBranchImpl;
  32. import org.sonar.ce.task.projectanalysis.component.ReportComponent;
  33. import org.sonar.ce.task.projectanalysis.component.TreeRootHolder;
  34. import org.sonar.ce.task.projectanalysis.component.TreeRootHolderRule;
  35. import org.sonar.ce.task.projectanalysis.event.Event;
  36. import org.sonar.ce.task.projectanalysis.event.EventRepository;
  37. import org.sonar.ce.task.projectanalysis.measure.Measure;
  38. import org.sonar.ce.task.projectanalysis.measure.MeasureRepository;
  39. import org.sonar.ce.task.projectanalysis.measure.QualityGateStatus;
  40. import org.sonar.ce.task.projectanalysis.metric.Metric;
  41. import org.sonar.ce.task.projectanalysis.metric.MetricRepository;
  42. import org.sonar.ce.task.step.TestComputationStepContext;
  43. import org.sonar.db.component.BranchType;
  44. import org.sonar.server.notification.NotificationService;
  45. import org.sonar.server.project.Project;
  46. import org.sonar.server.qualitygate.notification.QGChangeNotification;
  47. import static java.util.Collections.emptyList;
  48. import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
  49. import static org.assertj.core.api.Assertions.assertThat;
  50. import static org.mockito.ArgumentMatchers.eq;
  51. import static org.mockito.Mockito.mock;
  52. import static org.mockito.Mockito.reset;
  53. import static org.mockito.Mockito.verify;
  54. import static org.mockito.Mockito.verifyNoMoreInteractions;
  55. import static org.mockito.Mockito.verifyZeroInteractions;
  56. import static org.mockito.Mockito.when;
  57. import static org.sonar.api.measures.CoreMetrics.ALERT_STATUS_KEY;
  58. import static org.sonar.ce.task.projectanalysis.measure.Measure.Level.ERROR;
  59. import static org.sonar.ce.task.projectanalysis.measure.Measure.Level.OK;
  60. public class QualityGateEventsStepTest {
  61. private static final String PROJECT_VERSION = randomAlphabetic(19);
  62. private static final ReportComponent PROJECT_COMPONENT = ReportComponent.builder(Component.Type.PROJECT, 1)
  63. .setUuid("uuid 1")
  64. .setKey("key 1")
  65. .setProjectVersion(PROJECT_VERSION)
  66. .setBuildString("V1.9")
  67. .setScmRevisionId("456def")
  68. .addChildren(ReportComponent.builder(Component.Type.DIRECTORY, 2).build())
  69. .build();
  70. private static final String INVALID_ALERT_STATUS = "trololo";
  71. private static final String ALERT_TEXT = "alert text";
  72. private static final QualityGateStatus OK_QUALITY_GATE_STATUS = new QualityGateStatus(OK, ALERT_TEXT);
  73. private static final QualityGateStatus ERROR_QUALITY_GATE_STATUS = new QualityGateStatus(ERROR, ALERT_TEXT);
  74. @Rule
  75. public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
  76. @Rule
  77. public AnalysisMetadataHolderRule analysisMetadataHolder = new AnalysisMetadataHolderRule();
  78. private ArgumentCaptor<Event> eventArgumentCaptor = ArgumentCaptor.forClass(Event.class);
  79. private ArgumentCaptor<Notification> notificationArgumentCaptor = ArgumentCaptor.forClass(Notification.class);
  80. private Metric alertStatusMetric = mock(Metric.class);
  81. private MetricRepository metricRepository = mock(MetricRepository.class);
  82. private MeasureRepository measureRepository = mock(MeasureRepository.class);
  83. private EventRepository eventRepository = mock(EventRepository.class);
  84. private NotificationService notificationService = mock(NotificationService.class);
  85. private QualityGateEventsStep underTest = new QualityGateEventsStep(treeRootHolder, metricRepository, measureRepository, eventRepository, notificationService,
  86. analysisMetadataHolder);
  87. @Before
  88. public void setUp() {
  89. when(metricRepository.getByKey(ALERT_STATUS_KEY)).thenReturn(alertStatusMetric);
  90. analysisMetadataHolder
  91. .setProject(new Project(PROJECT_COMPONENT.getUuid(), PROJECT_COMPONENT.getDbKey(), PROJECT_COMPONENT.getName(), PROJECT_COMPONENT.getDescription(), emptyList()));
  92. analysisMetadataHolder.setBranch(mock(Branch.class));
  93. treeRootHolder.setRoot(PROJECT_COMPONENT);
  94. }
  95. @Test
  96. public void no_event_if_no_raw_ALERT_STATUS_measure() {
  97. when(measureRepository.getRawMeasure(PROJECT_COMPONENT, alertStatusMetric)).thenReturn(Optional.empty());
  98. underTest.execute(new TestComputationStepContext());
  99. verify(measureRepository).getRawMeasure(PROJECT_COMPONENT, alertStatusMetric);
  100. verifyNoMoreInteractions(measureRepository, eventRepository);
  101. }
  102. @Test
  103. public void no_event_created_if_raw_ALERT_STATUS_measure_is_null() {
  104. when(measureRepository.getRawMeasure(PROJECT_COMPONENT, alertStatusMetric)).thenReturn(of(Measure.newMeasureBuilder().createNoValue()));
  105. underTest.execute(new TestComputationStepContext());
  106. verify(measureRepository).getRawMeasure(PROJECT_COMPONENT, alertStatusMetric);
  107. verifyNoMoreInteractions(measureRepository, eventRepository);
  108. }
  109. private static Optional<Measure> of(Measure measure) {
  110. return Optional.of(measure);
  111. }
  112. @Test
  113. public void no_event_created_if_raw_ALERT_STATUS_measure_is_unsupported_value() {
  114. when(measureRepository.getRawMeasure(PROJECT_COMPONENT, alertStatusMetric)).thenReturn(of(Measure.newMeasureBuilder().create(INVALID_ALERT_STATUS)));
  115. underTest.execute(new TestComputationStepContext());
  116. verify(measureRepository).getRawMeasure(PROJECT_COMPONENT, alertStatusMetric);
  117. verifyNoMoreInteractions(measureRepository, eventRepository);
  118. }
  119. @Test
  120. public void no_event_created_if_no_base_ALERT_STATUS_and_raw_is_OK() {
  121. QualityGateStatus someQGStatus = new QualityGateStatus(Measure.Level.OK);
  122. when(measureRepository.getRawMeasure(PROJECT_COMPONENT, alertStatusMetric)).thenReturn(of(Measure.newMeasureBuilder().setQualityGateStatus(someQGStatus).createNoValue()));
  123. when(measureRepository.getBaseMeasure(PROJECT_COMPONENT, alertStatusMetric)).thenReturn(of(Measure.newMeasureBuilder().createNoValue()));
  124. underTest.execute(new TestComputationStepContext());
  125. verify(measureRepository).getRawMeasure(PROJECT_COMPONENT, alertStatusMetric);
  126. verify(measureRepository).getBaseMeasure(PROJECT_COMPONENT, alertStatusMetric);
  127. verifyNoMoreInteractions(measureRepository, eventRepository);
  128. }
  129. @Test
  130. public void event_created_if_base_ALERT_STATUS_has_no_alertStatus_and_raw_is_ERROR() {
  131. verify_event_created_if_no_base_ALERT_STATUS_measure(ERROR, "Red");
  132. }
  133. @Test
  134. public void event_created_if_base_ALERT_STATUS_has_invalid_alertStatus_and_raw_is_ERROR() {
  135. verify_event_created_if_no_base_ALERT_STATUS_measure(ERROR, "Red");
  136. }
  137. private void verify_event_created_if_no_base_ALERT_STATUS_measure(Measure.Level rawAlterStatus, String expectedLabel) {
  138. QualityGateStatus someQGStatus = new QualityGateStatus(rawAlterStatus, ALERT_TEXT);
  139. when(measureRepository.getRawMeasure(PROJECT_COMPONENT, alertStatusMetric)).thenReturn(of(Measure.newMeasureBuilder().setQualityGateStatus(someQGStatus).createNoValue()));
  140. when(measureRepository.getBaseMeasure(PROJECT_COMPONENT, alertStatusMetric)).thenReturn(of(Measure.newMeasureBuilder().createNoValue()));
  141. underTest.execute(new TestComputationStepContext());
  142. verify(measureRepository).getRawMeasure(PROJECT_COMPONENT, alertStatusMetric);
  143. verify(measureRepository).getBaseMeasure(PROJECT_COMPONENT, alertStatusMetric);
  144. verify(eventRepository).add(eq(PROJECT_COMPONENT), eventArgumentCaptor.capture());
  145. verifyNoMoreInteractions(measureRepository, eventRepository);
  146. Event event = eventArgumentCaptor.getValue();
  147. assertThat(event.getCategory()).isEqualTo(Event.Category.ALERT);
  148. assertThat(event.getName()).isEqualTo(expectedLabel);
  149. assertThat(event.getDescription()).isEqualTo(ALERT_TEXT);
  150. assertThat(event.getData()).isNull();
  151. ArgumentCaptor<Collection> collectionCaptor = ArgumentCaptor.forClass(Collection.class);
  152. verify(notificationService).deliverEmails(collectionCaptor.capture());
  153. verify(notificationService).deliver(notificationArgumentCaptor.capture());
  154. Notification notification = notificationArgumentCaptor.getValue();
  155. assertThat(collectionCaptor.getValue()).hasSize(1);
  156. assertThat(collectionCaptor.getValue().iterator().next()).isSameAs(notification);
  157. assertThat(notification).isInstanceOf(QGChangeNotification.class);
  158. assertThat(notification.getType()).isEqualTo("alerts");
  159. assertThat(notification.getFieldValue("projectKey")).isEqualTo(PROJECT_COMPONENT.getKey());
  160. assertThat(notification.getFieldValue("projectName")).isEqualTo(PROJECT_COMPONENT.getName());
  161. assertThat(notification.getFieldValue("projectVersion")).isEqualTo(PROJECT_COMPONENT.getProjectAttributes().getProjectVersion());
  162. assertThat(notification.getFieldValue("branch")).isNull();
  163. assertThat(notification.getFieldValue("alertLevel")).isEqualTo(rawAlterStatus.name());
  164. assertThat(notification.getFieldValue("alertName")).isEqualTo(expectedLabel);
  165. }
  166. @Test
  167. public void no_event_created_if_base_ALERT_STATUS_measure_but_status_is_the_same() {
  168. when(measureRepository.getRawMeasure(PROJECT_COMPONENT, alertStatusMetric))
  169. .thenReturn(of(Measure.newMeasureBuilder().setQualityGateStatus(OK_QUALITY_GATE_STATUS).createNoValue()));
  170. when(measureRepository.getBaseMeasure(PROJECT_COMPONENT, alertStatusMetric))
  171. .thenReturn(of(Measure.newMeasureBuilder().setQualityGateStatus(OK_QUALITY_GATE_STATUS).createNoValue()));
  172. underTest.execute(new TestComputationStepContext());
  173. verify(measureRepository).getRawMeasure(PROJECT_COMPONENT, alertStatusMetric);
  174. verify(measureRepository).getBaseMeasure(PROJECT_COMPONENT, alertStatusMetric);
  175. verifyNoMoreInteractions(measureRepository, eventRepository);
  176. }
  177. @Test
  178. public void event_created_if_base_ALERT_STATUS_measure_exists_and_status_has_changed() {
  179. verify_event_created_if_base_ALERT_STATUS_measure_exists_and_status_has_changed(OK, ERROR_QUALITY_GATE_STATUS, "Red (was Green)");
  180. verify_event_created_if_base_ALERT_STATUS_measure_exists_and_status_has_changed(ERROR, OK_QUALITY_GATE_STATUS, "Green (was Red)");
  181. }
  182. private void verify_event_created_if_base_ALERT_STATUS_measure_exists_and_status_has_changed(Measure.Level previousAlertStatus,
  183. QualityGateStatus newQualityGateStatus, String expectedLabel) {
  184. when(measureRepository.getRawMeasure(PROJECT_COMPONENT, alertStatusMetric))
  185. .thenReturn(of(Measure.newMeasureBuilder().setQualityGateStatus(newQualityGateStatus).createNoValue()));
  186. when(measureRepository.getBaseMeasure(PROJECT_COMPONENT, alertStatusMetric)).thenReturn(
  187. of(Measure.newMeasureBuilder().setQualityGateStatus(new QualityGateStatus(previousAlertStatus)).createNoValue()));
  188. underTest.execute(new TestComputationStepContext());
  189. verify(measureRepository).getRawMeasure(PROJECT_COMPONENT, alertStatusMetric);
  190. verify(measureRepository).getBaseMeasure(PROJECT_COMPONENT, alertStatusMetric);
  191. verify(eventRepository).add(eq(PROJECT_COMPONENT), eventArgumentCaptor.capture());
  192. verifyNoMoreInteractions(measureRepository, eventRepository);
  193. Event event = eventArgumentCaptor.getValue();
  194. assertThat(event.getCategory()).isEqualTo(Event.Category.ALERT);
  195. assertThat(event.getName()).isEqualTo(expectedLabel);
  196. assertThat(event.getDescription()).isEqualTo(ALERT_TEXT);
  197. assertThat(event.getData()).isNull();
  198. verify(notificationService).deliver(notificationArgumentCaptor.capture());
  199. Notification notification = notificationArgumentCaptor.getValue();
  200. assertThat(notification.getType()).isEqualTo("alerts");
  201. assertThat(notification.getFieldValue("projectKey")).isEqualTo(PROJECT_COMPONENT.getKey());
  202. assertThat(notification.getFieldValue("projectName")).isEqualTo(PROJECT_COMPONENT.getName());
  203. assertThat(notification.getFieldValue("projectVersion")).isEqualTo(PROJECT_COMPONENT.getProjectAttributes().getProjectVersion());
  204. assertThat(notification.getFieldValue("branch")).isNull();
  205. assertThat(notification.getFieldValue("alertLevel")).isEqualTo(newQualityGateStatus.getStatus().name());
  206. assertThat(notification.getFieldValue("alertName")).isEqualTo(expectedLabel);
  207. reset(measureRepository, eventRepository, notificationService);
  208. }
  209. @Test
  210. public void verify_branch_name_is_not_set_in_notification_when_main() {
  211. analysisMetadataHolder.setBranch(new DefaultBranchImpl());
  212. when(measureRepository.getRawMeasure(PROJECT_COMPONENT, alertStatusMetric))
  213. .thenReturn(of(Measure.newMeasureBuilder().setQualityGateStatus(OK_QUALITY_GATE_STATUS).createNoValue()));
  214. when(measureRepository.getBaseMeasure(PROJECT_COMPONENT, alertStatusMetric)).thenReturn(
  215. of(Measure.newMeasureBuilder().setQualityGateStatus(new QualityGateStatus(ERROR)).createNoValue()));
  216. underTest.execute(new TestComputationStepContext());
  217. verify(notificationService).deliver(notificationArgumentCaptor.capture());
  218. Notification notification = notificationArgumentCaptor.getValue();
  219. assertThat(notification.getType()).isEqualTo("alerts");
  220. assertThat(notification.getFieldValue("projectKey")).isEqualTo(PROJECT_COMPONENT.getKey());
  221. assertThat(notification.getFieldValue("projectName")).isEqualTo(PROJECT_COMPONENT.getName());
  222. assertThat(notification.getFieldValue("projectVersion")).isEqualTo(PROJECT_COMPONENT.getProjectAttributes().getProjectVersion());
  223. assertThat(notification.getFieldValue("branch")).isEqualTo(null);
  224. reset(measureRepository, eventRepository, notificationService);
  225. }
  226. @Test
  227. public void no_alert_on_short_living_branches() {
  228. Branch shortBranch = mock(Branch.class);
  229. when(shortBranch.getType()).thenReturn(BranchType.SHORT);
  230. analysisMetadataHolder.setBranch(shortBranch);
  231. TreeRootHolder treeRootHolder = mock(TreeRootHolder.class);
  232. MetricRepository metricRepository = mock(MetricRepository.class);
  233. MeasureRepository measureRepository = mock(MeasureRepository.class);
  234. EventRepository eventRepository = mock(EventRepository.class);
  235. NotificationService notificationService = mock(NotificationService.class);
  236. QualityGateEventsStep underTest = new QualityGateEventsStep(treeRootHolder, metricRepository, measureRepository,
  237. eventRepository, notificationService, analysisMetadataHolder);
  238. underTest.execute(new TestComputationStepContext());
  239. verifyZeroInteractions(treeRootHolder, metricRepository, measureRepository, eventRepository, notificationService);
  240. }
  241. @Test
  242. public void no_alert_on_pull_request_branches() {
  243. Branch shortBranch = mock(Branch.class);
  244. when(shortBranch.getType()).thenReturn(BranchType.PULL_REQUEST);
  245. analysisMetadataHolder.setBranch(shortBranch);
  246. TreeRootHolder treeRootHolder = mock(TreeRootHolder.class);
  247. MetricRepository metricRepository = mock(MetricRepository.class);
  248. MeasureRepository measureRepository = mock(MeasureRepository.class);
  249. EventRepository eventRepository = mock(EventRepository.class);
  250. NotificationService notificationService = mock(NotificationService.class);
  251. QualityGateEventsStep underTest = new QualityGateEventsStep(treeRootHolder, metricRepository, measureRepository,
  252. eventRepository, notificationService, analysisMetadataHolder);
  253. underTest.execute(new TestComputationStepContext());
  254. verifyZeroInteractions(treeRootHolder, metricRepository, measureRepository, eventRepository, notificationService);
  255. }
  256. }