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.

ProjectsInWarningDaemonTest.java 9.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  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.server.qualitygate;
  21. import org.junit.After;
  22. import org.junit.Before;
  23. import org.junit.Rule;
  24. import org.junit.Test;
  25. import org.junit.rules.ExpectedException;
  26. import org.sonar.api.config.internal.MapSettings;
  27. import org.sonar.api.measures.CoreMetrics;
  28. import org.sonar.api.measures.Metric;
  29. import org.sonar.api.utils.System2;
  30. import org.sonar.api.utils.log.LogTester;
  31. import org.sonar.api.utils.log.LoggerLevel;
  32. import org.sonar.db.DbTester;
  33. import org.sonar.db.component.ComponentDto;
  34. import org.sonar.db.metric.MetricDto;
  35. import org.sonar.server.es.EsTester;
  36. import org.sonar.server.measure.index.ProjectMeasuresIndex;
  37. import org.sonar.server.measure.index.ProjectMeasuresIndexer;
  38. import org.sonar.server.permission.index.PermissionIndexerTester;
  39. import org.sonar.server.permission.index.WebAuthorizationTypeSupport;
  40. import org.sonar.server.util.GlobalLockManager;
  41. import static org.assertj.core.api.Assertions.assertThat;
  42. import static org.mockito.ArgumentMatchers.any;
  43. import static org.mockito.ArgumentMatchers.anyInt;
  44. import static org.mockito.Mockito.mock;
  45. import static org.mockito.Mockito.when;
  46. import static org.sonar.api.measures.Metric.Level.WARN;
  47. import static org.sonar.db.measure.MeasureTesting.newLiveMeasure;
  48. import static org.sonar.server.qualitygate.ProjectsInWarningDaemon.PROJECTS_IN_WARNING_INTERNAL_PROPERTY;
  49. public class ProjectsInWarningDaemonTest {
  50. @Rule
  51. public ExpectedException expectedException = ExpectedException.none();
  52. @Rule
  53. public DbTester db = DbTester.create();
  54. @Rule
  55. public EsTester es = EsTester.create();
  56. @Rule
  57. public LogTester logger = new LogTester().setLevel(LoggerLevel.DEBUG);
  58. private PermissionIndexerTester authorizationIndexerTester = new PermissionIndexerTester(es, new ProjectMeasuresIndexer(db.getDbClient(), es.client()));
  59. private ProjectMeasuresIndexer projectMeasuresIndexer = new ProjectMeasuresIndexer(db.getDbClient(), es.client());
  60. private ProjectMeasuresIndex projectMeasuresIndex = new ProjectMeasuresIndex(es.client(), new WebAuthorizationTypeSupport(null), System2.INSTANCE);
  61. private MapSettings settings = new MapSettings();
  62. private GlobalLockManager lockManager = mock(GlobalLockManager.class);
  63. private ProjectsInWarning projectsInWarning = new ProjectsInWarning();
  64. private ProjectsInWarningDaemon underTest = new ProjectsInWarningDaemon(db.getDbClient(), projectMeasuresIndex, settings.asConfig(), lockManager, projectsInWarning);
  65. @Before
  66. public void setUp() throws Exception {
  67. settings.setProperty("sonar.projectsInWarning.frequencyInSeconds", "1");
  68. }
  69. @After
  70. public void tearDown() {
  71. underTest.stop();
  72. }
  73. @Test
  74. public void store_projects_in_warning() throws InterruptedException {
  75. allowLockToBeAcquired();
  76. MetricDto qualityGateStatus = insertQualityGateStatusMetric();
  77. insertProjectInWarning(qualityGateStatus);
  78. insertProjectInWarning(qualityGateStatus);
  79. // Setting does not exist
  80. assertThat(db.getDbClient().internalPropertiesDao().selectByKey(db.getSession(), PROJECTS_IN_WARNING_INTERNAL_PROPERTY)).isEmpty();
  81. underTest.notifyStart();
  82. assertProjectsInWarningValue(2L);
  83. assertThat(logger.logs(LoggerLevel.INFO)).contains("Counting number of projects in warning is enabled.");
  84. }
  85. @Test
  86. public void update_projects_in_warning_when_new_project_in_warning() throws InterruptedException {
  87. allowLockToBeAcquired();
  88. MetricDto qualityGateStatus = insertQualityGateStatusMetric();
  89. ;
  90. insertProjectInWarning(qualityGateStatus);
  91. insertProjectInWarning(qualityGateStatus);
  92. // Setting does not exist
  93. assertThat(db.getDbClient().internalPropertiesDao().selectByKey(db.getSession(), PROJECTS_IN_WARNING_INTERNAL_PROPERTY)).isEmpty();
  94. underTest.notifyStart();
  95. // Add a project in warning after the start in order to let the thread do his job
  96. insertProjectInWarning(qualityGateStatus);
  97. assertProjectsInWarningValue(3L);
  98. assertThat(logger.logs(LoggerLevel.INFO)).contains("Counting number of projects in warning is enabled.");
  99. }
  100. @Test
  101. public void stop_thread_when_number_of_projects_in_warning_reach_zero() throws InterruptedException {
  102. allowLockToBeAcquired();
  103. MetricDto qualityGateStatus = insertQualityGateStatusMetric();
  104. ;
  105. ComponentDto project = insertProjectInWarning(qualityGateStatus);
  106. underTest.notifyStart();
  107. assertProjectsInWarningValue(1L);
  108. // Set quality gate status of the project to OK => No more projects in warning
  109. db.getDbClient().liveMeasureDao().insertOrUpdate(db.getSession(),
  110. newLiveMeasure(project, qualityGateStatus).setData(Metric.Level.OK.name()).setValue(null));
  111. db.commit();
  112. projectMeasuresIndexer.indexOnAnalysis(project.uuid());
  113. assertProjectsInWarningValue(0L);
  114. assertThat(logger.logs(LoggerLevel.INFO))
  115. .contains(
  116. "Counting number of projects in warning is enabled.",
  117. "Counting number of projects in warning will be disabled as there are no more projects in warning.");
  118. }
  119. @Test
  120. public void update_internal_properties_when_already_exits_and_projects_in_warnings_more_than_zero() throws InterruptedException {
  121. allowLockToBeAcquired();
  122. MetricDto qualityGateStatus = insertQualityGateStatusMetric();
  123. ;
  124. insertProjectInWarning(qualityGateStatus);
  125. insertProjectInWarning(qualityGateStatus);
  126. // Setting contains 10, it should be updated with new value
  127. db.getDbClient().internalPropertiesDao().save(db.getSession(), PROJECTS_IN_WARNING_INTERNAL_PROPERTY, "10");
  128. db.commit();
  129. underTest.notifyStart();
  130. assertProjectsInWarningValue(2L);
  131. assertThat(logger.logs(LoggerLevel.INFO)).contains("Counting number of projects in warning is enabled.");
  132. }
  133. @Test
  134. public void store_zero_projects_in_warning_when_no_projects() throws InterruptedException {
  135. allowLockToBeAcquired();
  136. assertThat(db.getDbClient().internalPropertiesDao().selectByKey(db.getSession(), PROJECTS_IN_WARNING_INTERNAL_PROPERTY)).isEmpty();
  137. underTest.notifyStart();
  138. assertProjectsInWarningValue(0L);
  139. assertThat(logger.logs(LoggerLevel.INFO)).contains("Counting number of projects in warning is enabled.");
  140. }
  141. @Test
  142. public void do_not_compute_projects_in_warning_when_internal_property_is_zero() throws InterruptedException {
  143. allowLockToBeAcquired();
  144. MetricDto qualityGateStatus = insertQualityGateStatusMetric();
  145. ;
  146. insertProjectInWarning(qualityGateStatus);
  147. // Setting contains 0, even if there are projects in warning it will stay 0 (as it's not possible to have new projects in warning)
  148. db.getDbClient().internalPropertiesDao().save(db.getSession(), PROJECTS_IN_WARNING_INTERNAL_PROPERTY, "0");
  149. db.commit();
  150. underTest.notifyStart();
  151. assertProjectsInWarningValue(0L);
  152. assertThat(logger.logs(LoggerLevel.INFO)).contains("Counting number of projects in warning is not started as there are no projects in this situation.");
  153. }
  154. @Test
  155. public void do_not_store_projects_in_warning_in_db_when_cannot_acquire_lock() throws InterruptedException {
  156. when(lockManager.tryLock(any(), anyInt())).thenReturn(false);
  157. MetricDto qualityGateStatus = insertQualityGateStatusMetric();
  158. ;
  159. insertProjectInWarning(qualityGateStatus);
  160. underTest.notifyStart();
  161. waitForValueToBeComputed(1L);
  162. assertThat(projectsInWarning.count()).isEqualTo(1L);
  163. assertThat(countNumberOfProjectsInWarning()).isEqualTo(0L);
  164. }
  165. private void waitForValueToBeComputed(long expectedValue) throws InterruptedException {
  166. for (int i = 0; i < 100; i++) {
  167. if (projectsInWarning.isInitialized() && projectsInWarning.count() == expectedValue) {
  168. break;
  169. }
  170. Thread.sleep(100);
  171. }
  172. }
  173. private void assertProjectsInWarningValue(long expectedValue) throws InterruptedException {
  174. waitForValueToBeComputed(expectedValue);
  175. assertThat(projectsInWarning.count()).isEqualTo(expectedValue);
  176. assertThat(countNumberOfProjectsInWarning()).isEqualTo(expectedValue);
  177. }
  178. private long countNumberOfProjectsInWarning() {
  179. return db.getDbClient().internalPropertiesDao().selectByKey(db.getSession(), PROJECTS_IN_WARNING_INTERNAL_PROPERTY)
  180. .map(Long::valueOf)
  181. .orElse(0L);
  182. }
  183. private ComponentDto insertProjectInWarning(MetricDto qualityGateStatus) {
  184. ComponentDto project = db.components().insertPrivateProject();
  185. db.measures().insertLiveMeasure(project, qualityGateStatus, lm -> lm.setData(WARN.name()).setValue(null));
  186. authorizationIndexerTester.allowOnlyAnyone(project);
  187. projectMeasuresIndexer.indexOnAnalysis(project.uuid());
  188. return project;
  189. }
  190. private MetricDto insertQualityGateStatusMetric() {
  191. return db.measures().insertMetric(m -> m.setKey(CoreMetrics.ALERT_STATUS_KEY).setValueType(Metric.ValueType.LEVEL.name()));
  192. }
  193. private void allowLockToBeAcquired() {
  194. when(lockManager.tryLock(any(), anyInt())).thenReturn(true);
  195. }
  196. }