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.

InternalCeQueueImplTest.java 29KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716
  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.queue;
  21. import com.google.common.collect.ImmutableSet;
  22. import java.io.ByteArrayOutputStream;
  23. import java.io.PrintStream;
  24. import java.util.List;
  25. import java.util.Optional;
  26. import javax.annotation.Nullable;
  27. import org.junit.Before;
  28. import org.junit.Rule;
  29. import org.junit.Test;
  30. import org.junit.rules.ExpectedException;
  31. import org.sonar.api.utils.System2;
  32. import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
  33. import org.sonar.ce.container.ComputeEngineStatus;
  34. import org.sonar.ce.monitoring.CEQueueStatus;
  35. import org.sonar.ce.monitoring.CEQueueStatusImpl;
  36. import org.sonar.ce.task.CeTask;
  37. import org.sonar.ce.task.CeTaskResult;
  38. import org.sonar.ce.task.TypedException;
  39. import org.sonar.core.util.UuidFactory;
  40. import org.sonar.core.util.UuidFactoryImpl;
  41. import org.sonar.db.DbSession;
  42. import org.sonar.db.DbTester;
  43. import org.sonar.db.ce.CeActivityDto;
  44. import org.sonar.db.ce.CeQueueDto;
  45. import org.sonar.db.ce.CeQueueTesting;
  46. import org.sonar.db.ce.CeTaskTypes;
  47. import org.sonar.db.component.ComponentDto;
  48. import org.sonar.db.component.ComponentTesting;
  49. import org.sonar.db.organization.OrganizationDto;
  50. import org.sonar.db.user.UserDto;
  51. import org.sonar.server.organization.DefaultOrganization;
  52. import org.sonar.server.organization.DefaultOrganizationProvider;
  53. import static java.util.Arrays.asList;
  54. import static java.util.Collections.emptyMap;
  55. import static org.assertj.core.api.Assertions.assertThat;
  56. import static org.assertj.core.api.Assertions.fail;
  57. import static org.mockito.ArgumentMatchers.anyLong;
  58. import static org.mockito.Mockito.mock;
  59. import static org.mockito.Mockito.verify;
  60. import static org.mockito.Mockito.verifyZeroInteractions;
  61. import static org.mockito.Mockito.when;
  62. import static org.sonar.ce.container.ComputeEngineStatus.Status.STARTED;
  63. import static org.sonar.ce.container.ComputeEngineStatus.Status.STOPPING;
  64. public class InternalCeQueueImplTest {
  65. private static final String AN_ANALYSIS_UUID = "U1";
  66. private static final String WORKER_UUID_1 = "worker uuid 1";
  67. private static final String WORKER_UUID_2 = "worker uuid 2";
  68. private System2 system2 = new AlwaysIncreasingSystem2();
  69. @Rule
  70. public ExpectedException expectedException = ExpectedException.none();
  71. @Rule
  72. public DbTester db = DbTester.create(system2);
  73. private DbSession session = db.getSession();
  74. private UuidFactory uuidFactory = UuidFactoryImpl.INSTANCE;
  75. private CEQueueStatus queueStatus = new CEQueueStatusImpl(db.getDbClient(), mock(System2.class));
  76. private DefaultOrganizationProvider defaultOrganizationProvider = mock(DefaultOrganizationProvider.class);
  77. private ComputeEngineStatus computeEngineStatus = mock(ComputeEngineStatus.class);
  78. private InternalCeQueue underTest = new InternalCeQueueImpl(system2, db.getDbClient(), uuidFactory, queueStatus, defaultOrganizationProvider, computeEngineStatus);
  79. @Before
  80. public void setUp() {
  81. OrganizationDto defaultOrganization = db.getDefaultOrganization();
  82. when(defaultOrganizationProvider.get()).thenReturn(DefaultOrganization.newBuilder()
  83. .setUuid(defaultOrganization.getUuid())
  84. .setKey(defaultOrganization.getKey())
  85. .setName(defaultOrganization.getName())
  86. .setCreatedAt(defaultOrganization.getCreatedAt())
  87. .setUpdatedAt(defaultOrganization.getUpdatedAt())
  88. .build());
  89. when(computeEngineStatus.getStatus()).thenReturn(STARTED);
  90. }
  91. @Test
  92. public void submit_returns_task_populated_from_CeTaskSubmit_and_creates_CeQueue_row() {
  93. CeTaskSubmit taskSubmit = createTaskSubmit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1"), "rob");
  94. CeTask task = underTest.submit(taskSubmit);
  95. UserDto userDto = db.getDbClient().userDao().selectByUuid(db.getSession(), taskSubmit.getSubmitterUuid());
  96. verifyCeTask(taskSubmit, task, null, userDto);
  97. verifyCeQueueDtoForTaskSubmit(taskSubmit);
  98. }
  99. @Test
  100. public void submit_populates_component_name_and_key_of_CeTask_if_component_exists() {
  101. ComponentDto componentDto = insertComponent(newProjectDto("PROJECT_1"));
  102. CeTaskSubmit taskSubmit = createTaskSubmit(CeTaskTypes.REPORT, componentDto, null);
  103. CeTask task = underTest.submit(taskSubmit);
  104. verifyCeTask(taskSubmit, task, componentDto, null);
  105. }
  106. @Test
  107. public void submit_returns_task_without_component_info_when_submit_has_none() {
  108. CeTaskSubmit taskSubmit = createTaskSubmit("not cpt related");
  109. CeTask task = underTest.submit(taskSubmit);
  110. verifyCeTask(taskSubmit, task, null, null);
  111. }
  112. @Test
  113. public void massSubmit_returns_tasks_for_each_CeTaskSubmit_populated_from_CeTaskSubmit_and_creates_CeQueue_row_for_each() {
  114. CeTaskSubmit taskSubmit1 = createTaskSubmit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1"), "rob");
  115. CeTaskSubmit taskSubmit2 = createTaskSubmit("some type");
  116. List<CeTask> tasks = underTest.massSubmit(asList(taskSubmit1, taskSubmit2));
  117. UserDto userDto1 = db.getDbClient().userDao().selectByUuid(db.getSession(), taskSubmit1.getSubmitterUuid());
  118. assertThat(tasks).hasSize(2);
  119. verifyCeTask(taskSubmit1, tasks.get(0), null, userDto1);
  120. verifyCeTask(taskSubmit2, tasks.get(1), null, null);
  121. verifyCeQueueDtoForTaskSubmit(taskSubmit1);
  122. verifyCeQueueDtoForTaskSubmit(taskSubmit2);
  123. }
  124. @Test
  125. public void massSubmit_populates_component_name_and_key_of_CeTask_if_component_exists() {
  126. ComponentDto componentDto1 = insertComponent(newProjectDto("PROJECT_1"));
  127. CeTaskSubmit taskSubmit1 = createTaskSubmit(CeTaskTypes.REPORT, componentDto1, null);
  128. CeTaskSubmit taskSubmit2 = createTaskSubmit("something", newProjectDto("non existing component uuid"), null);
  129. List<CeTask> tasks = underTest.massSubmit(asList(taskSubmit1, taskSubmit2));
  130. assertThat(tasks).hasSize(2);
  131. verifyCeTask(taskSubmit1, tasks.get(0), componentDto1, null);
  132. verifyCeTask(taskSubmit2, tasks.get(1), null, null);
  133. }
  134. @Test
  135. public void peek_throws_NPE_if_workerUUid_is_null() {
  136. expectedException.expect(NullPointerException.class);
  137. expectedException.expectMessage("workerUuid can't be null");
  138. underTest.peek(null);
  139. }
  140. @Test
  141. public void test_remove() {
  142. CeTask task = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1"));
  143. Optional<CeTask> peek = underTest.peek(WORKER_UUID_1);
  144. underTest.remove(peek.get(), CeActivityDto.Status.SUCCESS, null, null);
  145. // queue is empty
  146. assertThat(db.getDbClient().ceQueueDao().selectByUuid(db.getSession(), task.getUuid()).isPresent()).isFalse();
  147. assertThat(underTest.peek(WORKER_UUID_2).isPresent()).isFalse();
  148. // available in history
  149. Optional<CeActivityDto> history = db.getDbClient().ceActivityDao().selectByUuid(db.getSession(), task.getUuid());
  150. assertThat(history.isPresent()).isTrue();
  151. assertThat(history.get().getStatus()).isEqualTo(CeActivityDto.Status.SUCCESS);
  152. assertThat(history.get().getIsLast()).isTrue();
  153. assertThat(history.get().getAnalysisUuid()).isNull();
  154. }
  155. @Test
  156. public void remove_throws_IAE_if_exception_is_provided_but_status_is_SUCCESS() {
  157. expectedException.expect(IllegalArgumentException.class);
  158. expectedException.expectMessage("Error can be provided only when status is FAILED");
  159. underTest.remove(mock(CeTask.class), CeActivityDto.Status.SUCCESS, null, new RuntimeException("Some error"));
  160. }
  161. @Test
  162. public void remove_throws_IAE_if_exception_is_provided_but_status_is_CANCELED() {
  163. expectedException.expect(IllegalArgumentException.class);
  164. expectedException.expectMessage("Error can be provided only when status is FAILED");
  165. underTest.remove(mock(CeTask.class), CeActivityDto.Status.CANCELED, null, new RuntimeException("Some error"));
  166. }
  167. @Test
  168. public void remove_does_not_set_analysisUuid_in_CeActivity_when_CeTaskResult_has_no_analysis_uuid() {
  169. CeTask task = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1"));
  170. Optional<CeTask> peek = underTest.peek(WORKER_UUID_1);
  171. underTest.remove(peek.get(), CeActivityDto.Status.SUCCESS, newTaskResult(null), null);
  172. // available in history
  173. Optional<CeActivityDto> history = db.getDbClient().ceActivityDao().selectByUuid(db.getSession(), task.getUuid());
  174. assertThat(history.isPresent()).isTrue();
  175. assertThat(history.get().getAnalysisUuid()).isNull();
  176. }
  177. @Test
  178. public void remove_sets_analysisUuid_in_CeActivity_when_CeTaskResult_has_analysis_uuid() {
  179. CeTask task = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1"));
  180. Optional<CeTask> peek = underTest.peek(WORKER_UUID_2);
  181. underTest.remove(peek.get(), CeActivityDto.Status.SUCCESS, newTaskResult(AN_ANALYSIS_UUID), null);
  182. // available in history
  183. Optional<CeActivityDto> history = db.getDbClient().ceActivityDao().selectByUuid(db.getSession(), task.getUuid());
  184. assertThat(history.isPresent()).isTrue();
  185. assertThat(history.get().getAnalysisUuid()).isEqualTo("U1");
  186. }
  187. @Test
  188. public void remove_saves_error_message_and_stacktrace_when_exception_is_provided() {
  189. Throwable error = new NullPointerException("Fake NPE to test persistence to DB");
  190. CeTask task = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1"));
  191. Optional<CeTask> peek = underTest.peek(WORKER_UUID_1);
  192. underTest.remove(peek.get(), CeActivityDto.Status.FAILED, null, error);
  193. Optional<CeActivityDto> activityDto = db.getDbClient().ceActivityDao().selectByUuid(session, task.getUuid());
  194. assertThat(activityDto).isPresent();
  195. assertThat(activityDto.get().getErrorMessage()).isEqualTo(error.getMessage());
  196. assertThat(activityDto.get().getErrorStacktrace()).isEqualToIgnoringWhitespace(stacktraceToString(error));
  197. assertThat(activityDto.get().getErrorType()).isNull();
  198. }
  199. @Test
  200. public void remove_saves_error_when_TypedMessageException_is_provided() {
  201. Throwable error = new TypedExceptionImpl("aType", "aMessage");
  202. CeTask task = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1"));
  203. Optional<CeTask> peek = underTest.peek(WORKER_UUID_1);
  204. underTest.remove(peek.get(), CeActivityDto.Status.FAILED, null, error);
  205. CeActivityDto activityDto = db.getDbClient().ceActivityDao().selectByUuid(session, task.getUuid()).get();
  206. assertThat(activityDto.getErrorType()).isEqualTo("aType");
  207. assertThat(activityDto.getErrorMessage()).isEqualTo("aMessage");
  208. assertThat(activityDto.getErrorStacktrace()).isEqualToIgnoringWhitespace(stacktraceToString(error));
  209. }
  210. @Test
  211. public void remove_updates_queueStatus_success_even_if_task_does_not_exist_in_DB() {
  212. CEQueueStatus queueStatus = mock(CEQueueStatus.class);
  213. CeTask task = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1"));
  214. db.getDbClient().ceQueueDao().deleteByUuid(db.getSession(), task.getUuid());
  215. db.commit();
  216. InternalCeQueueImpl underTest = new InternalCeQueueImpl(system2, db.getDbClient(), null, queueStatus, null, null);
  217. try {
  218. underTest.remove(task, CeActivityDto.Status.SUCCESS, null, null);
  219. fail("remove should have thrown a IllegalStateException");
  220. } catch (IllegalStateException e) {
  221. verify(queueStatus).addSuccess(anyLong());
  222. }
  223. }
  224. @Test
  225. public void remove_updates_queueStatus_failure_even_if_task_does_not_exist_in_DB() {
  226. CEQueueStatus queueStatusMock = mock(CEQueueStatus.class);
  227. CeTask task = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1"));
  228. db.getDbClient().ceQueueDao().deleteByUuid(db.getSession(), task.getUuid());
  229. db.commit();
  230. InternalCeQueueImpl underTest = new InternalCeQueueImpl(system2, db.getDbClient(), null, queueStatusMock, null, null);
  231. try {
  232. underTest.remove(task, CeActivityDto.Status.FAILED, null, null);
  233. fail("remove should have thrown a IllegalStateException");
  234. } catch (IllegalStateException e) {
  235. verify(queueStatusMock).addError(anyLong());
  236. }
  237. }
  238. @Test
  239. public void cancelWornOuts_does_not_update_queueStatus() {
  240. CEQueueStatus queueStatusMock = mock(CEQueueStatus.class);
  241. CeTask task = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1"));
  242. db.executeUpdateSql("update ce_queue set status = 'PENDING', started_at = 123 where uuid = '" + task.getUuid() + "'");
  243. db.commit();
  244. InternalCeQueueImpl underTest = new InternalCeQueueImpl(system2, db.getDbClient(), null, queueStatusMock, null, null);
  245. underTest.cancelWornOuts();
  246. assertThat(db.getDbClient().ceActivityDao().selectByUuid(db.getSession(), task.getUuid())).isPresent();
  247. verifyZeroInteractions(queueStatusMock);
  248. }
  249. private static class TypedExceptionImpl extends RuntimeException implements TypedException {
  250. private final String type;
  251. private TypedExceptionImpl(String type, String message) {
  252. super(message);
  253. this.type = type;
  254. }
  255. @Override
  256. public String getType() {
  257. return type;
  258. }
  259. }
  260. @Test
  261. public void remove_copies_workerUuid() {
  262. CeQueueDto ceQueueDto = db.getDbClient().ceQueueDao().insert(session, new CeQueueDto()
  263. .setUuid("uuid")
  264. .setTaskType("foo")
  265. .setStatus(CeQueueDto.Status.PENDING));
  266. makeInProgress(ceQueueDto, "Dustin");
  267. db.commit();
  268. underTest.remove(new CeTask.Builder()
  269. .setOrganizationUuid("foo")
  270. .setUuid("uuid")
  271. .setType("bar")
  272. .build(), CeActivityDto.Status.SUCCESS, null, null);
  273. CeActivityDto dto = db.getDbClient().ceActivityDao().selectByUuid(db.getSession(), "uuid").get();
  274. assertThat(dto.getWorkerUuid()).isEqualTo("Dustin");
  275. }
  276. @Test
  277. public void fail_to_remove_if_not_in_queue() {
  278. CeTask task = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1"));
  279. underTest.remove(task, CeActivityDto.Status.SUCCESS, null, null);
  280. expectedException.expect(IllegalStateException.class);
  281. underTest.remove(task, CeActivityDto.Status.SUCCESS, null, null);
  282. }
  283. @Test
  284. public void test_peek() {
  285. CeTask task = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1"));
  286. Optional<CeTask> peek = underTest.peek(WORKER_UUID_1);
  287. assertThat(peek.isPresent()).isTrue();
  288. assertThat(peek.get().getUuid()).isEqualTo(task.getUuid());
  289. assertThat(peek.get().getType()).isEqualTo(CeTaskTypes.REPORT);
  290. assertThat(peek.get().getComponent()).contains(new CeTask.Component("PROJECT_1", null, null));
  291. assertThat(peek.get().getMainComponent()).contains(peek.get().getComponent().get());
  292. // no more pending tasks
  293. peek = underTest.peek(WORKER_UUID_2);
  294. assertThat(peek.isPresent()).isFalse();
  295. }
  296. @Test
  297. public void peek_populates_name_and_key_for_existing_component_and_main_component() {
  298. ComponentDto project = db.components().insertPrivateProject();
  299. ComponentDto branch = db.components().insertProjectBranch(project);
  300. CeTask task = submit(CeTaskTypes.REPORT, branch);
  301. Optional<CeTask> peek = underTest.peek(WORKER_UUID_1);
  302. assertThat(peek.isPresent()).isTrue();
  303. assertThat(peek.get().getUuid()).isEqualTo(task.getUuid());
  304. assertThat(peek.get().getType()).isEqualTo(CeTaskTypes.REPORT);
  305. assertThat(peek.get().getComponent()).contains(new CeTask.Component(branch.uuid(), branch.getDbKey(), branch.name()));
  306. assertThat(peek.get().getMainComponent()).contains(new CeTask.Component(project.uuid(), project.getDbKey(), project.name()));
  307. // no more pending tasks
  308. peek = underTest.peek(WORKER_UUID_2);
  309. assertThat(peek.isPresent()).isFalse();
  310. }
  311. @Test
  312. public void peek_is_paused_then_resumed() {
  313. CeTask task = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1"));
  314. underTest.pauseWorkers();
  315. Optional<CeTask> peek = underTest.peek(WORKER_UUID_1);
  316. assertThat(peek).isEmpty();
  317. underTest.resumeWorkers();
  318. peek = underTest.peek(WORKER_UUID_1);
  319. assertThat(peek).isPresent();
  320. assertThat(peek.get().getUuid()).isEqualTo(task.getUuid());
  321. }
  322. @Test
  323. public void peek_ignores_in_progress_tasks() {
  324. CeQueueDto dto = db.getDbClient().ceQueueDao().insert(session, new CeQueueDto()
  325. .setUuid("uuid")
  326. .setTaskType("foo")
  327. .setStatus(CeQueueDto.Status.PENDING));
  328. makeInProgress(dto, "foo");
  329. db.commit();
  330. assertThat(underTest.peek(WORKER_UUID_1)).isEmpty();
  331. }
  332. @Test
  333. public void peek_nothing_if_application_status_stopping() {
  334. submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1"));
  335. when(computeEngineStatus.getStatus()).thenReturn(STOPPING);
  336. Optional<CeTask> peek = underTest.peek(WORKER_UUID_1);
  337. assertThat(peek.isPresent()).isFalse();
  338. }
  339. @Test
  340. public void peek_peeks_pending_task() {
  341. db.getDbClient().ceQueueDao().insert(session, new CeQueueDto()
  342. .setUuid("uuid")
  343. .setTaskType("foo")
  344. .setStatus(CeQueueDto.Status.PENDING));
  345. db.commit();
  346. assertThat(underTest.peek(WORKER_UUID_1).get().getUuid()).isEqualTo("uuid");
  347. }
  348. @Test
  349. public void peek_resets_to_pending_any_task_in_progress_for_specified_worker_uuid_and_updates_updatedAt() {
  350. insertPending("u0"); // add a pending one that will be picked so that u1 isn't peek and status reset is visible in DB
  351. CeQueueDto u1 = insertPending("u1");// will be picked-because older than any of the reset ones
  352. CeQueueDto u2 = insertInProgress("u2", WORKER_UUID_1);// will be reset
  353. assertThat(underTest.peek(WORKER_UUID_1).get().getUuid()).isEqualTo("u0");
  354. verifyUnmodifiedTask(u1);
  355. verifyResetTask(u2);
  356. }
  357. @Test
  358. public void peek_resets_to_pending_any_task_in_progress_for_specified_worker_uuid_and_only_this_uuid() {
  359. insertPending("u0"); // add a pending one that will be picked so that u1 isn't peek and status reset is visible in DB
  360. CeQueueDto u1 = insertInProgress("u1", WORKER_UUID_1);
  361. CeQueueDto u2 = insertInProgress("u2", WORKER_UUID_2);
  362. CeQueueDto u3 = insertInProgress("u3", WORKER_UUID_1);
  363. CeQueueDto u4 = insertInProgress("u4", WORKER_UUID_2);
  364. assertThat(underTest.peek(WORKER_UUID_1).get().getUuid()).isEqualTo("u0");
  365. verifyResetTask(u1);
  366. verifyUnmodifiedTask(u2);
  367. verifyResetTask(u3);
  368. verifyUnmodifiedTask(u4);
  369. }
  370. private void verifyResetTask(CeQueueDto originalDto) {
  371. CeQueueDto dto = db.getDbClient().ceQueueDao().selectByUuid(session, originalDto.getUuid()).get();
  372. assertThat(dto.getStatus()).isEqualTo(CeQueueDto.Status.PENDING);
  373. assertThat(dto.getCreatedAt()).isEqualTo(originalDto.getCreatedAt());
  374. assertThat(dto.getUpdatedAt()).isGreaterThan(originalDto.getUpdatedAt());
  375. }
  376. private void verifyUnmodifiedTask(CeQueueDto originalDto) {
  377. CeQueueDto dto = db.getDbClient().ceQueueDao().selectByUuid(session, originalDto.getUuid()).get();
  378. assertThat(dto.getStatus()).isEqualTo(originalDto.getStatus());
  379. assertThat(dto.getCreatedAt()).isEqualTo(originalDto.getCreatedAt());
  380. assertThat(dto.getUpdatedAt()).isEqualTo(originalDto.getUpdatedAt());
  381. }
  382. private CeQueueDto insertInProgress(String uuid, String workerUuid) {
  383. CeQueueDto dto = new CeQueueDto()
  384. .setUuid(uuid)
  385. .setTaskType("foo")
  386. .setStatus(CeQueueDto.Status.PENDING);
  387. db.getDbClient().ceQueueDao().insert(session, dto);
  388. makeInProgress(dto, workerUuid);
  389. db.commit();
  390. return db.getDbClient().ceQueueDao().selectByUuid(session, uuid).get();
  391. }
  392. private CeQueueDto insertPending(String uuid) {
  393. CeQueueDto dto = new CeQueueDto()
  394. .setUuid(uuid)
  395. .setTaskType("foo")
  396. .setStatus(CeQueueDto.Status.PENDING);
  397. db.getDbClient().ceQueueDao().insert(session, dto);
  398. db.commit();
  399. return dto;
  400. }
  401. @Test
  402. public void cancel_pending() {
  403. CeTask task = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1"));
  404. CeQueueDto queueDto = db.getDbClient().ceQueueDao().selectByUuid(db.getSession(), task.getUuid()).get();
  405. underTest.cancel(db.getSession(), queueDto);
  406. Optional<CeActivityDto> activity = db.getDbClient().ceActivityDao().selectByUuid(db.getSession(), task.getUuid());
  407. assertThat(activity.isPresent()).isTrue();
  408. assertThat(activity.get().getStatus()).isEqualTo(CeActivityDto.Status.CANCELED);
  409. }
  410. @Test
  411. public void fail_to_cancel_if_in_progress() {
  412. CeTask task = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1"));
  413. underTest.peek(WORKER_UUID_2);
  414. CeQueueDto queueDto = db.getDbClient().ceQueueDao().selectByUuid(db.getSession(), task.getUuid()).get();
  415. expectedException.expect(IllegalStateException.class);
  416. expectedException.expectMessage("Task is in progress and can't be canceled");
  417. underTest.cancel(db.getSession(), queueDto);
  418. }
  419. @Test
  420. public void cancelAll_pendings_but_not_in_progress() {
  421. CeTask inProgressTask = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1"));
  422. CeTask pendingTask1 = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_2"));
  423. CeTask pendingTask2 = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_3"));
  424. underTest.peek(WORKER_UUID_2);
  425. int canceledCount = underTest.cancelAll();
  426. assertThat(canceledCount).isEqualTo(2);
  427. Optional<CeActivityDto> history = db.getDbClient().ceActivityDao().selectByUuid(db.getSession(), pendingTask1.getUuid());
  428. assertThat(history.get().getStatus()).isEqualTo(CeActivityDto.Status.CANCELED);
  429. history = db.getDbClient().ceActivityDao().selectByUuid(db.getSession(), pendingTask2.getUuid());
  430. assertThat(history.get().getStatus()).isEqualTo(CeActivityDto.Status.CANCELED);
  431. history = db.getDbClient().ceActivityDao().selectByUuid(db.getSession(), inProgressTask.getUuid());
  432. assertThat(history.isPresent()).isFalse();
  433. }
  434. @Test
  435. public void resetTasksWithUnknownWorkerUUIDs_reset_only_in_progress_tasks() {
  436. CeQueueDto u1 = insertCeQueueDto("u1");
  437. CeQueueDto u2 = insertCeQueueDto("u2");
  438. CeQueueDto u6 = insertInProgress("u6", "worker1");
  439. CeQueueDto u7 = insertInProgress("u7", "worker2");
  440. CeQueueDto u8 = insertInProgress("u8", "worker3");
  441. underTest.resetTasksWithUnknownWorkerUUIDs(ImmutableSet.of("worker2", "worker3"));
  442. // Pending tasks must not be modified even if a workerUUID is not present
  443. verifyUnmodified(u1);
  444. verifyUnmodified(u2);
  445. // Unknown worker : null, "worker1"
  446. verifyReset(u6);
  447. // Known workers : "worker2", "worker3"
  448. verifyUnmodified(u7);
  449. verifyUnmodified(u8);
  450. }
  451. @Test
  452. public void resetTasksWithUnknownWorkerUUIDs_with_empty_set_will_reset_all_in_progress_tasks() {
  453. CeQueueDto u1 = insertCeQueueDto("u1");
  454. CeQueueDto u2 = insertCeQueueDto("u2");
  455. CeQueueDto u6 = insertInProgress("u6", "worker1");
  456. CeQueueDto u7 = insertInProgress("u7", "worker2");
  457. CeQueueDto u8 = insertInProgress("u8", "worker3");
  458. underTest.resetTasksWithUnknownWorkerUUIDs(ImmutableSet.of());
  459. // Pending tasks must not be modified even if a workerUUID is not present
  460. verifyUnmodified(u1);
  461. verifyUnmodified(u2);
  462. // Unknown worker : null, "worker1"
  463. verifyReset(u6);
  464. verifyReset(u7);
  465. verifyReset(u8);
  466. }
  467. @Test
  468. public void resetTasksWithUnknownWorkerUUIDs_with_worker_without_tasks_will_reset_all_in_progress_tasks() {
  469. CeQueueDto u1 = insertCeQueueDto("u1");
  470. CeQueueDto u2 = insertCeQueueDto("u2");
  471. CeQueueDto u6 = insertInProgress("u6", "worker1");
  472. CeQueueDto u7 = insertInProgress("u7", "worker2");
  473. CeQueueDto u8 = insertInProgress("u8", "worker3");
  474. underTest.resetTasksWithUnknownWorkerUUIDs(ImmutableSet.of("worker1000", "worker1001"));
  475. // Pending tasks must not be modified even if a workerUUID is not present
  476. verifyUnmodified(u1);
  477. verifyUnmodified(u2);
  478. // Unknown worker : null, "worker1"
  479. verifyReset(u6);
  480. verifyReset(u7);
  481. verifyReset(u8);
  482. }
  483. private void verifyReset(CeQueueDto original) {
  484. CeQueueDto dto = db.getDbClient().ceQueueDao().selectByUuid(db.getSession(), original.getUuid()).get();
  485. // We do not touch CreatedAt
  486. assertThat(dto.getCreatedAt()).isEqualTo(original.getCreatedAt());
  487. // Status must have changed to PENDING and must not be equal to previous status
  488. assertThat(dto.getStatus()).isEqualTo(CeQueueDto.Status.PENDING).isNotEqualTo(original.getStatus());
  489. // UpdatedAt must have been updated
  490. assertThat(dto.getUpdatedAt()).isNotEqualTo(original.getUpdatedAt());
  491. assertThat(dto.getStartedAt()).isEqualTo(original.getStartedAt());
  492. // WorkerUuid must be null
  493. assertThat(dto.getWorkerUuid()).isNull();
  494. }
  495. private void verifyUnmodified(CeQueueDto original) {
  496. CeQueueDto dto = db.getDbClient().ceQueueDao().selectByUuid(db.getSession(), original.getUuid()).get();
  497. assertThat(dto.getStatus()).isEqualTo(original.getStatus());
  498. assertThat(dto.getCreatedAt()).isEqualTo(original.getCreatedAt());
  499. assertThat(dto.getUpdatedAt()).isEqualTo(original.getUpdatedAt());
  500. }
  501. private CeQueueDto insertCeQueueDto(String uuid) {
  502. CeQueueDto dto = new CeQueueDto()
  503. .setUuid(uuid)
  504. .setTaskType("foo")
  505. .setStatus(CeQueueDto.Status.PENDING);
  506. db.getDbClient().ceQueueDao().insert(db.getSession(), dto);
  507. db.commit();
  508. return dto;
  509. }
  510. private void verifyCeTask(CeTaskSubmit taskSubmit, CeTask task, @Nullable ComponentDto componentDto, @Nullable UserDto userDto) {
  511. if (componentDto == null) {
  512. assertThat(task.getOrganizationUuid()).isEqualTo(defaultOrganizationProvider.get().getUuid());
  513. } else {
  514. assertThat(task.getOrganizationUuid()).isEqualTo(componentDto.getOrganizationUuid());
  515. }
  516. assertThat(task.getUuid()).isEqualTo(taskSubmit.getUuid());
  517. assertThat(task.getType()).isEqualTo(taskSubmit.getType());
  518. if (componentDto != null) {
  519. CeTask.Component component = task.getComponent().get();
  520. assertThat(component.getUuid()).isEqualTo(componentDto.uuid());
  521. assertThat(component.getKey()).contains(componentDto.getDbKey());
  522. assertThat(component.getName()).contains(componentDto.name());
  523. } else if (taskSubmit.getComponent().isPresent()) {
  524. assertThat(task.getComponent()).contains(new CeTask.Component(taskSubmit.getComponent().get().getUuid(), null, null));
  525. } else {
  526. assertThat(task.getComponent()).isEmpty();
  527. }
  528. if (taskSubmit.getSubmitterUuid() != null) {
  529. if (userDto == null) {
  530. assertThat(task.getSubmitter().getUuid()).isEqualTo(taskSubmit.getSubmitterUuid());
  531. assertThat(task.getSubmitter().getLogin()).isNull();
  532. } else {
  533. assertThat(task.getSubmitter().getUuid()).isEqualTo(userDto.getUuid()).isEqualTo(taskSubmit.getSubmitterUuid());
  534. assertThat(task.getSubmitter().getUuid()).isEqualTo(userDto.getLogin());
  535. }
  536. }
  537. }
  538. private void verifyCeQueueDtoForTaskSubmit(CeTaskSubmit taskSubmit) {
  539. Optional<CeQueueDto> queueDto = db.getDbClient().ceQueueDao().selectByUuid(db.getSession(), taskSubmit.getUuid());
  540. assertThat(queueDto.isPresent()).isTrue();
  541. CeQueueDto dto = queueDto.get();
  542. assertThat(dto.getTaskType()).isEqualTo(taskSubmit.getType());
  543. Optional<CeTaskSubmit.Component> component = taskSubmit.getComponent();
  544. if (component.isPresent()) {
  545. assertThat(dto.getMainComponentUuid()).isEqualTo(component.get().getMainComponentUuid());
  546. assertThat(dto.getComponentUuid()).isEqualTo(component.get().getUuid());
  547. } else {
  548. assertThat(dto.getMainComponentUuid()).isNull();
  549. assertThat(dto.getComponentUuid()).isNull();
  550. }
  551. assertThat(dto.getSubmitterUuid()).isEqualTo(taskSubmit.getSubmitterUuid());
  552. assertThat(dto.getCreatedAt()).isEqualTo(dto.getUpdatedAt()).isNotNull();
  553. }
  554. private ComponentDto newProjectDto(String uuid) {
  555. return ComponentTesting.newPublicProjectDto(db.getDefaultOrganization(), uuid).setName("name_" + uuid).setDbKey("key_" + uuid);
  556. }
  557. private CeTask submit(String reportType, ComponentDto componentDto) {
  558. return underTest.submit(createTaskSubmit(reportType, componentDto, null));
  559. }
  560. private CeTaskSubmit createTaskSubmit(String type) {
  561. return createTaskSubmit(type, null, null);
  562. }
  563. private CeTaskSubmit createTaskSubmit(String type, @Nullable ComponentDto componentDto, @Nullable String submitterUuid) {
  564. CeTaskSubmit.Builder builder = underTest.prepareSubmit()
  565. .setType(type)
  566. .setSubmitterUuid(submitterUuid)
  567. .setCharacteristics(emptyMap());
  568. if (componentDto != null) {
  569. builder.setComponent(CeTaskSubmit.Component.fromDto(componentDto));
  570. }
  571. return builder.build();
  572. }
  573. private CeTaskResult newTaskResult(@Nullable String analysisUuid) {
  574. CeTaskResult taskResult = mock(CeTaskResult.class);
  575. when(taskResult.getAnalysisUuid()).thenReturn(java.util.Optional.ofNullable(analysisUuid));
  576. return taskResult;
  577. }
  578. private ComponentDto insertComponent(ComponentDto componentDto) {
  579. db.getDbClient().componentDao().insert(session, componentDto);
  580. session.commit();
  581. return componentDto;
  582. }
  583. private CeQueueDto makeInProgress(CeQueueDto ceQueueDto, String workerUuid) {
  584. CeQueueTesting.makeInProgress(session, workerUuid, system2.now(), ceQueueDto);
  585. return db.getDbClient().ceQueueDao().selectByUuid(session, ceQueueDto.getUuid()).get();
  586. }
  587. private static String stacktraceToString(Throwable error) {
  588. ByteArrayOutputStream out = new ByteArrayOutputStream();
  589. error.printStackTrace(new PrintStream(out));
  590. return out.toString();
  591. }
  592. }