Skip to content

Commit

Permalink
SONAR-9926 CeQueue#cancel now needs CeQueuDto instead of uuid
Browse files Browse the repository at this point in the history
  • Loading branch information
julienlancelot committed Oct 19, 2017
1 parent 90feaa7 commit 7953067
Show file tree
Hide file tree
Showing 6 changed files with 174 additions and 131 deletions.

Large diffs are not rendered by default.

Expand Up @@ -22,6 +22,9 @@
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;


import org.sonar.db.DbSession;
import org.sonar.db.ce.CeQueueDto;

/** /**
* Queue of pending Compute Engine tasks. Both producer and consumer actions * Queue of pending Compute Engine tasks. Both producer and consumer actions
* are implemented. * are implemented.
Expand Down Expand Up @@ -60,11 +63,8 @@ public interface CeQueue {
/** /**
* Cancels a task in status {@link org.sonar.db.ce.CeQueueDto.Status#PENDING}. An unchecked * Cancels a task in status {@link org.sonar.db.ce.CeQueueDto.Status#PENDING}. An unchecked
* exception is thrown if the status is not {@link org.sonar.db.ce.CeQueueDto.Status#PENDING}. * exception is thrown if the status is not {@link org.sonar.db.ce.CeQueueDto.Status#PENDING}.
* The method does nothing and returns {@code false} if the task does not exist.
*
* @return true if the task exists and is successfully canceled.
*/ */
boolean cancel(String taskUuid); void cancel(DbSession dbSession, CeQueueDto ceQueueDto);


/** /**
* Removes all the tasks from the queue, except the tasks with status * Removes all the tasks from the queue, except the tasks with status
Expand Down
Expand Up @@ -19,17 +19,22 @@
*/ */
package org.sonar.ce.queue; package org.sonar.ce.queue;


import com.google.common.base.Function; import static com.google.common.base.Preconditions.checkState;
import com.google.common.collect.ImmutableMap; import static com.google.common.base.Predicates.notNull;
import static com.google.common.collect.FluentIterable.from;
import static java.util.Collections.singleton;
import static java.util.Objects.requireNonNull;

import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;

import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;

import org.sonar.api.ce.ComputeEngineSide; import org.sonar.api.ce.ComputeEngineSide;
import org.sonar.core.util.UuidFactory; import org.sonar.core.util.UuidFactory;
import org.sonar.db.DbClient; import org.sonar.db.DbClient;
Expand All @@ -39,11 +44,8 @@
import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ComponentDto;
import org.sonar.server.organization.DefaultOrganizationProvider; import org.sonar.server.organization.DefaultOrganizationProvider;


import static com.google.common.base.Preconditions.checkState; import com.google.common.base.Function;
import static com.google.common.base.Predicates.notNull; import com.google.common.collect.ImmutableMap;
import static com.google.common.collect.FluentIterable.from;
import static java.util.Collections.singleton;
import static java.util.Objects.requireNonNull;


