/* * SonarQube * Copyright (C) 2009-2017 SonarSource SA * mailto:info AT sonarsource DOT com * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package org.sonar.ce.queue; import java.util.List; import java.util.Optional; import javax.annotation.Nullable; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.sonar.api.utils.System2; import org.sonar.api.utils.internal.TestSystem2; import org.sonar.core.util.UuidFactory; import org.sonar.core.util.UuidFactoryImpl; import org.sonar.db.DbSession; import org.sonar.db.DbTester; import org.sonar.db.ce.CeActivityDto; import org.sonar.db.ce.CeQueueDto; import org.sonar.db.ce.CeTaskTypes; import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ComponentTesting; import org.sonar.server.organization.DefaultOrganizationProvider; import org.sonar.server.organization.TestDefaultOrganizationProvider; import static java.util.Arrays.asList; import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.Matchers.startsWith; public class CeQueueImplTest { private static final String WORKER_UUID = "workerUuid"; private static final int MAX_EXECUTION_COUNT = 3; private System2 system2 = new TestSystem2().setNow(1_450_000_000_000L); @Rule public ExpectedException expectedException = ExpectedException.none(); @Rule public DbTester dbTester = DbTester.create(system2); private DbSession session = dbTester.getSession(); private UuidFactory uuidFactory = UuidFactoryImpl.INSTANCE; private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(dbTester); private CeQueue underTest = new CeQueueImpl(dbTester.getDbClient(), uuidFactory, defaultOrganizationProvider); @Test public void submit_returns_task_populated_from_CeTaskSubmit_and_creates_CeQueue_row() { CeTaskSubmit taskSubmit = createTaskSubmit(CeTaskTypes.REPORT, "PROJECT_1", "rob"); CeTask task = underTest.submit(taskSubmit); verifyCeTask(taskSubmit, task, null); verifyCeQueueDtoForTaskSubmit(taskSubmit); } @Test public void submit_populates_component_name_and_key_of_CeTask_if_component_exists() { ComponentDto componentDto = insertComponent(ComponentTesting.newPrivateProjectDto(dbTester.organizations().insert(), "PROJECT_1")); CeTaskSubmit taskSubmit = createTaskSubmit(CeTaskTypes.REPORT, componentDto.uuid(), null); CeTask task = underTest.submit(taskSubmit); verifyCeTask(taskSubmit, task, componentDto); } @Test public void submit_returns_task_without_component_info_when_submit_has_none() { CeTaskSubmit taskSubmit = createTaskSubmit("not cpt related"); CeTask task = underTest.submit(taskSubmit); verifyCeTask(taskSubmit, task, null); } @Test public void submit_fails_with_ISE_if_paused() { underTest.pauseSubmit(); expectedException.expect(IllegalStateException.class); expectedException.expectMessage("Compute Engine does not currently accept new tasks"); submit(CeTaskTypes.REPORT, "PROJECT_1"); } @Test public void massSubmit_returns_tasks_for_each_CeTaskSubmit_populated_from_CeTaskSubmit_and_creates_CeQueue_row_for_each() { CeTaskSubmit taskSubmit1 = createTaskSubmit(CeTaskTypes.REPORT, "PROJECT_1", "rob"); CeTaskSubmit taskSubmit2 = createTaskSubmit("some type"); List<CeTask> tasks = underTest.massSubmit(asList(taskSubmit1, taskSubmit2)); assertThat(tasks).hasSize(2); verifyCeTask(taskSubmit1, tasks.get(0), null); verifyCeTask(taskSubmit2, tasks.get(1), null); verifyCeQueueDtoForTaskSubmit(taskSubmit1); verifyCeQueueDtoForTaskSubmit(taskSubmit2); } @Test public void massSubmit_populates_component_name_and_key_of_CeTask_if_component_exists() { ComponentDto componentDto1 = insertComponent(ComponentTesting.newPrivateProjectDto(dbTester.getDefaultOrganization(), "PROJECT_1")); CeTaskSubmit taskSubmit1 = createTaskSubmit(CeTaskTypes.REPORT, componentDto1.uuid(), null); CeTaskSubmit taskSubmit2 = createTaskSubmit("something", "non existing component uuid", null); List<CeTask> tasks = underTest.massSubmit(asList(taskSubmit1, taskSubmit2)); assertThat(tasks).hasSize(2); verifyCeTask(taskSubmit1, tasks.get(0), componentDto1); verifyCeTask(taskSubmit2, tasks.get(1), null); } @Test public void cancel_pending() throws Exception { CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1"); // ignore boolean canceled = underTest.cancel("UNKNOWN"); assertThat(canceled).isFalse(); canceled = underTest.cancel(task.getUuid()); assertThat(canceled).isTrue(); Optional<CeActivityDto> activity = dbTester.getDbClient().ceActivityDao().selectByUuid(dbTester.getSession(), task.getUuid()); assertThat(activity.isPresent()).isTrue(); assertThat(activity.get().getStatus()).isEqualTo(CeActivityDto.Status.CANCELED); } @Test public void fail_to_cancel_if_in_progress() throws Exception { expectedException.expect(IllegalStateException.class); expectedException.expectMessage(startsWith("Task is in progress and can't be canceled")); CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1"); dbTester.getDbClient().ceQueueDao().peek(session, WORKER_UUID, MAX_EXECUTION_COUNT); underTest.cancel(task.getUuid()); } @Test public void cancelAll_pendings_but_not_in_progress() throws Exception { CeTask inProgressTask = submit(CeTaskTypes.REPORT, "PROJECT_1"); CeTask pendingTask1 = submit(CeTaskTypes.REPORT, "PROJECT_2"); CeTask pendingTask2 = submit(CeTaskTypes.REPORT, "PROJECT_3"); dbTester.getDbClient().ceQueueDao().peek(session, WORKER_UUID, MAX_EXECUTION_COUNT); int canceledCount = underTest.cancelAll(); assertThat(canceledCount).isEqualTo(2); Optional<CeActivityDto> history = dbTester.getDbClient().ceActivityDao().selectByUuid(dbTester.getSession(), pendingTask1.getUuid()); assertThat(history.get().getStatus()).isEqualTo(CeActivityDto.Status.CANCELED); history = dbTester.getDbClient().ceActivityDao().selectByUuid(dbTester.getSession(), pendingTask2.getUuid()); assertThat(history.get().getStatus()).isEqualTo(CeActivityDto.Status.CANCELED); history = dbTester.getDbClient().ceActivityDao().selectByUuid(dbTester.getSession(), inProgressTask.getUuid()); assertThat(history.isPresent()).isFalse(); } @Test public void pause_and_resume_submits() throws Exception { assertThat(underTest.isSubmitPaused()).isFalse(); underTest.pauseSubmit(); assertThat(underTest.isSubmitPaused()).isTrue(); underTest.resumeSubmit(); assertThat(underTest.isSubmitPaused()).isFalse(); } private void verifyCeTask(CeTaskSubmit taskSubmit, CeTask task, @Nullable ComponentDto componentDto) { if (componentDto == null) { assertThat(task.getOrganizationUuid()).isEqualTo(defaultOrganizationProvider.get().getUuid()); } else { assertThat(task.getOrganizationUuid()).isEqualTo(componentDto.getOrganizationUuid()); } assertThat(task.getUuid()).isEqualTo(taskSubmit.getUuid()); assertThat(task.getComponentUuid()).isEqualTo(task.getComponentUuid()); assertThat(task.getType()).isEqualTo(taskSubmit.getType()); if (componentDto == null) { assertThat(task.getComponentKey()).isNull(); assertThat(task.getComponentName()).isNull(); } else { assertThat(task.getComponentKey()).isEqualTo(componentDto.key()); assertThat(task.getComponentName()).isEqualTo(componentDto.name()); } assertThat(task.getSubmitterLogin()).isEqualTo(taskSubmit.getSubmitterLogin()); } private void verifyCeQueueDtoForTaskSubmit(CeTaskSubmit taskSubmit) { Optional<CeQueueDto> queueDto = dbTester.getDbClient().ceQueueDao().selectByUuid(dbTester.getSession(), taskSubmit.getUuid()); assertThat(queueDto.isPresent()).isTrue(); assertThat(queueDto.get().getTaskType()).isEqualTo(taskSubmit.getType()); assertThat(queueDto.get().getComponentUuid()).isEqualTo(taskSubmit.getComponentUuid()); assertThat(queueDto.get().getSubmitterLogin()).isEqualTo(taskSubmit.getSubmitterLogin()); assertThat(queueDto.get().getCreatedAt()).isEqualTo(1_450_000_000_000L); } private CeTask submit(String reportType, String componentUuid) { return underTest.submit(createTaskSubmit(reportType, componentUuid, null)); } private CeTaskSubmit createTaskSubmit(String type) { return createTaskSubmit(type, null, null); } private CeTaskSubmit createTaskSubmit(String type, @Nullable String componentUuid, @Nullable String submitterLogin) { CeTaskSubmit.Builder submission = underTest.prepareSubmit(); submission.setType(type); submission.setComponentUuid(componentUuid); submission.setSubmitterLogin(submitterLogin); return submission.build(); } private ComponentDto insertComponent(ComponentDto componentDto) { dbTester.getDbClient().componentDao().insert(session, componentDto); session.commit(); return componentDto; } }