@ComputeEngineSide @ComputeEngineSide
public class CeQueueImpl implements CeQueue { public class CeQueueImpl implements CeQueue {
Expand Down Expand Up @@ -121,16 +123,9 @@ private List<CeTask> loadTasks(DbSession dbSession, List<CeQueueDto> dtos) {
} }


@Override @Override
public boolean cancel(String taskUuid) { public void cancel(DbSession dbSession, CeQueueDto ceQueueDto) {
try (DbSession dbSession = dbClient.openSession(false)) { checkState(CeQueueDto.Status.PENDING.equals(ceQueueDto.getStatus()), "Task is in progress and can't be canceled [uuid=%s]", ceQueueDto.getUuid());
Optional<CeQueueDto> queueDto = dbClient.ceQueueDao().selectByUuid(dbSession, taskUuid); cancelImpl(dbSession, ceQueueDto);
if (queueDto.isPresent()) {
checkState(CeQueueDto.Status.PENDING.equals(queueDto.get().getStatus()), "Task is in progress and can't be canceled [uuid=%s]", taskUuid);
cancelImpl(dbSession, queueDto.get());
return true;
}
return false;
}
} }


private void cancelImpl(DbSession dbSession, CeQueueDto q) { private void cancelImpl(DbSession dbSession, CeQueueDto q) {
Expand Down
Expand Up @@ -19,29 +19,42 @@
*/ */
package org.sonar.server.ce.ws; package org.sonar.server.ce.ws;


import java.util.Optional;

import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService; import org.sonar.api.server.ws.WebService;
import org.sonar.ce.queue.CeQueue; import org.sonar.ce.queue.CeQueue;
import org.sonar.core.util.Uuids; import org.sonar.core.util.Uuids;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.ce.CeQueueDto;
import org.sonar.server.user.UserSession; import org.sonar.server.user.UserSession;


public class CancelAction implements CeWsAction { public class CancelAction implements CeWsAction {


public static final String PARAM_TASK_ID = "id"; public static final String PARAM_TASK_ID = "id";


private final UserSession userSession; private final UserSession userSession;
private DbClient dbClient;
private final CeQueue queue; private final CeQueue queue;


public CancelAction(UserSession userSession, CeQueue queue) { public CancelAction(UserSession userSession, DbClient dbClient, CeQueue queue) {
this.userSession = userSession; this.userSession = userSession;
this.dbClient = dbClient;
this.queue = queue; this.queue = queue;
} }


@Override @Override
public void define(WebService.NewController controller) { public void define(WebService.NewController controller) {
WebService.NewAction action = controller.createAction("cancel") WebService.NewAction action = controller.createAction("cancel")
.setDescription("Cancels a pending task. Requires system administration permission. In-progress tasks cannot be canceled.") .setDescription("Cancels a pending task.<br/>" +
"In-progress tasks cannot be canceled.<br/>" +
"Requires one of the following permissions:" +
"<ul>" +
"<li>'Administer System'</li>" +
"<li>'Administer' rights on the project related to the task</li>" +
"</ul>")
.setInternal(true) .setInternal(true)
.setPost(true) .setPost(true)
.setSince("5.2") .setSince("5.2")
Expand All @@ -58,7 +71,13 @@ public void define(WebService.NewController controller) {
public void handle(Request wsRequest, Response wsResponse) { public void handle(Request wsRequest, Response wsResponse) {
userSession.checkIsSystemAdministrator(); userSession.checkIsSystemAdministrator();
String taskId = wsRequest.mandatoryParam(PARAM_TASK_ID); String taskId = wsRequest.mandatoryParam(PARAM_TASK_ID);
queue.cancel(taskId); try (DbSession dbSession = dbClient.openSession(false)) {
Optional<CeQueueDto> queueDto = dbClient.ceQueueDao().selectByUuid(dbSession, taskId);
queueDto.ifPresent(dto -> {
queue.cancel(dbSession, dto);
});
}
wsResponse.noContent(); wsResponse.noContent();
} }

} }
Expand Up @@ -19,9 +19,15 @@
*/ */
package org.sonar.ce.queue; package org.sonar.ce.queue;


import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.startsWith;

import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;

import javax.annotation.Nullable; import javax.annotation.Nullable;

import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.ExpectedException; import org.junit.rules.ExpectedException;
Expand All @@ -39,10 +45,6 @@
import org.sonar.server.organization.DefaultOrganizationProvider; import org.sonar.server.organization.DefaultOrganizationProvider;
import org.sonar.server.organization.TestDefaultOrganizationProvider; 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 { public class CeQueueImplTest {


private static final String WORKER_UUID = "workerUuid"; private static final String WORKER_UUID = "workerUuid";
Expand All @@ -53,18 +55,19 @@ public class CeQueueImplTest {
@Rule @Rule
public ExpectedException expectedException = ExpectedException.none(); public ExpectedException expectedException = ExpectedException.none();
@Rule @Rule
public DbTester dbTester = DbTester.create(system2); public DbTester db = DbTester.create(system2);


private DbSession session = dbTester.getSession(); private DbSession session = db.getSession();


private UuidFactory uuidFactory = UuidFactoryImpl.INSTANCE; private UuidFactory uuidFactory = UuidFactoryImpl.INSTANCE;
private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(dbTester); private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db);


private CeQueue underTest = new CeQueueImpl(dbTester.getDbClient(), uuidFactory, defaultOrganizationProvider); private CeQueue underTest = new CeQueueImpl(db.getDbClient(), uuidFactory, defaultOrganizationProvider);


@Test @Test
public void submit_returns_task_populated_from_CeTaskSubmit_and_creates_CeQueue_row() { public void submit_returns_task_populated_from_CeTaskSubmit_and_creates_CeQueue_row() {
CeTaskSubmit taskSubmit = createTaskSubmit(CeTaskTypes.REPORT, "PROJECT_1", "rob"); CeTaskSubmit taskSubmit = createTaskSubmit(CeTaskTypes.REPORT, "PROJECT_1", "rob");

CeTask task = underTest.submit(taskSubmit); CeTask task = underTest.submit(taskSubmit);


verifyCeTask(taskSubmit, task, null); verifyCeTask(taskSubmit, task, null);
Expand All @@ -73,7 +76,7 @@ public void submit_returns_task_populated_from_CeTaskSubmit_and_creates_CeQueue_


@Test @Test
public void submit_populates_component_name_and_key_of_CeTask_if_component_exists() { public void submit_populates_component_name_and_key_of_CeTask_if_component_exists() {
ComponentDto componentDto = insertComponent(ComponentTesting.newPrivateProjectDto(dbTester.organizations().insert(), "PROJECT_1")); ComponentDto componentDto = insertComponent(ComponentTesting.newPrivateProjectDto(db.organizations().insert(), "PROJECT_1"));
CeTaskSubmit taskSubmit = createTaskSubmit(CeTaskTypes.REPORT, componentDto.uuid(), null); CeTaskSubmit taskSubmit = createTaskSubmit(CeTaskTypes.REPORT, componentDto.uuid(), null);


CeTask task = underTest.submit(taskSubmit); CeTask task = underTest.submit(taskSubmit);
Expand Down Expand Up @@ -116,7 +119,7 @@ public void massSubmit_returns_tasks_for_each_CeTaskSubmit_populated_from_CeTask


@Test @Test
public void massSubmit_populates_component_name_and_key_of_CeTask_if_component_exists() { public void massSubmit_populates_component_name_and_key_of_CeTask_if_component_exists() {
ComponentDto componentDto1 = insertComponent(ComponentTesting.newPrivateProjectDto(dbTester.getDefaultOrganization(), "PROJECT_1")); ComponentDto componentDto1 = insertComponent(ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization(), "PROJECT_1"));
CeTaskSubmit taskSubmit1 = createTaskSubmit(CeTaskTypes.REPORT, componentDto1.uuid(), null); CeTaskSubmit taskSubmit1 = createTaskSubmit(CeTaskTypes.REPORT, componentDto1.uuid(), null);
CeTaskSubmit taskSubmit2 = createTaskSubmit("something", "non existing component uuid", null); CeTaskSubmit taskSubmit2 = createTaskSubmit("something", "non existing component uuid", null);


Expand All @@ -130,28 +133,24 @@ public void massSubmit_populates_component_name_and_key_of_CeTask_if_component_e
@Test @Test
public void cancel_pending() throws Exception { public void cancel_pending() throws Exception {
CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1"); CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1");
CeQueueDto queueDto = db.getDbClient().ceQueueDao().selectByUuid(db.getSession(), task.getUuid()).get();


// ignore underTest.cancel(db.getSession(), queueDto);
boolean canceled = underTest.cancel("UNKNOWN");
assertThat(canceled).isFalse();


canceled = underTest.cancel(task.getUuid()); Optional<CeActivityDto> activity = db.getDbClient().ceActivityDao().selectByUuid(db.getSession(), task.getUuid());
assertThat(canceled).isTrue();
Optional<CeActivityDto> activity = dbTester.getDbClient().ceActivityDao().selectByUuid(dbTester.getSession(), task.getUuid());
assertThat(activity.isPresent()).isTrue(); assertThat(activity.isPresent()).isTrue();
assertThat(activity.get().getStatus()).isEqualTo(CeActivityDto.Status.CANCELED); assertThat(activity.get().getStatus()).isEqualTo(CeActivityDto.Status.CANCELED);
} }


@Test @Test
public void fail_to_cancel_if_in_progress() throws Exception { public void fail_to_cancel_if_in_progress() throws Exception {
submit(CeTaskTypes.REPORT, "PROJECT_1");
CeQueueDto ceQueueDto = db.getDbClient().ceQueueDao().peek(session, WORKER_UUID, MAX_EXECUTION_COUNT).get();

expectedException.expect(IllegalStateException.class); expectedException.expect(IllegalStateException.class);
expectedException.expectMessage(startsWith("Task is in progress and can't be canceled")); expectedException.expectMessage(startsWith("Task is in progress and can't be canceled"));


CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1"); underTest.cancel(db.getSession(), ceQueueDto);

dbTester.getDbClient().ceQueueDao().peek(session, WORKER_UUID, MAX_EXECUTION_COUNT);

underTest.cancel(task.getUuid());
} }


@Test @Test
Expand All @@ -160,16 +159,16 @@ public void cancelAll_pendings_but_not_in_progress() throws Exception {
CeTask pendingTask1 = submit(CeTaskTypes.REPORT, "PROJECT_2"); CeTask pendingTask1 = submit(CeTaskTypes.REPORT, "PROJECT_2");
CeTask pendingTask2 = submit(CeTaskTypes.REPORT, "PROJECT_3"); CeTask pendingTask2 = submit(CeTaskTypes.REPORT, "PROJECT_3");


dbTester.getDbClient().ceQueueDao().peek(session, WORKER_UUID, MAX_EXECUTION_COUNT); db.getDbClient().ceQueueDao().peek(session, WORKER_UUID, MAX_EXECUTION_COUNT);


int canceledCount = underTest.cancelAll(); int canceledCount = underTest.cancelAll();
assertThat(canceledCount).isEqualTo(2); assertThat(canceledCount).isEqualTo(2);


Optional<CeActivityDto> history = dbTester.getDbClient().ceActivityDao().selectByUuid(dbTester.getSession(), pendingTask1.getUuid()); Optional<CeActivityDto> history = db.getDbClient().ceActivityDao().selectByUuid(db.getSession(), pendingTask1.getUuid());
assertThat(history.get().getStatus()).isEqualTo(CeActivityDto.Status.CANCELED); assertThat(history.get().getStatus()).isEqualTo(CeActivityDto.Status.CANCELED);
history = dbTester.getDbClient().ceActivityDao().selectByUuid(dbTester.getSession(), pendingTask2.getUuid()); history = db.getDbClient().ceActivityDao().selectByUuid(db.getSession(), pendingTask2.getUuid());
assertThat(history.get().getStatus()).isEqualTo(CeActivityDto.Status.CANCELED); assertThat(history.get().getStatus()).isEqualTo(CeActivityDto.Status.CANCELED);
history = dbTester.getDbClient().ceActivityDao().selectByUuid(dbTester.getSession(), inProgressTask.getUuid()); history = db.getDbClient().ceActivityDao().selectByUuid(db.getSession(), inProgressTask.getUuid());
assertThat(history.isPresent()).isFalse(); assertThat(history.isPresent()).isFalse();
} }


Expand Down Expand Up @@ -202,7 +201,7 @@ private void verifyCeTask(CeTaskSubmit taskSubmit, CeTask task, @Nullable Compon
} }


private void verifyCeQueueDtoForTaskSubmit(CeTaskSubmit taskSubmit) { private void verifyCeQueueDtoForTaskSubmit(CeTaskSubmit taskSubmit) {
Optional<CeQueueDto> queueDto = dbTester.getDbClient().ceQueueDao().selectByUuid(dbTester.getSession(), taskSubmit.getUuid()); Optional<CeQueueDto> queueDto = db.getDbClient().ceQueueDao().selectByUuid(db.getSession(), taskSubmit.getUuid());
assertThat(queueDto.isPresent()).isTrue(); assertThat(queueDto.isPresent()).isTrue();
assertThat(queueDto.get().getTaskType()).isEqualTo(taskSubmit.getType()); assertThat(queueDto.get().getTaskType()).isEqualTo(taskSubmit.getType());
assertThat(queueDto.get().getComponentUuid()).isEqualTo(taskSubmit.getComponentUuid()); assertThat(queueDto.get().getComponentUuid()).isEqualTo(taskSubmit.getComponentUuid());
Expand All @@ -227,7 +226,7 @@ private CeTaskSubmit createTaskSubmit(String type, @Nullable String componentUui
} }


private ComponentDto insertComponent(ComponentDto componentDto) { private ComponentDto insertComponent(ComponentDto componentDto) {
dbTester.getDbClient().componentDao().insert(session, componentDto); db.getDbClient().componentDao().insert(session, componentDto);
session.commit(); session.commit();
return componentDto; return componentDto;
} }
Expand Down
Expand Up @@ -19,38 +19,62 @@
*/ */
package org.sonar.server.ce.ws; package org.sonar.server.ce.ws;


import static org.assertj.core.api.Java6Assertions.assertThat;

import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.ExpectedException; import org.junit.rules.ExpectedException;
import org.sonar.ce.queue.CeQueue; import org.sonar.ce.queue.CeQueue;
import org.sonar.ce.queue.CeQueueImpl;
import org.sonar.ce.queue.CeTask;
import org.sonar.ce.queue.CeTaskSubmit;
import org.sonar.core.util.UuidFactoryFast;
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.server.exceptions.ForbiddenException; import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.organization.DefaultOrganizationProvider;
import org.sonar.server.organization.TestDefaultOrganizationProvider;
import org.sonar.server.tester.UserSessionRule; import org.sonar.server.tester.UserSessionRule;
import org.sonar.server.ws.WsActionTester; import org.sonar.server.ws.WsActionTester;


import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;

public class CancelActionTest { public class CancelActionTest {


@Rule @Rule
public UserSessionRule userSession = UserSessionRule.standalone(); public UserSessionRule userSession = UserSessionRule.standalone();
@Rule @Rule
public ExpectedException expectedException = ExpectedException.none(); public ExpectedException expectedException = ExpectedException.none();
@Rule
public DbTester db = DbTester.create();

private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db);
private CeQueue queue = new CeQueueImpl(db.getDbClient(), UuidFactoryFast.getInstance(), defaultOrganizationProvider);


private CeQueue queue = mock(CeQueue.class); private CancelAction underTest = new CancelAction(userSession, db.getDbClient(), queue);
private CancelAction underTest = new CancelAction(userSession, queue);
private WsActionTester tester = new WsActionTester(underTest); private WsActionTester tester = new WsActionTester(underTest);


@Test @Test
public void cancel_pending_task() { public void cancel_pending_task() {
logInAsSystemAdministrator(); logInAsSystemAdministrator();
ComponentDto project = db.components().insertPrivateProject();
CeQueueDto queue = createTaskSubmit(project);


tester.newRequest() tester.newRequest()
.setParam("id", "T1") .setParam("id", queue.getUuid())
.execute(); .execute();


verify(queue).cancel("T1"); assertThat(db.getDbClient().ceActivityDao().selectByUuid(db.getSession(), queue.getUuid()).get().getStatus()).isEqualTo(CeActivityDto.Status.CANCELED);
}

@Test
public void does_not_fail_on_unknown_task() {
logInAsSystemAdministrator();

tester.newRequest()
.setParam("id", "UNKNOWN")
.execute();
} }


@Test @Test
Expand All @@ -61,8 +85,6 @@ public void throw_IllegalArgumentException_if_missing_id() {
expectedException.expectMessage("The 'id' parameter is missing"); expectedException.expectMessage("The 'id' parameter is missing");


tester.newRequest().execute(); tester.newRequest().execute();

verifyZeroInteractions(queue);
} }


@Test @Test
Expand All @@ -75,11 +97,18 @@ public void throw_ForbiddenException_if_not_system_administrator() {
tester.newRequest() tester.newRequest()
.setParam("id", "T1") .setParam("id", "T1")
.execute(); .execute();

verifyZeroInteractions(queue);
} }


private void logInAsSystemAdministrator() { private void logInAsSystemAdministrator() {
userSession.logIn().setSystemAdministrator(); userSession.logIn().setSystemAdministrator();
} }

private CeQueueDto createTaskSubmit(ComponentDto component) {
CeTaskSubmit.Builder submission = queue.prepareSubmit();
submission.setType(CeTaskTypes.REPORT);
submission.setComponentUuid(component.uuid());
submission.setSubmitterLogin(null);
CeTask task = queue.submit(submission.build());
return db.getDbClient().ceQueueDao().selectByUuid(db.getSession(), task.getUuid()).get();
}
} }

0 comments on commit 7953067

Please sign in to comment.