- add main_component_uuid temporary columns to CE_QUEUE - add main_last_key and main_component_uuid columns to CE_ACTIVITY - back to initial paradigm in Compute Engine: even for branches/PRs, the row in table PROJECTS a task belongs to is created in api/ce/submit - add main component concept to CeTask - improved consistency check when processing a report task to account for row in PROJECTS now being the one of the branche/PR - stronger validation of characteristics passed to api/ce/submit - add api/system/migrate_data for SonarCloud online data migrationtags/7.5
@@ -57,7 +57,7 @@ public interface CeQueue { | |||
* <p> | |||
* This method is equivalent to calling {@code massSubmit(Collections.singletonList(submission))}. | |||
* | |||
* @return empty if {@code options} contains {@link SubmitOption#UNIQUE_QUEUE_PER_COMPONENT UNIQUE_QUEUE_PER_COMPONENT} | |||
* @return empty if {@code options} contains {@link SubmitOption#UNIQUE_QUEUE_PER_MAIN_COMPONENT UNIQUE_QUEUE_PER_MAIN_COMPONENT} | |||
* and there's already a queued task, otherwise the created task. | |||
*/ | |||
Optional<CeTask> submit(CeTaskSubmit submission, SubmitOption... options); | |||
@@ -102,7 +102,7 @@ public interface CeQueue { | |||
WorkersPauseStatus getWorkersPauseStatus(); | |||
enum SubmitOption { | |||
UNIQUE_QUEUE_PER_COMPONENT | |||
UNIQUE_QUEUE_PER_MAIN_COMPONENT | |||
} | |||
enum WorkersPauseStatus { |
@@ -28,9 +28,11 @@ import java.util.EnumSet; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Objects; | |||
import java.util.Optional; | |||
import java.util.Set; | |||
import java.util.function.Predicate; | |||
import java.util.stream.Collectors; | |||
import java.util.stream.Stream; | |||
import javax.annotation.Nullable; | |||
import org.sonar.api.server.ServerSide; | |||
import org.sonar.api.utils.log.Loggers; | |||
@@ -48,8 +50,11 @@ import org.sonar.server.organization.DefaultOrganizationProvider; | |||
import org.sonar.server.property.InternalProperties; | |||
import static com.google.common.base.Preconditions.checkState; | |||
import static java.util.Collections.emptyMap; | |||
import static java.util.Collections.singleton; | |||
import static org.sonar.ce.queue.CeQueue.SubmitOption.UNIQUE_QUEUE_PER_COMPONENT; | |||
import static java.util.Optional.of; | |||
import static java.util.Optional.ofNullable; | |||
import static org.sonar.ce.queue.CeQueue.SubmitOption.UNIQUE_QUEUE_PER_MAIN_COMPONENT; | |||
import static org.sonar.core.util.stream.MoreCollectors.toEnumSet; | |||
import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex; | |||
import static org.sonar.db.ce.CeQueueDto.Status.PENDING; | |||
@@ -78,30 +83,45 @@ public class CeQueueImpl implements CeQueue { | |||
} | |||
@Override | |||
public java.util.Optional<CeTask> submit(CeTaskSubmit submission, SubmitOption... options) { | |||
public Optional<CeTask> submit(CeTaskSubmit submission, SubmitOption... options) { | |||
return submit(submission, toSet(options)); | |||
} | |||
private java.util.Optional<CeTask> submit(CeTaskSubmit submission, EnumSet<SubmitOption> submitOptions) { | |||
private Optional<CeTask> submit(CeTaskSubmit submission, EnumSet<SubmitOption> submitOptions) { | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
if (submitOptions.contains(UNIQUE_QUEUE_PER_COMPONENT) | |||
&& submission.getComponentUuid() != null | |||
&& dbClient.ceQueueDao().countByStatusAndComponentUuid(dbSession, PENDING, submission.getComponentUuid()) > 0) { | |||
return java.util.Optional.empty(); | |||
if (submitOptions.contains(UNIQUE_QUEUE_PER_MAIN_COMPONENT) | |||
&& submission.getComponent() | |||
.map(component -> dbClient.ceQueueDao().countByStatusAndMainComponentUuid(dbSession, PENDING, component.getMainComponentUuid()) > 0) | |||
.orElse(false)) { | |||
return Optional.empty(); | |||
} | |||
CeQueueDto taskDto = addToQueueInDb(dbSession, submission); | |||
dbSession.commit(); | |||
ComponentDto component = null; | |||
String componentUuid = taskDto.getComponentUuid(); | |||
if (componentUuid != null) { | |||
component = dbClient.componentDao().selectByUuid(dbSession, componentUuid).orElse(null); | |||
Map<String, ComponentDto> componentsByUuid = loadComponentDtos(dbSession, taskDto); | |||
if (componentsByUuid.isEmpty()) { | |||
return of(convertToTask(taskDto, submission.getCharacteristics(), null, null)); | |||
} | |||
CeTask task = convertToTask(taskDto, submission.getCharacteristics(), component); | |||
return java.util.Optional.of(task); | |||
return of(convertToTask(taskDto, submission.getCharacteristics(), | |||
ofNullable(taskDto.getComponentUuid()).map(componentsByUuid::get).orElse(null), | |||
ofNullable(taskDto.getMainComponentUuid()).map(componentsByUuid::get).orElse(null))); | |||
} | |||
} | |||
Map<String, ComponentDto> loadComponentDtos(DbSession dbSession, CeQueueDto taskDto) { | |||
Set<String> componentUuids = Stream.of(taskDto.getComponentUuid(), taskDto.getMainComponentUuid()) | |||
.filter(Objects::nonNull) | |||
.collect(MoreCollectors.toSet(2)); | |||
if (componentUuids.isEmpty()) { | |||
return emptyMap(); | |||
} | |||
return dbClient.componentDao().selectByUuids(dbSession, componentUuids) | |||
.stream() | |||
.collect(uniqueIndex(ComponentDto::uuid, 2)); | |||
} | |||
@Override | |||
public List<CeTask> massSubmit(Collection<CeTaskSubmit> submissions, SubmitOption... options) { | |||
if (submissions.isEmpty()) { | |||
@@ -109,11 +129,11 @@ public class CeQueueImpl implements CeQueue { | |||
} | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
List<CeQueueDto> taskDto = submissions.stream() | |||
List<CeQueueDto> taskDtos = submissions.stream() | |||
.filter(filterBySubmitOptions(options, submissions, dbSession)) | |||
.map(submission -> addToQueueInDb(dbSession, submission)) | |||
.collect(Collectors.toList()); | |||
List<CeTask> tasks = loadTasks(dbSession, taskDto); | |||
List<CeTask> tasks = loadTasks(dbSession, taskDtos); | |||
dbSession.commit(); | |||
return tasks; | |||
} | |||
@@ -122,31 +142,34 @@ public class CeQueueImpl implements CeQueue { | |||
private Predicate<CeTaskSubmit> filterBySubmitOptions(SubmitOption[] options, Collection<CeTaskSubmit> submissions, DbSession dbSession) { | |||
EnumSet<SubmitOption> submitOptions = toSet(options); | |||
if (submitOptions.contains(UNIQUE_QUEUE_PER_COMPONENT)) { | |||
Set<String> componentUuids = submissions.stream() | |||
.map(CeTaskSubmit::getComponentUuid) | |||
.filter(Objects::nonNull) | |||
if (submitOptions.contains(UNIQUE_QUEUE_PER_MAIN_COMPONENT)) { | |||
Set<String> mainComponentUuids = submissions.stream() | |||
.map(CeTaskSubmit::getComponent) | |||
.filter(Optional::isPresent) | |||
.map(Optional::get) | |||
.map(CeTaskSubmit.Component::getMainComponentUuid) | |||
.collect(MoreCollectors.toSet(submissions.size())); | |||
if (componentUuids.isEmpty()) { | |||
if (mainComponentUuids.isEmpty()) { | |||
return t -> true; | |||
} | |||
return new NoPendingTaskFilter(dbSession, componentUuids); | |||
return new NoPendingTaskFilter(dbSession, mainComponentUuids); | |||
} | |||
return t -> true; | |||
} | |||
private class NoPendingTaskFilter implements Predicate<CeTaskSubmit> { | |||
private final Map<String, Integer> queuedItemsByComponentUuid; | |||
private final Map<String, Integer> queuedItemsByMainComponentUuid; | |||
private NoPendingTaskFilter(DbSession dbSession, Set<String> componentUuids) { | |||
queuedItemsByComponentUuid = dbClient.ceQueueDao().countByStatusAndComponentUuids(dbSession, PENDING, componentUuids); | |||
private NoPendingTaskFilter(DbSession dbSession, Set<String> projectUuids) { | |||
queuedItemsByMainComponentUuid = dbClient.ceQueueDao().countByStatusAndMainComponentUuids(dbSession, PENDING, projectUuids); | |||
} | |||
@Override | |||
public boolean test(CeTaskSubmit ceTaskSubmit) { | |||
String componentUuid = ceTaskSubmit.getComponentUuid(); | |||
return componentUuid == null || queuedItemsByComponentUuid.getOrDefault(componentUuid, 0) == 0; | |||
return ceTaskSubmit.getComponent() | |||
.map(component -> queuedItemsByMainComponentUuid.getOrDefault(component.getMainComponentUuid(), 0) == 0) | |||
.orElse(true); | |||
} | |||
} | |||
@@ -167,7 +190,9 @@ public class CeQueueImpl implements CeQueue { | |||
CeQueueDto dto = new CeQueueDto(); | |||
dto.setUuid(submission.getUuid()); | |||
dto.setTaskType(submission.getType()); | |||
dto.setComponentUuid(submission.getComponentUuid()); | |||
submission.getComponent().ifPresent(component -> dto | |||
.setComponentUuid(component.getUuid()) | |||
.setMainComponentUuid(component.getMainComponentUuid())); | |||
dto.setStatus(PENDING); | |||
dto.setSubmitterUuid(submission.getSubmitterUuid()); | |||
dbClient.ceQueueDao().insert(dbSession, dto); | |||
@@ -178,7 +203,7 @@ public class CeQueueImpl implements CeQueue { | |||
private List<CeTask> loadTasks(DbSession dbSession, List<CeQueueDto> dtos) { | |||
// load components, if defined | |||
Set<String> componentUuids = dtos.stream() | |||
.map(CeQueueDto::getComponentUuid) | |||
.flatMap(dto -> Stream.of(dto.getComponentUuid(), dto.getMainComponentUuid())) | |||
.filter(Objects::nonNull) | |||
.collect(Collectors.toSet()); | |||
Map<String, ComponentDto> componentsByUuid = dbClient.componentDao() | |||
@@ -194,13 +219,15 @@ public class CeQueueImpl implements CeQueue { | |||
List<CeTask> result = new ArrayList<>(); | |||
for (CeQueueDto dto : dtos) { | |||
ComponentDto component = null; | |||
if (dto.getComponentUuid() != null) { | |||
component = componentsByUuid.get(dto.getComponentUuid()); | |||
} | |||
ComponentDto component = ofNullable(dto.getComponentUuid()) | |||
.map(componentsByUuid::get) | |||
.orElse(null); | |||
ComponentDto mainComponent = ofNullable(dto.getMainComponentUuid()) | |||
.map(componentsByUuid::get) | |||
.orElse(null); | |||
Map<String, String> characteristics = characteristicsByTaskUuid.get(dto.getUuid()).stream() | |||
.collect(uniqueIndex(CeTaskCharacteristicDto::getKey, CeTaskCharacteristicDto::getValue)); | |||
result.add(convertToTask(dto, characteristics, component)); | |||
result.add(convertToTask(dto, characteristics, component, mainComponent)); | |||
} | |||
return result; | |||
} | |||
@@ -272,7 +299,7 @@ public class CeQueueImpl implements CeQueue { | |||
@Override | |||
public WorkersPauseStatus getWorkersPauseStatus() { | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
java.util.Optional<String> propValue = dbClient.internalPropertiesDao().selectByKey(dbSession, InternalProperties.COMPUTE_ENGINE_PAUSE); | |||
Optional<String> propValue = dbClient.internalPropertiesDao().selectByKey(dbSession, InternalProperties.COMPUTE_ENGINE_PAUSE); | |||
if (!propValue.isPresent() || !propValue.get().equals("true")) { | |||
return WorkersPauseStatus.RESUMED; | |||
} | |||
@@ -284,18 +311,26 @@ public class CeQueueImpl implements CeQueue { | |||
} | |||
} | |||
CeTask convertToTask(CeQueueDto taskDto, Map<String, String> characteristics, @Nullable ComponentDto component) { | |||
CeTask convertToTask(CeQueueDto taskDto, Map<String, String> characteristics, @Nullable ComponentDto component, @Nullable ComponentDto mainComponent) { | |||
CeTask.Builder builder = new CeTask.Builder() | |||
.setUuid(taskDto.getUuid()) | |||
.setType(taskDto.getTaskType()) | |||
.setSubmitterUuid(taskDto.getSubmitterUuid()) | |||
.setComponentUuid(taskDto.getComponentUuid()) | |||
.setCharacteristics(characteristics); | |||
String componentUuid = taskDto.getComponentUuid(); | |||
if (component != null) { | |||
builder.setComponent(new CeTask.Component(component.uuid(), component.getDbKey(), component.name())); | |||
builder.setOrganizationUuid(component.getOrganizationUuid()); | |||
builder.setComponentKey(component.getDbKey()); | |||
builder.setComponentName(component.name()); | |||
} else if (componentUuid != null) { | |||
builder.setComponent(new CeTask.Component(componentUuid, null, null)); | |||
} | |||
String mainComponentUuid = taskDto.getMainComponentUuid(); | |||
if (mainComponent != null) { | |||
builder.setMainComponent(new CeTask.Component(mainComponent.uuid(), mainComponent.getDbKey(), mainComponent.name())); | |||
} else if (mainComponentUuid != null) { | |||
builder.setMainComponent(new CeTask.Component(mainComponentUuid, null, null)); | |||
} | |||
// FIXME this should be set from the CeQueueDto |
@@ -20,11 +20,16 @@ | |||
package org.sonar.ce.queue; | |||
import java.util.Map; | |||
import java.util.Objects; | |||
import java.util.Optional; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import javax.annotation.concurrent.Immutable; | |||
import org.sonar.db.component.ComponentDto; | |||
import static com.google.common.base.MoreObjects.firstNonNull; | |||
import static com.google.common.base.Strings.emptyToNull; | |||
import static com.google.common.base.Strings.nullToEmpty; | |||
import static java.util.Collections.unmodifiableMap; | |||
import static java.util.Objects.requireNonNull; | |||
@@ -33,16 +38,16 @@ public final class CeTaskSubmit { | |||
private final String uuid; | |||
private final String type; | |||
private final String componentUuid; | |||
private final Component component; | |||
private final String submitterUuid; | |||
private final Map<String, String> characteristics; | |||
private CeTaskSubmit(Builder builder) { | |||
this.uuid = requireNonNull(emptyToNull(builder.uuid)); | |||
this.type = requireNonNull(emptyToNull(builder.type)); | |||
this.componentUuid = emptyToNull(builder.componentUuid); | |||
this.submitterUuid = emptyToNull(builder.submitterUuid); | |||
this.characteristics = unmodifiableMap(requireNonNull(builder.characteristics)); | |||
this.uuid = requireNonNull(builder.uuid); | |||
this.type = requireNonNull(builder.type); | |||
this.component = builder.component; | |||
this.submitterUuid = builder.submitterUuid; | |||
this.characteristics = unmodifiableMap(builder.characteristics); | |||
} | |||
public String getType() { | |||
@@ -53,9 +58,8 @@ public final class CeTaskSubmit { | |||
return uuid; | |||
} | |||
@CheckForNull | |||
public String getComponentUuid() { | |||
return componentUuid; | |||
public Optional<Component> getComponent() { | |||
return Optional.ofNullable(component); | |||
} | |||
@CheckForNull | |||
@@ -70,12 +74,12 @@ public final class CeTaskSubmit { | |||
public static final class Builder { | |||
private final String uuid; | |||
private String type; | |||
private String componentUuid; | |||
private Component component; | |||
private String submitterUuid; | |||
private Map<String, String> characteristics = null; | |||
public Builder(String uuid) { | |||
this.uuid = uuid; | |||
this.uuid = emptyToNull(uuid); | |||
} | |||
public String getUuid() { | |||
@@ -83,12 +87,12 @@ public final class CeTaskSubmit { | |||
} | |||
public Builder setType(String s) { | |||
this.type = s; | |||
this.type = emptyToNull(s); | |||
return this; | |||
} | |||
public Builder setComponentUuid(@Nullable String s) { | |||
this.componentUuid = s; | |||
public Builder setComponent(@Nullable Component component) { | |||
this.component = component; | |||
return this; | |||
} | |||
@@ -103,7 +107,58 @@ public final class CeTaskSubmit { | |||
} | |||
public CeTaskSubmit build() { | |||
requireNonNull(uuid, "uuid can't be null"); | |||
requireNonNull(type, "type can't be null"); | |||
requireNonNull(characteristics, "characteristics can't be null"); | |||
return new CeTaskSubmit(this); | |||
} | |||
} | |||
public static class Component { | |||
private String uuid; | |||
private String mainComponentUuid; | |||
public Component(String uuid, String mainComponentUuid) { | |||
this.uuid = requireNonNull(nullToEmpty(uuid), "uuid can't be null"); | |||
this.mainComponentUuid = requireNonNull(nullToEmpty(mainComponentUuid), "mainComponentUuid can't be null"); | |||
} | |||
public static Component fromDto(ComponentDto dto) { | |||
String uuid = dto.uuid(); | |||
return new Component(uuid, firstNonNull(dto.getMainBranchProjectUuid(), uuid)); | |||
} | |||
public String getUuid() { | |||
return uuid; | |||
} | |||
public String getMainComponentUuid() { | |||
return mainComponentUuid; | |||
} | |||
@Override | |||
public String toString() { | |||
return "Component{" + | |||
"uuid='" + uuid + '\'' + | |||
", mainComponentUuid='" + mainComponentUuid + '\'' + | |||
'}'; | |||
} | |||
@Override | |||
public boolean equals(Object o) { | |||
if (this == o) { | |||
return true; | |||
} | |||
if (o == null || getClass() != o.getClass()) { | |||
return false; | |||
} | |||
Component component = (Component) o; | |||
return uuid.equals(component.uuid) && mainComponentUuid.equals(component.mainComponentUuid); | |||
} | |||
@Override | |||
public int hashCode() { | |||
return Objects.hash(uuid, mainComponentUuid); | |||
} | |||
} | |||
} |
@@ -30,6 +30,7 @@ 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.ce.queue.CeTaskSubmit.Component; | |||
import org.sonar.ce.task.CeTask; | |||
import org.sonar.core.util.UuidFactory; | |||
import org.sonar.core.util.UuidFactoryFast; | |||
@@ -49,8 +50,9 @@ import static java.util.Arrays.asList; | |||
import static java.util.Collections.emptyMap; | |||
import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.tuple; | |||
import static org.hamcrest.Matchers.startsWith; | |||
import static org.sonar.ce.queue.CeQueue.SubmitOption.UNIQUE_QUEUE_PER_COMPONENT; | |||
import static org.sonar.ce.queue.CeQueue.SubmitOption.UNIQUE_QUEUE_PER_MAIN_COMPONENT; | |||
public class CeQueueImplTest { | |||
@@ -72,7 +74,9 @@ public class CeQueueImplTest { | |||
@Test | |||
public void submit_returns_task_populated_from_CeTaskSubmit_and_creates_CeQueue_row() { | |||
CeTaskSubmit taskSubmit = createTaskSubmit(CeTaskTypes.REPORT, "PROJECT_1", "submitter uuid"); | |||
String componentUuid = randomAlphabetic(3); | |||
String mainComponentUuid = randomAlphabetic(4); | |||
CeTaskSubmit taskSubmit = createTaskSubmit(CeTaskTypes.REPORT, new Component(componentUuid, mainComponentUuid), "submitter uuid"); | |||
CeTask task = underTest.submit(taskSubmit); | |||
@@ -83,7 +87,7 @@ public class CeQueueImplTest { | |||
@Test | |||
public void submit_populates_component_name_and_key_of_CeTask_if_component_exists() { | |||
ComponentDto componentDto = insertComponent(ComponentTesting.newPrivateProjectDto(db.organizations().insert(), "PROJECT_1")); | |||
CeTaskSubmit taskSubmit = createTaskSubmit(CeTaskTypes.REPORT, componentDto.uuid(), null); | |||
CeTaskSubmit taskSubmit = createTaskSubmit(CeTaskTypes.REPORT, Component.fromDto(componentDto), null); | |||
CeTask task = underTest.submit(taskSubmit); | |||
@@ -100,11 +104,11 @@ public class CeQueueImplTest { | |||
} | |||
@Test | |||
public void submit_with_UNIQUE_QUEUE_PER_COMPONENT_creates_task_without_component_when_there_is_a_pending_task_without_component() { | |||
public void submit_with_UNIQUE_QUEUE_PER_MAIN_COMPONENT_creates_task_without_component_when_there_is_a_pending_task_without_component() { | |||
CeTaskSubmit taskSubmit = createTaskSubmit("no_component"); | |||
CeQueueDto dto = insertPendingInQueue(null); | |||
Optional<CeTask> task = underTest.submit(taskSubmit, UNIQUE_QUEUE_PER_COMPONENT); | |||
Optional<CeTask> task = underTest.submit(taskSubmit, UNIQUE_QUEUE_PER_MAIN_COMPONENT); | |||
assertThat(task).isNotEmpty(); | |||
assertThat(db.getDbClient().ceQueueDao().selectAllInAscOrder(db.getSession())) | |||
@@ -113,13 +117,13 @@ public class CeQueueImplTest { | |||
} | |||
@Test | |||
public void submit_with_UNIQUE_QUEUE_PER_COMPONENT_creates_task_when_there_is_a_pending_task_for_another_component() { | |||
String componentUuid = randomAlphabetic(5); | |||
String otherComponentUuid = randomAlphabetic(6); | |||
CeTaskSubmit taskSubmit = createTaskSubmit("with_component", componentUuid, null); | |||
CeQueueDto dto = insertPendingInQueue(otherComponentUuid); | |||
public void submit_with_UNIQUE_QUEUE_PER_MAIN_COMPONENT_creates_task_when_there_is_a_pending_task_for_another_main_component() { | |||
String mainComponentUuid = randomAlphabetic(5); | |||
String otherMainComponentUuid = randomAlphabetic(6); | |||
CeTaskSubmit taskSubmit = createTaskSubmit("with_component", newComponent(mainComponentUuid), null); | |||
CeQueueDto dto = insertPendingInQueue(newComponent(otherMainComponentUuid)); | |||
Optional<CeTask> task = underTest.submit(taskSubmit, UNIQUE_QUEUE_PER_COMPONENT); | |||
Optional<CeTask> task = underTest.submit(taskSubmit, UNIQUE_QUEUE_PER_MAIN_COMPONENT); | |||
assertThat(task).isNotEmpty(); | |||
assertThat(db.getDbClient().ceQueueDao().selectAllInAscOrder(db.getSession())) | |||
@@ -128,12 +132,12 @@ public class CeQueueImplTest { | |||
} | |||
@Test | |||
public void submit_with_UNIQUE_QUEUE_PER_COMPONENT_does_not_create_task_when_there_is_one_pending_task_for_component() { | |||
String componentUuid = randomAlphabetic(5); | |||
CeTaskSubmit taskSubmit = createTaskSubmit("with_component", componentUuid, null); | |||
CeQueueDto dto = insertPendingInQueue(componentUuid); | |||
public void submit_with_UNIQUE_QUEUE_PER_MAIN_COMPONENT_does_not_create_task_when_there_is_one_pending_task_for_same_main_component() { | |||
String mainComponentUuid = randomAlphabetic(5); | |||
CeTaskSubmit taskSubmit = createTaskSubmit("with_component", newComponent(mainComponentUuid), null); | |||
CeQueueDto dto = insertPendingInQueue(newComponent(mainComponentUuid)); | |||
Optional<CeTask> task = underTest.submit(taskSubmit, UNIQUE_QUEUE_PER_COMPONENT); | |||
Optional<CeTask> task = underTest.submit(taskSubmit, UNIQUE_QUEUE_PER_MAIN_COMPONENT); | |||
assertThat(task).isEmpty(); | |||
assertThat(db.getDbClient().ceQueueDao().selectAllInAscOrder(db.getSession())) | |||
@@ -142,15 +146,15 @@ public class CeQueueImplTest { | |||
} | |||
@Test | |||
public void submit_with_UNIQUE_QUEUE_PER_COMPONENT_does_not_create_task_when_there_is_many_pending_task_for_component() { | |||
String componentUuid = randomAlphabetic(5); | |||
CeTaskSubmit taskSubmit = createTaskSubmit("with_component", componentUuid, null); | |||
public void submit_with_UNIQUE_QUEUE_PER_MAIN_COMPONENT_does_not_create_task_when_there_is_many_pending_task_for_same_main_component() { | |||
String mainComponentUuid = randomAlphabetic(5); | |||
CeTaskSubmit taskSubmit = createTaskSubmit("with_component", newComponent(mainComponentUuid), null); | |||
String[] uuids = IntStream.range(0, 2 + new Random().nextInt(5)) | |||
.mapToObj(i -> insertPendingInQueue(componentUuid)) | |||
.mapToObj(i -> insertPendingInQueue(newComponent(mainComponentUuid))) | |||
.map(CeQueueDto::getUuid) | |||
.toArray(String[]::new); | |||
Optional<CeTask> task = underTest.submit(taskSubmit, UNIQUE_QUEUE_PER_COMPONENT); | |||
Optional<CeTask> task = underTest.submit(taskSubmit, UNIQUE_QUEUE_PER_MAIN_COMPONENT); | |||
assertThat(task).isEmpty(); | |||
assertThat(db.getDbClient().ceQueueDao().selectAllInAscOrder(db.getSession())) | |||
@@ -159,10 +163,10 @@ public class CeQueueImplTest { | |||
} | |||
@Test | |||
public void submit_without_UNIQUE_QUEUE_PER_COMPONENT_creates_task_when_there_is_one_pending_task_for_component() { | |||
String componentUuid = randomAlphabetic(5); | |||
CeTaskSubmit taskSubmit = createTaskSubmit("with_component", componentUuid, null); | |||
CeQueueDto dto = insertPendingInQueue(componentUuid); | |||
public void submit_without_UNIQUE_QUEUE_PER_MAIN_COMPONENT_creates_task_when_there_is_one_pending_task_for_same_main_component() { | |||
String mainComponentUuid = randomAlphabetic(5); | |||
CeTaskSubmit taskSubmit = createTaskSubmit("with_component", newComponent(mainComponentUuid), null); | |||
CeQueueDto dto = insertPendingInQueue(newComponent(mainComponentUuid)); | |||
CeTask task = underTest.submit(taskSubmit); | |||
@@ -172,11 +176,11 @@ public class CeQueueImplTest { | |||
} | |||
@Test | |||
public void submit_without_UNIQUE_QUEUE_PER_COMPONENT_creates_task_when_there_is_many_pending_task_for_component() { | |||
String componentUuid = randomAlphabetic(5); | |||
CeTaskSubmit taskSubmit = createTaskSubmit("with_component", componentUuid, null); | |||
public void submit_without_UNIQUE_QUEUE_PER_MAIN_COMPONENT_creates_task_when_there_is_many_pending_task_for_same_main_component() { | |||
String mainComponentUuid = randomAlphabetic(5); | |||
CeTaskSubmit taskSubmit = createTaskSubmit("with_component", newComponent(mainComponentUuid), null); | |||
String[] uuids = IntStream.range(0, 2 + new Random().nextInt(5)) | |||
.mapToObj(i -> insertPendingInQueue(componentUuid)) | |||
.mapToObj(i -> insertPendingInQueue(newComponent(mainComponentUuid))) | |||
.map(CeQueueDto::getUuid) | |||
.toArray(String[]::new); | |||
@@ -191,7 +195,8 @@ public class CeQueueImplTest { | |||
@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", "submitter uuid"); | |||
String mainComponentUuid = randomAlphabetic(10); | |||
CeTaskSubmit taskSubmit1 = createTaskSubmit(CeTaskTypes.REPORT, newComponent(mainComponentUuid), "submitter uuid"); | |||
CeTaskSubmit taskSubmit2 = createTaskSubmit("some type"); | |||
List<CeTask> tasks = underTest.massSubmit(asList(taskSubmit1, taskSubmit2)); | |||
@@ -204,10 +209,10 @@ public class CeQueueImplTest { | |||
} | |||
@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_project_exists() { | |||
ComponentDto componentDto1 = insertComponent(ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization(), "PROJECT_1")); | |||
CeTaskSubmit taskSubmit1 = createTaskSubmit(CeTaskTypes.REPORT, componentDto1.uuid(), null); | |||
CeTaskSubmit taskSubmit2 = createTaskSubmit("something", "non existing component uuid", null); | |||
CeTaskSubmit taskSubmit1 = createTaskSubmit(CeTaskTypes.REPORT, Component.fromDto(componentDto1), null); | |||
CeTaskSubmit taskSubmit2 = createTaskSubmit("something", newComponent(randomAlphabetic(12)), null); | |||
List<CeTask> tasks = underTest.massSubmit(asList(taskSubmit1, taskSubmit2)); | |||
@@ -217,11 +222,26 @@ public class CeQueueImplTest { | |||
} | |||
@Test | |||
public void massSubmit_with_UNIQUE_QUEUE_PER_COMPONENT_creates_task_without_component_when_there_is_a_pending_task_without_component() { | |||
public void massSubmit_populates_component_name_and_key_of_CeTask_if_project_and_branch_exists() { | |||
ComponentDto project = insertComponent(ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization(), "PROJECT_1")); | |||
ComponentDto branch1 = db.components().insertProjectBranch(project); | |||
ComponentDto branch2 = db.components().insertProjectBranch(project); | |||
CeTaskSubmit taskSubmit1 = createTaskSubmit(CeTaskTypes.REPORT, Component.fromDto(branch1), null); | |||
CeTaskSubmit taskSubmit2 = createTaskSubmit("something", Component.fromDto(branch2), null); | |||
List<CeTask> tasks = underTest.massSubmit(asList(taskSubmit1, taskSubmit2)); | |||
assertThat(tasks).hasSize(2); | |||
verifyCeTask(taskSubmit1, tasks.get(0), branch1, project); | |||
verifyCeTask(taskSubmit2, tasks.get(1), branch2, project); | |||
} | |||
@Test | |||
public void massSubmit_with_UNIQUE_QUEUE_PER_MAIN_COMPONENT_creates_task_without_component_when_there_is_a_pending_task_without_component() { | |||
CeTaskSubmit taskSubmit = createTaskSubmit("no_component"); | |||
CeQueueDto dto = insertPendingInQueue(null); | |||
List<CeTask> tasks = underTest.massSubmit(of(taskSubmit), UNIQUE_QUEUE_PER_COMPONENT); | |||
List<CeTask> tasks = underTest.massSubmit(of(taskSubmit), UNIQUE_QUEUE_PER_MAIN_COMPONENT); | |||
assertThat(tasks).hasSize(1); | |||
assertThat(db.getDbClient().ceQueueDao().selectAllInAscOrder(db.getSession())) | |||
@@ -230,13 +250,13 @@ public class CeQueueImplTest { | |||
} | |||
@Test | |||
public void massSubmit_with_UNIQUE_QUEUE_PER_COMPONENT_creates_task_when_there_is_a_pending_task_for_another_component() { | |||
String componentUuid = randomAlphabetic(5); | |||
String otherComponentUuid = randomAlphabetic(6); | |||
CeTaskSubmit taskSubmit = createTaskSubmit("with_component", componentUuid, null); | |||
CeQueueDto dto = insertPendingInQueue(otherComponentUuid); | |||
public void massSubmit_with_UNIQUE_QUEUE_PER_MAIN_COMPONENT_creates_task_when_there_is_a_pending_task_for_another_main_component() { | |||
String mainComponentUuid = randomAlphabetic(5); | |||
String otherMainComponentUuid = randomAlphabetic(6); | |||
CeTaskSubmit taskSubmit = createTaskSubmit("with_component", newComponent(mainComponentUuid), null); | |||
CeQueueDto dto = insertPendingInQueue(newComponent(otherMainComponentUuid)); | |||
List<CeTask> tasks = underTest.massSubmit(of(taskSubmit), UNIQUE_QUEUE_PER_COMPONENT); | |||
List<CeTask> tasks = underTest.massSubmit(of(taskSubmit), UNIQUE_QUEUE_PER_MAIN_COMPONENT); | |||
assertThat(tasks).hasSize(1); | |||
assertThat(db.getDbClient().ceQueueDao().selectAllInAscOrder(db.getSession())) | |||
@@ -245,12 +265,12 @@ public class CeQueueImplTest { | |||
} | |||
@Test | |||
public void massSubmit_with_UNIQUE_QUEUE_PER_COMPONENT_does_not_create_task_when_there_is_one_pending_task_for_component() { | |||
String componentUuid = randomAlphabetic(5); | |||
CeTaskSubmit taskSubmit = createTaskSubmit("with_component", componentUuid, null); | |||
CeQueueDto dto = insertPendingInQueue(componentUuid); | |||
public void massSubmit_with_UNIQUE_QUEUE_PER_MAIN_COMPONENT_does_not_create_task_when_there_is_one_pending_task_for_same_main_component() { | |||
String mainComponentUuid = randomAlphabetic(5); | |||
CeTaskSubmit taskSubmit = createTaskSubmit("with_component", newComponent(mainComponentUuid), null); | |||
CeQueueDto dto = insertPendingInQueue(newComponent(mainComponentUuid)); | |||
List<CeTask> tasks = underTest.massSubmit(of(taskSubmit), UNIQUE_QUEUE_PER_COMPONENT); | |||
List<CeTask> tasks = underTest.massSubmit(of(taskSubmit), UNIQUE_QUEUE_PER_MAIN_COMPONENT); | |||
assertThat(tasks).isEmpty(); | |||
assertThat(db.getDbClient().ceQueueDao().selectAllInAscOrder(db.getSession())) | |||
@@ -259,15 +279,15 @@ public class CeQueueImplTest { | |||
} | |||
@Test | |||
public void massSubmit_with_UNIQUE_QUEUE_PER_COMPONENT_does_not_create_task_when_there_is_many_pending_task_for_component() { | |||
String componentUuid = randomAlphabetic(5); | |||
CeTaskSubmit taskSubmit = createTaskSubmit("with_component", componentUuid, null); | |||
public void massSubmit_with_UNIQUE_QUEUE_PER_MAIN_COMPONENT_does_not_create_task_when_there_is_many_pending_task_for_same_main_component() { | |||
String mainComponentUuid = randomAlphabetic(5); | |||
CeTaskSubmit taskSubmit = createTaskSubmit("with_component", newComponent(mainComponentUuid), null); | |||
String[] uuids = IntStream.range(0, 2 + new Random().nextInt(5)) | |||
.mapToObj(i -> insertPendingInQueue(componentUuid)) | |||
.mapToObj(i -> insertPendingInQueue(newComponent(mainComponentUuid))) | |||
.map(CeQueueDto::getUuid) | |||
.toArray(String[]::new); | |||
List<CeTask> tasks = underTest.massSubmit(of(taskSubmit), UNIQUE_QUEUE_PER_COMPONENT); | |||
List<CeTask> tasks = underTest.massSubmit(of(taskSubmit), UNIQUE_QUEUE_PER_MAIN_COMPONENT); | |||
assertThat(tasks).isEmpty(); | |||
assertThat(db.getDbClient().ceQueueDao().selectAllInAscOrder(db.getSession())) | |||
@@ -276,10 +296,10 @@ public class CeQueueImplTest { | |||
} | |||
@Test | |||
public void massSubmit_without_UNIQUE_QUEUE_PER_COMPONENT_creates_task_when_there_is_one_pending_task_for_component() { | |||
String componentUuid = randomAlphabetic(5); | |||
CeTaskSubmit taskSubmit = createTaskSubmit("with_component", componentUuid, null); | |||
CeQueueDto dto = insertPendingInQueue(componentUuid); | |||
public void massSubmit_without_UNIQUE_QUEUE_PER_MAIN_COMPONENT_creates_task_when_there_is_one_pending_task_for_other_main_component() { | |||
String mainComponentUuid = randomAlphabetic(5); | |||
CeTaskSubmit taskSubmit = createTaskSubmit("with_component", newComponent(mainComponentUuid), null); | |||
CeQueueDto dto = insertPendingInQueue(newComponent(mainComponentUuid)); | |||
List<CeTask> tasks = underTest.massSubmit(of(taskSubmit)); | |||
@@ -290,11 +310,11 @@ public class CeQueueImplTest { | |||
} | |||
@Test | |||
public void massSubmit_without_UNIQUE_QUEUE_PER_COMPONENT_creates_task_when_there_is_many_pending_task_for_component() { | |||
String componentUuid = randomAlphabetic(5); | |||
CeTaskSubmit taskSubmit = createTaskSubmit("with_component", componentUuid, null); | |||
public void massSubmit_without_UNIQUE_QUEUE_PER_MAIN_COMPONENT_creates_task_when_there_is_many_pending_task_for_other_main_component() { | |||
String mainComponentUuid = randomAlphabetic(5); | |||
CeTaskSubmit taskSubmit = createTaskSubmit("with_component", newComponent(mainComponentUuid), null); | |||
String[] uuids = IntStream.range(0, 2 + new Random().nextInt(5)) | |||
.mapToObj(i -> insertPendingInQueue(componentUuid)) | |||
.mapToObj(i -> insertPendingInQueue(newComponent(mainComponentUuid))) | |||
.map(CeQueueDto::getUuid) | |||
.toArray(String[]::new); | |||
@@ -309,30 +329,33 @@ public class CeQueueImplTest { | |||
} | |||
@Test | |||
public void massSubmit_with_UNIQUE_QUEUE_PER_COMPONENT_creates_tasks_depending_on_whether_there_is_pending_task_for_component() { | |||
String componentUuid1 = randomAlphabetic(5); | |||
String componentUuid2 = randomAlphabetic(6); | |||
String componentUuid3 = randomAlphabetic(7); | |||
String componentUuid4 = randomAlphabetic(8); | |||
String componentUuid5 = randomAlphabetic(9); | |||
CeTaskSubmit taskSubmit1 = createTaskSubmit("with_one_pending", componentUuid1, null); | |||
CeQueueDto dto1 = insertPendingInQueue(componentUuid1); | |||
CeTaskSubmit taskSubmit2 = createTaskSubmit("no_pending", componentUuid2, null); | |||
CeTaskSubmit taskSubmit3 = createTaskSubmit("with_many_pending", componentUuid3, null); | |||
public void massSubmit_with_UNIQUE_QUEUE_PER_MAIN_COMPONENT_creates_tasks_depending_on_whether_there_is_pending_task_for_same_main_component() { | |||
String mainComponentUuid1 = randomAlphabetic(5); | |||
String mainComponentUuid2 = randomAlphabetic(6); | |||
String mainComponentUuid3 = randomAlphabetic(7); | |||
String mainComponentUuid4 = randomAlphabetic(8); | |||
String mainComponentUuid5 = randomAlphabetic(9); | |||
CeTaskSubmit taskSubmit1 = createTaskSubmit("with_one_pending", newComponent(mainComponentUuid1), null); | |||
CeQueueDto dto1 = insertPendingInQueue(newComponent(mainComponentUuid1)); | |||
Component componentForMainComponentUuid2 = newComponent(mainComponentUuid2); | |||
CeTaskSubmit taskSubmit2 = createTaskSubmit("no_pending", componentForMainComponentUuid2, null); | |||
CeTaskSubmit taskSubmit3 = createTaskSubmit("with_many_pending", newComponent(mainComponentUuid3), null); | |||
String[] uuids3 = IntStream.range(0, 2 + new Random().nextInt(5)) | |||
.mapToObj(i -> insertPendingInQueue(componentUuid3)) | |||
.mapToObj(i -> insertPendingInQueue(newComponent(mainComponentUuid3))) | |||
.map(CeQueueDto::getUuid) | |||
.toArray(String[]::new); | |||
CeTaskSubmit taskSubmit4 = createTaskSubmit("no_pending_2", componentUuid4, null); | |||
CeTaskSubmit taskSubmit5 = createTaskSubmit("with_pending_2", componentUuid5, null); | |||
CeQueueDto dto5 = insertPendingInQueue(componentUuid5); | |||
Component componentForMainComponentUuid4 = newComponent(mainComponentUuid4); | |||
CeTaskSubmit taskSubmit4 = createTaskSubmit("no_pending_2", componentForMainComponentUuid4, null); | |||
CeTaskSubmit taskSubmit5 = createTaskSubmit("with_pending_2", newComponent(mainComponentUuid5), null); | |||
CeQueueDto dto5 = insertPendingInQueue(newComponent(mainComponentUuid5)); | |||
List<CeTask> tasks = underTest.massSubmit(of(taskSubmit1, taskSubmit2, taskSubmit3, taskSubmit4, taskSubmit5), UNIQUE_QUEUE_PER_COMPONENT); | |||
List<CeTask> tasks = underTest.massSubmit(of(taskSubmit1, taskSubmit2, taskSubmit3, taskSubmit4, taskSubmit5), UNIQUE_QUEUE_PER_MAIN_COMPONENT); | |||
assertThat(tasks) | |||
.hasSize(2) | |||
.extracting(CeTask::getComponentUuid) | |||
.containsOnly(componentUuid2, componentUuid4); | |||
.extracting(task -> task.getComponent().get().getUuid(),task -> task.getMainComponent().get().getUuid()) | |||
.containsOnly(tuple(componentForMainComponentUuid2.getUuid(), componentForMainComponentUuid2.getMainComponentUuid()), | |||
tuple(componentForMainComponentUuid4.getUuid(), componentForMainComponentUuid4.getMainComponentUuid())); | |||
assertThat(db.getDbClient().ceQueueDao().selectAllInAscOrder(db.getSession())) | |||
.extracting(CeQueueDto::getUuid) | |||
.hasSize(1 + uuids3.length + 1 + tasks.size()) | |||
@@ -344,7 +367,7 @@ public class CeQueueImplTest { | |||
@Test | |||
public void cancel_pending() { | |||
CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1"); | |||
CeTask task = submit(CeTaskTypes.REPORT, newComponent(randomAlphabetic(12))); | |||
CeQueueDto queueDto = db.getDbClient().ceQueueDao().selectByUuid(db.getSession(), task.getUuid()).get(); | |||
underTest.cancel(db.getSession(), queueDto); | |||
@@ -356,7 +379,7 @@ public class CeQueueImplTest { | |||
@Test | |||
public void fail_to_cancel_if_in_progress() { | |||
submit(CeTaskTypes.REPORT, "PROJECT_1"); | |||
submit(CeTaskTypes.REPORT, newComponent(randomAlphabetic(11))); | |||
CeQueueDto ceQueueDto = db.getDbClient().ceQueueDao().peek(session, WORKER_UUID).get(); | |||
expectedException.expect(IllegalStateException.class); | |||
@@ -367,9 +390,9 @@ public class CeQueueImplTest { | |||
@Test | |||
public void cancelAll_pendings_but_not_in_progress() { | |||
CeTask inProgressTask = submit(CeTaskTypes.REPORT, "PROJECT_1"); | |||
CeTask pendingTask1 = submit(CeTaskTypes.REPORT, "PROJECT_2"); | |||
CeTask pendingTask2 = submit(CeTaskTypes.REPORT, "PROJECT_3"); | |||
CeTask inProgressTask = submit(CeTaskTypes.REPORT, newComponent(randomAlphabetic(12))); | |||
CeTask pendingTask1 = submit(CeTaskTypes.REPORT, newComponent(randomAlphabetic(13))); | |||
CeTask pendingTask2 = submit(CeTaskTypes.REPORT, newComponent(randomAlphabetic(14))); | |||
db.getDbClient().ceQueueDao().peek(session, WORKER_UUID); | |||
@@ -386,7 +409,7 @@ public class CeQueueImplTest { | |||
@Test | |||
public void pauseWorkers_marks_workers_as_paused_if_zero_tasks_in_progress() { | |||
submit(CeTaskTypes.REPORT, "PROJECT_1"); | |||
submit(CeTaskTypes.REPORT, newComponent(randomAlphabetic(12))); | |||
// task is pending | |||
assertThat(underTest.getWorkersPauseStatus()).isEqualTo(CeQueue.WorkersPauseStatus.RESUMED); | |||
@@ -397,7 +420,7 @@ public class CeQueueImplTest { | |||
@Test | |||
public void pauseWorkers_marks_workers_as_pausing_if_some_tasks_in_progress() { | |||
submit(CeTaskTypes.REPORT, "PROJECT_1"); | |||
submit(CeTaskTypes.REPORT, newComponent(randomAlphabetic(12))); | |||
db.getDbClient().ceQueueDao().peek(session, WORKER_UUID); | |||
// task is in-progress | |||
@@ -418,7 +441,7 @@ public class CeQueueImplTest { | |||
@Test | |||
public void resumeWorkers_resumes_pausing_workers() { | |||
submit(CeTaskTypes.REPORT, "PROJECT_1"); | |||
submit(CeTaskTypes.REPORT, newComponent(randomAlphabetic(12))); | |||
db.getDbClient().ceQueueDao().peek(session, WORKER_UUID); | |||
// task is in-progress | |||
@@ -439,21 +462,37 @@ public class CeQueueImplTest { | |||
} | |||
private void verifyCeTask(CeTaskSubmit taskSubmit, CeTask task, @Nullable ComponentDto componentDto) { | |||
verifyCeTask(taskSubmit, task, componentDto, componentDto); | |||
} | |||
private void verifyCeTask(CeTaskSubmit taskSubmit, CeTask task, @Nullable ComponentDto componentDto, @Nullable ComponentDto mainComponentDto) { | |||
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(); | |||
if (componentDto != null) { | |||
CeTask.Component component = task.getComponent().get(); | |||
assertThat(component.getUuid()).isEqualTo(componentDto.uuid()); | |||
assertThat(component.getKey()).contains(componentDto.getDbKey()); | |||
assertThat(component.getName()).contains(componentDto.name()); | |||
} else if (taskSubmit.getComponent().isPresent()) { | |||
assertThat(task.getComponent()).contains(new CeTask.Component(taskSubmit.getComponent().get().getUuid(), null, null)); | |||
} else { | |||
assertThat(task.getComponent()).isEmpty(); | |||
} | |||
if (mainComponentDto != null) { | |||
CeTask.Component component = task.getMainComponent().get(); | |||
assertThat(component.getUuid()).isEqualTo(mainComponentDto.uuid()); | |||
assertThat(component.getKey()).contains(mainComponentDto.getDbKey()); | |||
assertThat(component.getName()).contains(mainComponentDto.name()); | |||
} else if (taskSubmit.getComponent().isPresent()) { | |||
assertThat(task.getMainComponent()).contains(new CeTask.Component(taskSubmit.getComponent().get().getMainComponentUuid(), null, null)); | |||
} else { | |||
assertThat(task.getComponentKey()).isEqualTo(componentDto.getDbKey()); | |||
assertThat(task.getComponentName()).isEqualTo(componentDto.name()); | |||
assertThat(task.getMainComponent()).isEmpty(); | |||
} | |||
assertThat(task.getType()).isEqualTo(taskSubmit.getType()); | |||
assertThat(task.getSubmitterUuid()).isEqualTo(taskSubmit.getSubmitterUuid()); | |||
} | |||
@@ -461,23 +500,30 @@ public class CeQueueImplTest { | |||
Optional<CeQueueDto> queueDto = db.getDbClient().ceQueueDao().selectByUuid(db.getSession(), taskSubmit.getUuid()); | |||
assertThat(queueDto.isPresent()).isTrue(); | |||
assertThat(queueDto.get().getTaskType()).isEqualTo(taskSubmit.getType()); | |||
assertThat(queueDto.get().getComponentUuid()).isEqualTo(taskSubmit.getComponentUuid()); | |||
Optional<Component> component = taskSubmit.getComponent(); | |||
if (component.isPresent()) { | |||
assertThat(queueDto.get().getComponentUuid()).isEqualTo(component.get().getUuid()); | |||
assertThat(queueDto.get().getMainComponentUuid()).isEqualTo(component.get().getMainComponentUuid()); | |||
} else { | |||
assertThat(queueDto.get().getComponentUuid()).isNull(); | |||
assertThat(queueDto.get().getComponentUuid()).isNull(); | |||
} | |||
assertThat(queueDto.get().getSubmitterUuid()).isEqualTo(taskSubmit.getSubmitterUuid()); | |||
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 CeTask submit(String reportType, Component component) { | |||
return underTest.submit(createTaskSubmit(reportType, component, null)); | |||
} | |||
private CeTaskSubmit createTaskSubmit(String type) { | |||
return createTaskSubmit(type, null, null); | |||
} | |||
private CeTaskSubmit createTaskSubmit(String type, @Nullable String componentUuid, @Nullable String submitterUuid) { | |||
private CeTaskSubmit createTaskSubmit(String type, @Nullable Component component, @Nullable String submitterUuid) { | |||
return underTest.prepareSubmit() | |||
.setType(type) | |||
.setComponentUuid(componentUuid) | |||
.setComponent(component) | |||
.setSubmitterUuid(submitterUuid) | |||
.setCharacteristics(emptyMap()) | |||
.build(); | |||
@@ -489,14 +535,22 @@ public class CeQueueImplTest { | |||
return componentDto; | |||
} | |||
private CeQueueDto insertPendingInQueue(@Nullable String componentUuid) { | |||
private CeQueueDto insertPendingInQueue(@Nullable Component component) { | |||
CeQueueDto dto = new CeQueueDto() | |||
.setUuid(UuidFactoryFast.getInstance().create()) | |||
.setTaskType("some type") | |||
.setComponentUuid(componentUuid) | |||
.setStatus(CeQueueDto.Status.PENDING); | |||
if (component != null) { | |||
dto.setComponentUuid(component.getUuid()) | |||
.setMainComponentUuid(component.getMainComponentUuid()); | |||
} | |||
db.getDbClient().ceQueueDao().insert(db.getSession(), dto); | |||
db.commit(); | |||
return dto; | |||
} | |||
private static int newComponentIdGenerator = new Random().nextInt(8_999_333); | |||
private static Component newComponent(String mainComponentUuid) { | |||
return new Component("uuid_" + newComponentIdGenerator++, mainComponentUuid); | |||
} | |||
} |
@@ -148,10 +148,12 @@ public class PostProjectAnalysisTasksExecutor implements ComputationStepExecutor | |||
} | |||
private static Project createProject(org.sonar.ce.task.CeTask ceTask) { | |||
return new ProjectImpl( | |||
ceTask.getComponentUuid(), | |||
ceTask.getComponentKey(), | |||
ceTask.getComponentName()); | |||
return ceTask.getMainComponent() | |||
.map(c -> new ProjectImpl( | |||
c.getUuid(), | |||
c.getKey().orElseThrow(() -> new IllegalStateException("Missing project key")), | |||
c.getName().orElseThrow(() -> new IllegalStateException("Missing project name")))) | |||
.orElseThrow(() -> new IllegalStateException("Report processed for a task of a deleted component")); | |||
} | |||
@CheckForNull |
@@ -21,10 +21,11 @@ package org.sonar.ce.task.projectanalysis.component; | |||
import javax.annotation.Nullable; | |||
import org.sonar.api.utils.MessageException; | |||
import org.sonar.scanner.protocol.output.ScannerReport; | |||
import org.sonar.ce.task.projectanalysis.analysis.MutableAnalysisMetadataHolder; | |||
import org.sonar.scanner.protocol.output.ScannerReport; | |||
import static org.apache.commons.lang.StringUtils.trimToNull; | |||
import static org.sonar.scanner.protocol.output.ScannerReport.Metadata.BranchType.UNSET; | |||
public class BranchLoader { | |||
private final MutableAnalysisMetadataHolder metadataHolder; | |||
@@ -47,10 +48,22 @@ public class BranchLoader { | |||
throw MessageException.of("Properties sonar.branch and sonar.branch.name can't be set together"); | |||
} | |||
if (delegate == null && hasBranchProperties(metadata)) { | |||
throw MessageException.of("Current edition does not support branch feature"); | |||
} | |||
if (delegate != null && deprecatedBranch == null) { | |||
delegate.load(metadata); | |||
} else { | |||
metadataHolder.setBranch(new DefaultBranchImpl(deprecatedBranch)); | |||
} | |||
} | |||
private static boolean hasBranchProperties(ScannerReport.Metadata metadata) { | |||
return !metadata.getBranchName().isEmpty() | |||
|| !metadata.getPullRequestKey().isEmpty() | |||
|| !metadata.getMergeBranchName().isEmpty() | |||
|| metadata.getBranchType() != UNSET; | |||
} | |||
} |
@@ -19,10 +19,7 @@ | |||
*/ | |||
package org.sonar.ce.task.projectanalysis.component; | |||
import java.util.Date; | |||
import java.util.Optional; | |||
import javax.annotation.Nullable; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder; | |||
import org.sonar.ce.task.projectanalysis.analysis.Branch; | |||
import org.sonar.db.DbClient; | |||
@@ -32,18 +29,16 @@ import org.sonar.db.component.BranchType; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.protobuf.DbProjectBranches; | |||
import static org.sonar.db.component.ComponentDto.UUID_PATH_OF_ROOT; | |||
import static org.sonar.db.component.ComponentDto.UUID_PATH_SEPARATOR; | |||
/** | |||
* Creates or updates the data in table {@code PROJECT_BRANCHES} for the current root. | |||
*/ | |||
public class BranchPersisterImpl implements BranchPersister { | |||
private final DbClient dbClient; | |||
private final System2 system2; | |||
private final TreeRootHolder treeRootHolder; | |||
private final AnalysisMetadataHolder analysisMetadataHolder; | |||
public BranchPersisterImpl(DbClient dbClient, System2 system2, TreeRootHolder treeRootHolder, AnalysisMetadataHolder analysisMetadataHolder) { | |||
public BranchPersisterImpl(DbClient dbClient, TreeRootHolder treeRootHolder, AnalysisMetadataHolder analysisMetadataHolder) { | |||
this.dbClient = dbClient; | |||
this.system2 = system2; | |||
this.treeRootHolder = treeRootHolder; | |||
this.analysisMetadataHolder = analysisMetadataHolder; | |||
} | |||
@@ -52,32 +47,14 @@ public class BranchPersisterImpl implements BranchPersister { | |||
Branch branch = analysisMetadataHolder.getBranch(); | |||
String branchUuid = treeRootHolder.getRoot().getUuid(); | |||
Optional<ComponentDto> branchComponentDtoOpt = dbClient.componentDao().selectByUuid(dbSession, branchUuid); | |||
ComponentDto branchComponentDto; | |||
if (branch.isMain()) { | |||
checkState(branchComponentDtoOpt.isPresent(), "Project has been deleted by end-user during analysis"); | |||
branchComponentDto = branchComponentDtoOpt.get(); | |||
} else { | |||
// inserts new row in table projects if it's the first time branch is analyzed | |||
branchComponentDto = branchComponentDtoOpt.orElseGet(() -> insertIntoProjectsTable(dbSession, branchUuid)); | |||
} | |||
ComponentDto branchComponentDto = dbClient.componentDao().selectByUuid(dbSession, branchUuid) | |||
.orElseThrow(() -> new IllegalStateException("Component has been deleted by end-user during analysis")); | |||
// insert or update in table project_branches | |||
dbClient.branchDao().upsert(dbSession, toBranchDto(branchComponentDto, branch)); | |||
} | |||
private static void checkState(boolean condition, String msg) { | |||
if (!condition) { | |||
throw new IllegalStateException(msg); | |||
} | |||
} | |||
private static <T> T firstNonNull(@Nullable T first, T second) { | |||
return (first != null) ? first : second; | |||
} | |||
private BranchDto toBranchDto(ComponentDto componentDto, Branch branch) { | |||
protected BranchDto toBranchDto(ComponentDto componentDto, Branch branch) { | |||
BranchDto dto = new BranchDto(); | |||
dto.setUuid(componentDto.uuid()); | |||
@@ -103,19 +80,8 @@ public class BranchPersisterImpl implements BranchPersister { | |||
return dto; | |||
} | |||
private ComponentDto insertIntoProjectsTable(DbSession dbSession, String branchUuid) { | |||
String mainBranchProjectUuid = analysisMetadataHolder.getProject().getUuid(); | |||
ComponentDto project = dbClient.componentDao().selectOrFailByUuid(dbSession, mainBranchProjectUuid); | |||
ComponentDto branchDto = project.copy(); | |||
branchDto.setUuid(branchUuid); | |||
branchDto.setProjectUuid(branchUuid); | |||
branchDto.setRootUuid(branchUuid); | |||
branchDto.setUuidPath(UUID_PATH_OF_ROOT); | |||
branchDto.setModuleUuidPath(UUID_PATH_SEPARATOR + branchUuid + UUID_PATH_SEPARATOR); | |||
branchDto.setMainBranchProjectUuid(mainBranchProjectUuid); | |||
branchDto.setDbKey(treeRootHolder.getRoot().getDbKey()); | |||
branchDto.setCreatedAt(new Date(system2.now())); | |||
dbClient.componentDao().insert(dbSession, branchDto); | |||
return branchDto; | |||
private static <T> T firstNonNull(@Nullable T first, T second) { | |||
return (first != null) ? first : second; | |||
} | |||
} |
@@ -41,18 +41,19 @@ public class PopulateFileSourceLineCount extends DataChange implements ProjectAn | |||
@Override | |||
protected void execute(Context context) throws SQLException { | |||
String componentUuid = ceTask.getComponent().get().getUuid(); | |||
Long unInitializedFileSources = context.prepareSelect("select count(1) from file_sources where line_count = ? and project_uuid = ?") | |||
.setInt(1, LINE_COUNT_NOT_POPULATED) | |||
.setString(2, ceTask.getComponentUuid()) | |||
.setString(2, componentUuid) | |||
.get(row -> row.getLong(1)); | |||
if (unInitializedFileSources != null && unInitializedFileSources > 0) { | |||
MassUpdate massUpdate = context.prepareMassUpdate(); | |||
massUpdate.select("select id,line_hashes from file_sources where line_count = ? and project_uuid = ?") | |||
.setInt(1, LINE_COUNT_NOT_POPULATED) | |||
.setString(2, ceTask.getComponentUuid()); | |||
.setString(2, componentUuid); | |||
massUpdate.update("update file_sources set line_count = ? where id = ?"); | |||
massUpdate.rowPluralName("line counts of sources of project " + ceTask.getComponentUuid()); | |||
massUpdate.rowPluralName("line counts of sources of project " + componentUuid); | |||
massUpdate.execute(PopulateFileSourceLineCount::handle); | |||
} | |||
} |
@@ -104,30 +104,40 @@ public class LoadReportAnalysisMetadataHolderStep implements ComputationStep { | |||
*/ | |||
private Runnable loadProject(ScannerReport.Metadata reportMetadata, Organization organization) { | |||
String reportProjectKey = projectKeyFromReport(reportMetadata); | |||
String componentKey = ceTask.getComponentKey(); | |||
if (componentKey == null) { | |||
throw MessageException.of(format( | |||
CeTask.Component mainComponent = mandatoryComponent(ceTask.getMainComponent()); | |||
String mainComponentKey = mainComponent.getKey() | |||
.orElseThrow(() -> MessageException.of(format( | |||
"Compute Engine task main component key is null. Project with UUID %s must have been deleted since report was uploaded. Can not proceed.", | |||
mainComponent.getUuid()))); | |||
CeTask.Component component = mandatoryComponent(ceTask.getComponent()); | |||
String componentKey = component.getKey() | |||
.orElseThrow(() -> MessageException.of(format( | |||
"Compute Engine task component key is null. Project with UUID %s must have been deleted since report was uploaded. Can not proceed.", | |||
ceTask.getComponentUuid())); | |||
} | |||
component.getUuid()))); | |||
ComponentDto dto = toProject(reportProjectKey); | |||
analysisMetadata.setProject(Project.from(dto)); | |||
return () -> { | |||
if (!componentKey.equals(reportProjectKey)) { | |||
if (!mainComponentKey.equals(reportProjectKey)) { | |||
throw MessageException.of(format( | |||
"ProjectKey in report (%s) is not consistent with projectKey under which the report has been submitted (%s)", | |||
reportProjectKey, | |||
componentKey)); | |||
mainComponentKey)); | |||
} | |||
if (!dto.getOrganizationUuid().equals(organization.getUuid())) { | |||
throw MessageException.of(format("Project is not in the expected organization: %s", organization.getKey())); | |||
} | |||
if (dto.getMainBranchProjectUuid() != null) { | |||
throw MessageException.of("Project should not reference a branch"); | |||
if (componentKey.equals(mainComponentKey) && dto.getMainBranchProjectUuid() != null) { | |||
throw MessageException.of("Component should not reference a branch"); | |||
} | |||
}; | |||
} | |||
private static CeTask.Component mandatoryComponent(Optional<CeTask.Component> mainComponent) { | |||
return mainComponent | |||
.orElseThrow(() -> new IllegalStateException("component missing on ce task")); | |||
} | |||
private Organization loadOrganization(ScannerReport.Metadata reportMetadata) { | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
Organization organization = toOrganization(dbSession, ceTask.getOrganizationUuid()); |
@@ -87,13 +87,13 @@ public class PostProjectAnalysisTasksExecutorTest { | |||
private String organizationName = organizationUuid + "_name"; | |||
private System2 system2 = mock(System2.class); | |||
private ArgumentCaptor<PostProjectAnalysisTask.ProjectAnalysis> projectAnalysisArgumentCaptor = ArgumentCaptor.forClass(PostProjectAnalysisTask.ProjectAnalysis.class); | |||
private CeTask.Component component = new CeTask.Component("component uuid", "component key", "component name"); | |||
private CeTask ceTask = new CeTask.Builder() | |||
.setOrganizationUuid(organizationUuid) | |||
.setType("type") | |||
.setUuid("uuid") | |||
.setComponentKey("component key") | |||
.setComponentName("component name") | |||
.setComponentUuid("component uuid") | |||
.setComponent(component) | |||
.setMainComponent(component) | |||
.build(); | |||
private PostProjectAnalysisTask postProjectAnalysisTask = mock(PostProjectAnalysisTask.class); | |||
private PostProjectAnalysisTasksExecutor underTest = new PostProjectAnalysisTasksExecutor( | |||
@@ -203,9 +203,9 @@ public class PostProjectAnalysisTasksExecutorTest { | |||
verify(postProjectAnalysisTask).finished(projectAnalysisArgumentCaptor.capture()); | |||
Project project = projectAnalysisArgumentCaptor.getValue().getProject(); | |||
assertThat(project.getUuid()).isEqualTo(ceTask.getComponentUuid()); | |||
assertThat(project.getKey()).isEqualTo(ceTask.getComponentKey()); | |||
assertThat(project.getName()).isEqualTo(ceTask.getComponentName()); | |||
assertThat(project.getUuid()).isEqualTo(ceTask.getComponent().get().getUuid()); | |||
assertThat(project.getKey()).isEqualTo(ceTask.getComponent().get().getKey().get()); | |||
assertThat(project.getName()).isEqualTo(ceTask.getComponent().get().getName().get()); | |||
} | |||
@Test |
@@ -19,25 +19,36 @@ | |||
*/ | |||
package org.sonar.ce.task.projectanalysis.component; | |||
import com.tngtech.java.junit.dataprovider.DataProvider; | |||
import com.tngtech.java.junit.dataprovider.DataProviderRunner; | |||
import com.tngtech.java.junit.dataprovider.UseDataProvider; | |||
import java.util.Optional; | |||
import javax.annotation.Nullable; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.junit.runner.RunWith; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolderRule; | |||
import org.sonar.ce.task.projectanalysis.analysis.Branch; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.component.BranchDto; | |||
import org.sonar.db.component.BranchType; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.component.ComponentTesting; | |||
import org.sonar.db.protobuf.DbProjectBranches; | |||
import org.sonar.server.project.Project; | |||
import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.when; | |||
import static org.sonar.ce.task.projectanalysis.component.Component.Type.PROJECT; | |||
import static org.sonar.ce.task.projectanalysis.component.ReportComponent.builder; | |||
import static org.sonar.db.component.BranchType.LONG; | |||
import static org.sonar.db.component.BranchType.PULL_REQUEST; | |||
@RunWith(DataProviderRunner.class) | |||
public class BranchPersisterImplTest { | |||
private final static Component MAIN = builder(PROJECT, 1).setUuid("PROJECT_UUID").setKey("PROJECT_KEY").build(); | |||
private final static Component BRANCH = builder(PROJECT, 1).setUuid("BRANCH_UUID").setKey("BRANCH_KEY").build(); | |||
@@ -51,66 +62,133 @@ public class BranchPersisterImplTest { | |||
@Rule | |||
public ExpectedException exception = ExpectedException.none(); | |||
BranchPersister underTest = new BranchPersisterImpl(dbTester.getDbClient(), System2.INSTANCE, treeRootHolder, analysisMetadataHolder); | |||
BranchPersister underTest = new BranchPersisterImpl(dbTester.getDbClient(), treeRootHolder, analysisMetadataHolder); | |||
@Test | |||
public void fail_if_no_component_for_main_branches() { | |||
analysisMetadataHolder.setBranch(createBranch(BranchType.LONG, true, "master")); | |||
public void persist_fails_with_ISE_if_no_component_for_main_branches() { | |||
analysisMetadataHolder.setBranch(createBranch(LONG, true, "master")); | |||
treeRootHolder.setRoot(MAIN); | |||
exception.expect(IllegalStateException.class); | |||
exception.expectMessage("Project has been deleted by end-user during analysis"); | |||
expectMissingComponentISE(); | |||
underTest.persist(dbTester.getSession()); | |||
} | |||
@Test | |||
public void persist_fails_with_ISE_if_no_component_for_long_branches() { | |||
analysisMetadataHolder.setBranch(createBranch(LONG, false, "foo")); | |||
treeRootHolder.setRoot(BRANCH); | |||
expectMissingComponentISE(); | |||
underTest.persist(dbTester.getSession()); | |||
} | |||
@Test | |||
public void persist_secondary_branch() { | |||
analysisMetadataHolder.setBranch(createBranch(BranchType.LONG, false, "branch")); | |||
public void persist_fails_with_ISE_if_no_component_for_short_branches() { | |||
analysisMetadataHolder.setBranch(createBranch(BranchType.SHORT, false, "foo")); | |||
treeRootHolder.setRoot(BRANCH); | |||
// add main branch in project table and in metadata | |||
ComponentDto dto = ComponentTesting.newPrivateProjectDto(dbTester.organizations().insert(), MAIN.getUuid()).setDbKey(MAIN.getDbKey()); | |||
analysisMetadataHolder.setProject(Project.from(dto)); | |||
dbTester.getDbClient().componentDao().insert(dbTester.getSession(), dto); | |||
expectMissingComponentISE(); | |||
underTest.persist(dbTester.getSession()); | |||
} | |||
@Test | |||
public void persist_fails_with_ISE_if_no_component_for_pull_request() { | |||
analysisMetadataHolder.setBranch(createBranch(BranchType.PULL_REQUEST, false, "12")); | |||
treeRootHolder.setRoot(BRANCH); | |||
expectMissingComponentISE(); | |||
underTest.persist(dbTester.getSession()); | |||
} | |||
@Test | |||
@UseDataProvider("nullOrNotNullString") | |||
public void persist_creates_row_in_PROJECTS_BRANCHES_for_long_branch(@Nullable String mergeBranchUuid) { | |||
String branchName = "branch"; | |||
// add project and branch in table PROJECTS | |||
ComponentDto mainComponent = ComponentTesting.newPrivateProjectDto(dbTester.organizations().insert(), MAIN.getUuid()).setDbKey(MAIN.getKey()); | |||
ComponentDto component = ComponentTesting.newProjectBranch(mainComponent, new BranchDto().setUuid(BRANCH.getUuid()).setKey(BRANCH.getKey()).setBranchType(LONG)); | |||
dbTester.getDbClient().componentDao().insert(dbTester.getSession(), mainComponent, component); | |||
dbTester.commit(); | |||
// set project in metadata | |||
treeRootHolder.setRoot(BRANCH); | |||
analysisMetadataHolder.setBranch(createBranch(LONG, false, branchName, mergeBranchUuid)); | |||
analysisMetadataHolder.setProject(Project.from(mainComponent)); | |||
// this should add new columns in project and project_branches | |||
underTest.persist(dbTester.getSession()); | |||
dbTester.getSession().commit(); | |||
assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(2); | |||
assertThat(dbTester.countRowsOfTable("project_branches")).isEqualTo(1); | |||
Optional<BranchDto> branchDto = dbTester.getDbClient().branchDao().selectByUuid(dbTester.getSession(), BRANCH.getUuid()); | |||
assertThat(branchDto).isPresent(); | |||
assertThat(branchDto.get().getBranchType()).isEqualTo(LONG); | |||
assertThat(branchDto.get().getKey()).isEqualTo(branchName); | |||
assertThat(branchDto.get().getMergeBranchUuid()).isEqualTo(mergeBranchUuid); | |||
assertThat(branchDto.get().getProjectUuid()).isEqualTo(MAIN.getUuid()); | |||
assertThat(branchDto.get().getPullRequestData()).isNull(); | |||
} | |||
@DataProvider | |||
public static Object[][] nullOrNotNullString() { | |||
return new Object[][] { | |||
{null}, | |||
{randomAlphabetic(12)} | |||
}; | |||
} | |||
@Test | |||
public void persist_pull_request_data() { | |||
@UseDataProvider("nullOrNotNullString") | |||
public void persist_creates_row_in_PROJECTS_BRANCHES_for_pull_request(@Nullable String mergeBranchUuid) { | |||
String pullRequestId = "pr-123"; | |||
analysisMetadataHolder.setBranch(createBranch(BranchType.PULL_REQUEST, false, pullRequestId)); | |||
analysisMetadataHolder.setPullRequestKey(pullRequestId); | |||
treeRootHolder.setRoot(BRANCH); | |||
// add main branch in project table and in metadata | |||
ComponentDto dto = ComponentTesting.newPrivateProjectDto(dbTester.organizations().insert(), MAIN.getUuid()).setDbKey(MAIN.getDbKey()); | |||
analysisMetadataHolder.setProject(Project.from(dto)); | |||
dbTester.getDbClient().componentDao().insert(dbTester.getSession(), dto); | |||
// add project and branch in table PROJECTS | |||
ComponentDto mainComponent = ComponentTesting.newPrivateProjectDto(dbTester.organizations().insert(), MAIN.getUuid()).setDbKey(MAIN.getKey()); | |||
ComponentDto component = ComponentTesting.newProjectBranch(mainComponent, new BranchDto().setUuid(BRANCH.getUuid()).setKey(BRANCH.getKey()).setBranchType(PULL_REQUEST)); | |||
dbTester.getDbClient().componentDao().insert(dbTester.getSession(), mainComponent, component); | |||
dbTester.commit(); | |||
// set project in metadata | |||
treeRootHolder.setRoot(BRANCH); | |||
analysisMetadataHolder.setBranch(createBranch(PULL_REQUEST, false, pullRequestId, mergeBranchUuid)); | |||
analysisMetadataHolder.setProject(Project.from(mainComponent)); | |||
analysisMetadataHolder.setPullRequestKey(pullRequestId); | |||
// this should add new columns in project and project_branches | |||
underTest.persist(dbTester.getSession()); | |||
dbTester.getSession().commit(); | |||
assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(2); | |||
assertThat(dbTester.countRowsOfTable("project_branches")).isEqualTo(1); | |||
assertThat(dbTester.countSql("select count(*) from project_branches where pull_request_binary is not null")).isEqualTo(1); | |||
Optional<BranchDto> branchDto = dbTester.getDbClient().branchDao().selectByUuid(dbTester.getSession(), BRANCH.getUuid()); | |||
assertThat(branchDto).isPresent(); | |||
assertThat(branchDto.get().getBranchType()).isEqualTo(PULL_REQUEST); | |||
assertThat(branchDto.get().getKey()).isEqualTo(pullRequestId); | |||
assertThat(branchDto.get().getMergeBranchUuid()).isEqualTo(mergeBranchUuid); | |||
assertThat(branchDto.get().getProjectUuid()).isEqualTo(MAIN.getUuid()); | |||
assertThat(branchDto.get().getPullRequestData()).isEqualTo(DbProjectBranches.PullRequestData.newBuilder() | |||
.setBranch(pullRequestId) | |||
.setTitle(pullRequestId) | |||
.build()); | |||
} | |||
private static Branch createBranch(BranchType type, boolean isMain, String name) { | |||
return createBranch(type, isMain, name, null); | |||
} | |||
private static Branch createBranch(BranchType type, boolean isMain, String name, @Nullable String mergeBranchUuid) { | |||
Branch branch = mock(Branch.class); | |||
when(branch.getType()).thenReturn(type); | |||
when(branch.getName()).thenReturn(name); | |||
when(branch.isMain()).thenReturn(isMain); | |||
when(branch.getMergeBranchUuid()).thenReturn(Optional.empty()); | |||
when(branch.getMergeBranchUuid()).thenReturn(Optional.ofNullable(mergeBranchUuid)); | |||
return branch; | |||
} | |||
private void expectMissingComponentISE() { | |||
exception.expect(IllegalStateException.class); | |||
exception.expectMessage("Component has been deleted by end-user during analysis"); | |||
} | |||
} |
@@ -23,6 +23,7 @@ import com.tngtech.java.junit.dataprovider.DataProvider; | |||
import com.tngtech.java.junit.dataprovider.DataProviderRunner; | |||
import com.tngtech.java.junit.dataprovider.UseDataProvider; | |||
import java.sql.SQLException; | |||
import java.util.Optional; | |||
import java.util.Random; | |||
import java.util.stream.Collectors; | |||
import java.util.stream.IntStream; | |||
@@ -57,6 +58,9 @@ public class PopulateFileSourceLineCountTest { | |||
@Test | |||
public void execute_has_no_effect_on_empty_table() throws SQLException { | |||
String projectUuid = randomAlphanumeric(4); | |||
when(ceTask.getComponent()).thenReturn(newComponent(projectUuid)); | |||
underTest.execute(); | |||
} | |||
@@ -65,7 +69,7 @@ public class PopulateFileSourceLineCountTest { | |||
public void execute_populates_line_count_of_any_type(String type) throws SQLException { | |||
String projectUuid = randomAlphanumeric(4); | |||
String fileUuid = randomAlphanumeric(5); | |||
when(ceTask.getComponentUuid()).thenReturn(projectUuid); | |||
when(ceTask.getComponent()).thenReturn(newComponent(projectUuid)); | |||
int lineCount = 1 + random.nextInt(15); | |||
insertUnpopulatedFileSource(projectUuid, fileUuid, type, lineCount); | |||
assertThat(getLineCountByFileUuid(fileUuid)).isEqualTo(LINE_COUNT_NOT_POPULATED); | |||
@@ -86,7 +90,7 @@ public class PopulateFileSourceLineCountTest { | |||
int lineCountFile2 = 50 + random.nextInt(15); | |||
int lineCountFile3 = 150 + random.nextInt(15); | |||
when(ceTask.getComponentUuid()).thenReturn(projectUuid); | |||
when(ceTask.getComponent()).thenReturn(newComponent(projectUuid)); | |||
insertPopulatedFileSource(projectUuid, fileUuid1, type, lineCountFile1); | |||
int badLineCountFile2 = insertInconsistentPopulatedFileSource(projectUuid, fileUuid2, type, lineCountFile2); | |||
insertUnpopulatedFileSource(projectUuid, fileUuid3, type, lineCountFile3); | |||
@@ -111,7 +115,7 @@ public class PopulateFileSourceLineCountTest { | |||
int lineCountFile1 = 100 + random.nextInt(15); | |||
int lineCountFile2 = 30 + random.nextInt(15); | |||
when(ceTask.getComponentUuid()).thenReturn(projectUuid1); | |||
when(ceTask.getComponent()).thenReturn(newComponent(projectUuid1)); | |||
insertUnpopulatedFileSource(projectUuid1, fileUuid1, type, lineCountFile1); | |||
insertUnpopulatedFileSource(projectUuid2, fileUuid2, type, lineCountFile2); | |||
@@ -127,7 +131,7 @@ public class PopulateFileSourceLineCountTest { | |||
String projectUuid = randomAlphanumeric(4); | |||
String fileUuid1 = randomAlphanumeric(5); | |||
when(ceTask.getComponentUuid()).thenReturn(projectUuid); | |||
when(ceTask.getComponent()).thenReturn(newComponent(projectUuid)); | |||
insertFileSource(projectUuid, fileUuid1, type, null, LINE_COUNT_NOT_POPULATED); | |||
underTest.execute(); | |||
@@ -141,7 +145,7 @@ public class PopulateFileSourceLineCountTest { | |||
String projectUuid = randomAlphanumeric(4); | |||
String fileUuid1 = randomAlphanumeric(5); | |||
when(ceTask.getComponentUuid()).thenReturn(projectUuid); | |||
when(ceTask.getComponent()).thenReturn(newComponent(projectUuid)); | |||
insertFileSource(projectUuid, fileUuid1, type, "", LINE_COUNT_NOT_POPULATED); | |||
underTest.execute(); | |||
@@ -204,4 +208,8 @@ public class PopulateFileSourceLineCountTest { | |||
"UPDATED_AT", 1_222_333L); | |||
db.commit(); | |||
} | |||
private static Optional<CeTask.Component> newComponent(String projectUuid) { | |||
return Optional.of(new CeTask.Component(projectUuid, "key_" + projectUuid, "name_" + projectUuid)); | |||
} | |||
} |
@@ -25,6 +25,7 @@ import com.tngtech.java.junit.dataprovider.UseDataProvider; | |||
import java.util.Collection; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import java.util.Optional; | |||
import org.assertj.core.api.Assertions; | |||
import org.junit.Before; | |||
import org.junit.Rule; | |||
@@ -165,10 +166,44 @@ public class LoadReportAnalysisMetadataHolderStepTest { | |||
assertThat(analysisMetadataHolder.isCrossProjectDuplicationEnabled()).isEqualTo(false); | |||
} | |||
@Test | |||
public void execute_fails_with_ISE_if_component_is_null_in_CE_task() { | |||
CeTask res = mock(CeTask.class); | |||
when(res.getComponent()).thenReturn(Optional.empty()); | |||
when(res.getOrganizationUuid()).thenReturn(defaultOrganizationProvider.get().getUuid()); | |||
reportReader.setMetadata(ScannerReport.Metadata.newBuilder().build()); | |||
ComputationStep underTest = createStep(res); | |||
expectedException.expect(IllegalStateException.class); | |||
expectedException.expectMessage("component missing on ce task"); | |||
underTest.execute(new TestComputationStepContext()); | |||
} | |||
@Test | |||
public void execute_fails_with_MessageException_if_main_projectKey_is_null_in_CE_task() { | |||
CeTask res = mock(CeTask.class); | |||
Optional<CeTask.Component> component = Optional.of(new CeTask.Component("main_prj_uuid", null, null)); | |||
when(res.getComponent()).thenReturn(component); | |||
when(res.getMainComponent()).thenReturn(component); | |||
when(res.getOrganizationUuid()).thenReturn(defaultOrganizationProvider.get().getUuid()); | |||
reportReader.setMetadata(ScannerReport.Metadata.newBuilder().build()); | |||
ComputationStep underTest = createStep(res); | |||
expectedException.expect(MessageException.class); | |||
expectedException.expectMessage("Compute Engine task main component key is null. Project with UUID main_prj_uuid must have been deleted since report was uploaded. Can not proceed."); | |||
underTest.execute(new TestComputationStepContext()); | |||
} | |||
@Test | |||
public void execute_fails_with_MessageException_if_projectKey_is_null_in_CE_task() { | |||
CeTask res = mock(CeTask.class); | |||
when(res.getComponentUuid()).thenReturn("prj_uuid"); | |||
Optional<CeTask.Component> component = Optional.of(new CeTask.Component("prj_uuid", null, null)); | |||
when(res.getComponent()).thenReturn(component); | |||
when(res.getMainComponent()).thenReturn(Optional.of(new CeTask.Component("main_prj_uuid", "main_prj_key", null))); | |||
when(res.getOrganizationUuid()).thenReturn(defaultOrganizationProvider.get().getUuid()); | |||
reportReader.setMetadata(ScannerReport.Metadata.newBuilder().build()); | |||
@@ -407,8 +442,10 @@ public class LoadReportAnalysisMetadataHolderStepTest { | |||
private CeTask createCeTask(String projectKey, String organizationUuid) { | |||
CeTask res = mock(CeTask.class); | |||
Optional<CeTask.Component> component = Optional.of(new CeTask.Component(projectKey + "_uuid", projectKey, projectKey + "_name")); | |||
when(res.getOrganizationUuid()).thenReturn(organizationUuid); | |||
when(res.getComponentKey()).thenReturn(projectKey); | |||
when(res.getComponent()).thenReturn(component); | |||
when(res.getMainComponent()).thenReturn(component); | |||
return res; | |||
} | |||
@@ -22,10 +22,13 @@ package org.sonar.ce.task; | |||
import com.google.common.base.MoreObjects; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import java.util.Objects; | |||
import java.util.Optional; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import javax.annotation.concurrent.Immutable; | |||
import static com.google.common.base.Preconditions.checkArgument; | |||
import static com.google.common.base.Strings.emptyToNull; | |||
import static java.util.Collections.emptyMap; | |||
import static java.util.Collections.unmodifiableMap; | |||
@@ -37,9 +40,8 @@ public class CeTask { | |||
private final String organizationUuid; | |||
private final String type; | |||
private final String uuid; | |||
private final String componentUuid; | |||
private final String componentKey; | |||
private final String componentName; | |||
private final Component component; | |||
private final Component mainComponent; | |||
private final String submitterUuid; | |||
private final Map<String, String> characteristics; | |||
@@ -47,9 +49,10 @@ public class CeTask { | |||
this.organizationUuid = requireNonNull(emptyToNull(builder.organizationUuid), "organizationUuid can't be null nor empty"); | |||
this.uuid = requireNonNull(emptyToNull(builder.uuid), "uuid can't be null nor empty"); | |||
this.type = requireNonNull(emptyToNull(builder.type), "type can't be null nor empty"); | |||
this.componentUuid = emptyToNull(builder.componentUuid); | |||
this.componentKey = emptyToNull(builder.componentKey); | |||
this.componentName = emptyToNull(builder.componentName); | |||
checkArgument((builder.component == null) == (builder.mainComponent == null), | |||
"None or both component and main component must be non null"); | |||
this.component = builder.component; | |||
this.mainComponent = builder.mainComponent; | |||
this.submitterUuid = emptyToNull(builder.submitterUuid); | |||
if (builder.characteristics == null) { | |||
this.characteristics = emptyMap(); | |||
@@ -70,19 +73,12 @@ public class CeTask { | |||
return type; | |||
} | |||
@CheckForNull | |||
public String getComponentUuid() { | |||
return componentUuid; | |||
} | |||
@CheckForNull | |||
public String getComponentKey() { | |||
return componentKey; | |||
public Optional<Component> getComponent() { | |||
return Optional.ofNullable(component); | |||
} | |||
@CheckForNull | |||
public String getComponentName() { | |||
return componentName; | |||
public Optional<Component> getMainComponent() { | |||
return Optional.ofNullable(mainComponent); | |||
} | |||
@CheckForNull | |||
@@ -100,9 +96,8 @@ public class CeTask { | |||
.add("organizationUuid", organizationUuid) | |||
.add("type", type) | |||
.add("uuid", uuid) | |||
.add("componentUuid", componentUuid) | |||
.add("componentKey", componentKey) | |||
.add("componentName", componentName) | |||
.add("component", component) | |||
.add("mainComponent", mainComponent) | |||
.add("submitterUuid", submitterUuid) | |||
.toString(); | |||
} | |||
@@ -128,9 +123,8 @@ public class CeTask { | |||
private String organizationUuid; | |||
private String uuid; | |||
private String type; | |||
private String componentUuid; | |||
private String componentKey; | |||
private String componentName; | |||
private Component component; | |||
private Component mainComponent; | |||
private String submitterUuid; | |||
private Map<String, String> characteristics; | |||
@@ -154,18 +148,13 @@ public class CeTask { | |||
return this; | |||
} | |||
public Builder setComponentUuid(@Nullable String componentUuid) { | |||
this.componentUuid = componentUuid; | |||
return this; | |||
} | |||
public Builder setComponentKey(@Nullable String s) { | |||
this.componentKey = s; | |||
public Builder setComponent(@Nullable Component component) { | |||
this.component = component; | |||
return this; | |||
} | |||
public Builder setComponentName(@Nullable String s) { | |||
this.componentName = s; | |||
public Builder setMainComponent(@Nullable Component mainComponent) { | |||
this.mainComponent = mainComponent; | |||
return this; | |||
} | |||
@@ -183,4 +172,58 @@ public class CeTask { | |||
return new CeTask(this); | |||
} | |||
} | |||
public static final class Component { | |||
private final String uuid; | |||
@CheckForNull | |||
private final String key; | |||
@CheckForNull | |||
private final String name; | |||
public Component(String uuid, @Nullable String key, @Nullable String name) { | |||
this.uuid = requireNonNull(emptyToNull(uuid), "uuid can't be null nor empty"); | |||
this.key = emptyToNull(key); | |||
this.name = emptyToNull(name); | |||
} | |||
public String getUuid() { | |||
return uuid; | |||
} | |||
public Optional<String> getKey() { | |||
return Optional.ofNullable(key); | |||
} | |||
public Optional<String> getName() { | |||
return Optional.ofNullable(name); | |||
} | |||
@Override | |||
public boolean equals(Object o) { | |||
if (this == o) { | |||
return true; | |||
} | |||
if (o == null || getClass() != o.getClass()) { | |||
return false; | |||
} | |||
Component component = (Component) o; | |||
return Objects.equals(uuid, component.uuid) && | |||
Objects.equals(key, component.key) && | |||
Objects.equals(name, component.name); | |||
} | |||
@Override | |||
public int hashCode() { | |||
return Objects.hash(uuid, key, name); | |||
} | |||
@Override | |||
public String toString() { | |||
return "Component{" + | |||
"uuid='" + uuid + '\'' + | |||
", key='" + key + '\'' + | |||
", name='" + name + '\'' + | |||
'}'; | |||
} | |||
} | |||
} |
@@ -0,0 +1,105 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 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.task; | |||
import com.tngtech.java.junit.dataprovider.DataProvider; | |||
import com.tngtech.java.junit.dataprovider.DataProviderRunner; | |||
import com.tngtech.java.junit.dataprovider.UseDataProvider; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.junit.runner.RunWith; | |||
import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
@RunWith(DataProviderRunner.class) | |||
public class CeTaskComponentTest { | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
@Test | |||
@UseDataProvider("nullOrEmpty") | |||
public void constructor_fails_with_NPE_if_uuid_is_null_or_empty(String str) { | |||
expectedException.expect(NullPointerException.class); | |||
expectedException.expectMessage("uuid can't be null nor empty"); | |||
new CeTask.Component(str, "foo", "bar"); | |||
} | |||
@Test | |||
@UseDataProvider("nullOrEmpty") | |||
public void constructor_considers_empty_as_null_and_accept_it_for_key(String str) { | |||
CeTask.Component underTest = new CeTask.Component("foo", str, "bar"); | |||
assertThat(underTest.getKey()).isEmpty(); | |||
} | |||
@Test | |||
@UseDataProvider("nullOrEmpty") | |||
public void constructor_considers_empty_as_null_and_accept_it_for_name(String str) { | |||
CeTask.Component underTest = new CeTask.Component("foo", "bar", str); | |||
assertThat(underTest.getName()).isEmpty(); | |||
} | |||
@Test | |||
public void equals_is_based_on_all_fields() { | |||
String uuid = randomAlphabetic(2); | |||
String key = randomAlphabetic(3); | |||
String name = randomAlphabetic(4); | |||
String somethingElse = randomAlphabetic(5); | |||
CeTask.Component underTest = new CeTask.Component(uuid, key, name); | |||
assertThat(underTest).isEqualTo(underTest); | |||
assertThat(underTest).isEqualTo(new CeTask.Component(uuid, key, name)); | |||
assertThat(underTest).isNotEqualTo(null); | |||
assertThat(underTest).isNotEqualTo(new Object()); | |||
assertThat(underTest).isNotEqualTo(new CeTask.Component(somethingElse, key, name)); | |||
assertThat(underTest).isNotEqualTo(new CeTask.Component(uuid, somethingElse, name)); | |||
assertThat(underTest).isNotEqualTo(new CeTask.Component(uuid, key, somethingElse)); | |||
assertThat(underTest).isNotEqualTo(new CeTask.Component(uuid, key, null)); | |||
} | |||
@Test | |||
public void hashcode_is_based_on_all_fields() { | |||
String uuid = randomAlphabetic(2); | |||
String key = randomAlphabetic(3); | |||
String name = randomAlphabetic(4); | |||
String somethingElse = randomAlphabetic(5); | |||
CeTask.Component underTest = new CeTask.Component(uuid, key, name); | |||
assertThat(underTest.hashCode()).isEqualTo(underTest.hashCode()); | |||
assertThat(underTest.hashCode()).isEqualTo(new CeTask.Component(uuid, key, name).hashCode()); | |||
assertThat(underTest.hashCode()).isNotEqualTo(new Object().hashCode()); | |||
assertThat(underTest.hashCode()).isNotEqualTo(new CeTask.Component(somethingElse, key, name).hashCode()); | |||
assertThat(underTest.hashCode()).isNotEqualTo(new CeTask.Component(uuid, somethingElse, name).hashCode()); | |||
assertThat(underTest.hashCode()).isNotEqualTo(new CeTask.Component(uuid, key, somethingElse).hashCode()); | |||
assertThat(underTest.hashCode()).isNotEqualTo(new CeTask.Component(uuid, key, null).hashCode()); | |||
} | |||
@DataProvider | |||
public static Object[][] nullOrEmpty() { | |||
return new Object[][] { | |||
{null}, | |||
{""}, | |||
}; | |||
} | |||
} |
@@ -20,13 +20,18 @@ | |||
package org.sonar.ce.task; | |||
import com.google.common.collect.ImmutableMap; | |||
import com.tngtech.java.junit.dataprovider.DataProvider; | |||
import com.tngtech.java.junit.dataprovider.DataProviderRunner; | |||
import com.tngtech.java.junit.dataprovider.UseDataProvider; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.junit.runner.RunWith; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.entry; | |||
@RunWith(DataProviderRunner.class) | |||
public class CeTaskTest { | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
@@ -91,15 +96,40 @@ public class CeTaskTest { | |||
underTest.build(); | |||
} | |||
@Test | |||
@UseDataProvider("oneAndOnlyOneOfComponentAndMainComponent") | |||
public void build_fails_with_IAE_if_only_one_of_component_and_main_component_is_non_null(CeTask.Component component, CeTask.Component mainComponent) { | |||
underTest.setOrganizationUuid("org1"); | |||
underTest.setType("TYPE_1"); | |||
underTest.setUuid("UUID_1"); | |||
underTest.setComponent(component); | |||
underTest.setMainComponent(mainComponent); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("None or both component and main component must be non null"); | |||
underTest.build(); | |||
} | |||
@DataProvider | |||
public static Object[][] oneAndOnlyOneOfComponentAndMainComponent() { | |||
CeTask.Component component = new CeTask.Component("COMPONENT_UUID_1", "COMPONENT_KEY_1", "The component"); | |||
return new Object[][] { | |||
{component, null}, | |||
{null, component} | |||
}; | |||
} | |||
@Test | |||
public void verify_getters() { | |||
CeTask.Component component = new CeTask.Component("COMPONENT_UUID_1", "COMPONENT_KEY_1", "The component"); | |||
CeTask.Component mainComponent = new CeTask.Component("MAIN_COMPONENT_UUID_1", "MAIN_COMPONENT_KEY_1", "The main component"); | |||
underTest.setOrganizationUuid("org1"); | |||
underTest.setType("TYPE_1"); | |||
underTest.setUuid("UUID_1"); | |||
underTest.setSubmitterUuid("LOGIN_1"); | |||
underTest.setComponentKey("COMPONENT_KEY_1"); | |||
underTest.setComponentUuid("COMPONENT_UUID_1"); | |||
underTest.setComponentName("The component"); | |||
underTest.setComponent(component); | |||
underTest.setMainComponent(mainComponent); | |||
underTest.setCharacteristics(ImmutableMap.of("k1", "v1", "k2", "v2")); | |||
CeTask task = underTest.build(); | |||
@@ -108,25 +138,11 @@ public class CeTaskTest { | |||
assertThat(task.getUuid()).isEqualTo("UUID_1"); | |||
assertThat(task.getType()).isEqualTo("TYPE_1"); | |||
assertThat(task.getSubmitterUuid()).isEqualTo("LOGIN_1"); | |||
assertThat(task.getComponentKey()).isEqualTo("COMPONENT_KEY_1"); | |||
assertThat(task.getComponentUuid()).isEqualTo("COMPONENT_UUID_1"); | |||
assertThat(task.getComponentName()).isEqualTo("The component"); | |||
assertThat(task.getComponent()).contains(component); | |||
assertThat(task.getMainComponent()).contains(mainComponent); | |||
assertThat(task.getCharacteristics()).containsExactly(entry("k1", "v1"), entry("k2", "v2")); | |||
} | |||
@Test | |||
public void empty_in_component_properties_is_considered_as_null() { | |||
CeTask ceTask = underTest.setOrganizationUuid("org1").setUuid("uuid").setType("type") | |||
.setComponentKey("") | |||
.setComponentName("") | |||
.setComponentUuid("") | |||
.build(); | |||
assertThat(ceTask.getComponentKey()).isNull(); | |||
assertThat(ceTask.getComponentName()).isNull(); | |||
assertThat(ceTask.getComponentUuid()).isNull(); | |||
} | |||
@Test | |||
public void empty_in_submitterLogin_is_considered_as_null() { | |||
CeTask ceTask = underTest.setOrganizationUuid("org1").setUuid("uuid").setType("type") |
@@ -64,7 +64,7 @@ public class ReportAnalysisFailureNotificationExecutionListener implements CeWor | |||
if (status == CeActivityDto.Status.SUCCESS) { | |||
return; | |||
} | |||
String projectUuid = ceTask.getComponentUuid(); | |||
String projectUuid = ceTask.getComponent().map(CeTask.Component::getUuid).orElse(null); | |||
if (!CeTaskTypes.REPORT.equals(ceTask.getType()) || projectUuid == null) { | |||
return; | |||
} |
@@ -53,6 +53,7 @@ import static com.google.common.base.Preconditions.checkArgument; | |||
import static java.lang.String.format; | |||
import static java.util.Collections.singletonList; | |||
import static java.util.Objects.requireNonNull; | |||
import static java.util.Optional.ofNullable; | |||
import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex; | |||
@ComputeEngineSide | |||
@@ -90,15 +91,13 @@ public class InternalCeQueueImpl extends CeQueueImpl implements InternalCeQueue | |||
Optional<CeQueueDto> opt = ceQueueDao.peek(dbSession, workerUuid); | |||
if (opt.isPresent()) { | |||
CeQueueDto taskDto = opt.get(); | |||
ComponentDto component = null; | |||
String componentUuid = taskDto.getComponentUuid(); | |||
if (componentUuid != null) { | |||
component = dbClient.componentDao().selectByUuid(dbSession, componentUuid).orElse(null); | |||
} | |||
Map<String, ComponentDto> componentsByUuid = loadComponentDtos(dbSession, taskDto); | |||
Map<String, String> characteristics = dbClient.ceTaskCharacteristicsDao().selectByTaskUuids(dbSession, singletonList(taskDto.getUuid())).stream() | |||
.collect(uniqueIndex(CeTaskCharacteristicDto::getKey, CeTaskCharacteristicDto::getValue)); | |||
CeTask task = convertToTask(taskDto, characteristics, component); | |||
CeTask task = convertToTask(taskDto, characteristics, | |||
ofNullable(taskDto.getComponentUuid()).map(componentsByUuid::get).orElse(null), | |||
ofNullable(taskDto.getMainComponentUuid()).map(componentsByUuid::get).orElse(null)); | |||
queueStatus.addInProgress(); | |||
return Optional.of(task); | |||
} |
@@ -180,7 +180,7 @@ public class CeWorkerImpl implements CeWorker { | |||
private static Profiler startLogProfiler(CeTask task) { | |||
Profiler profiler = Profiler.create(LOG) | |||
.logTimeLast(true) | |||
.addContext("project", task.getComponentKey()) | |||
.addContext("project", task.getMainComponent().flatMap(CeTask.Component::getKey).orElse(null)) | |||
.addContext("type", task.getType()); | |||
for (Map.Entry<String, String> characteristic : task.getCharacteristics().entrySet()) { | |||
profiler.addContext(characteristic.getKey(), characteristic.getValue()); |
@@ -20,6 +20,7 @@ | |||
package org.sonar.ce.notification; | |||
import java.util.Arrays; | |||
import java.util.Optional; | |||
import java.util.Random; | |||
import javax.annotation.Nullable; | |||
import org.junit.Before; | |||
@@ -121,7 +122,7 @@ public class ReportAnalysisFailureNotificationExecutionListenerTest { | |||
public void onEnd_has_no_effect_if_there_is_no_subscriber_for_ReportAnalysisFailureNotification_type() { | |||
String componentUuid = randomAlphanumeric(6); | |||
when(ceTaskMock.getType()).thenReturn(CeTaskTypes.REPORT); | |||
when(ceTaskMock.getComponentUuid()).thenReturn(componentUuid); | |||
when(ceTaskMock.getComponent()).thenReturn(Optional.of(new CeTask.Component(componentUuid, null, null))); | |||
when(notificationService.hasProjectSubscribersForTypes(componentUuid, singleton(ReportAnalysisFailureNotification.TYPE))) | |||
.thenReturn(false); | |||
@@ -134,7 +135,7 @@ public class ReportAnalysisFailureNotificationExecutionListenerTest { | |||
public void onEnd_fails_with_RowNotFoundException_if_component_does_not_exist_in_DB() { | |||
String componentUuid = randomAlphanumeric(6); | |||
when(ceTaskMock.getType()).thenReturn(CeTaskTypes.REPORT); | |||
when(ceTaskMock.getComponentUuid()).thenReturn(componentUuid); | |||
when(ceTaskMock.getComponent()).thenReturn(Optional.of(new CeTask.Component(componentUuid, null, null))); | |||
when(notificationService.hasProjectSubscribersForTypes(componentUuid, singleton(ReportAnalysisFailureNotification.TYPE))) | |||
.thenReturn(true); | |||
@@ -160,7 +161,7 @@ public class ReportAnalysisFailureNotificationExecutionListenerTest { | |||
Arrays.asList(module, directory, file, view, subView, projectCopy, application) | |||
.forEach(component -> { | |||
try { | |||
when(ceTaskMock.getComponentUuid()).thenReturn(component.uuid()); | |||
when(ceTaskMock.getComponent()).thenReturn(Optional.of(new CeTask.Component(component.uuid(), null, null))); | |||
when(notificationService.hasProjectSubscribersForTypes(component.uuid(), singleton(ReportAnalysisFailureNotification.TYPE))) | |||
.thenReturn(true); | |||
@@ -180,7 +181,7 @@ public class ReportAnalysisFailureNotificationExecutionListenerTest { | |||
String taskUuid = randomAlphanumeric(6); | |||
when(ceTaskMock.getType()).thenReturn(CeTaskTypes.REPORT); | |||
when(ceTaskMock.getUuid()).thenReturn(taskUuid); | |||
when(ceTaskMock.getComponentUuid()).thenReturn(componentUuid); | |||
when(ceTaskMock.getComponent()).thenReturn(Optional.of(new CeTask.Component(componentUuid, null, null))); | |||
when(notificationService.hasProjectSubscribersForTypes(componentUuid, singleton(ReportAnalysisFailureNotification.TYPE))) | |||
.thenReturn(true); | |||
dbTester.components().insertPrivateProject(s -> s.setUuid(componentUuid)); | |||
@@ -293,7 +294,7 @@ public class ReportAnalysisFailureNotificationExecutionListenerTest { | |||
private ComponentDto initMocksToPassConditions(String taskUuid, int createdAt, @Nullable Long executedAt) { | |||
ComponentDto project = random.nextBoolean() ? dbTester.components().insertPrivateProject() : dbTester.components().insertPublicProject(); | |||
when(ceTaskMock.getType()).thenReturn(CeTaskTypes.REPORT); | |||
when(ceTaskMock.getComponentUuid()).thenReturn(project.uuid()); | |||
when(ceTaskMock.getComponent()).thenReturn(Optional.of(new CeTask.Component(project.uuid(), null, null))); | |||
when(ceTaskMock.getUuid()).thenReturn(taskUuid); | |||
when(notificationService.hasProjectSubscribersForTypes(project.uuid(), singleton(ReportAnalysisFailureNotification.TYPE))) | |||
.thenReturn(true); |
@@ -99,7 +99,7 @@ public class InternalCeQueueImplTest { | |||
@Test | |||
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, newProjectDto("PROJECT_1"), "rob"); | |||
CeTask task = underTest.submit(taskSubmit); | |||
verifyCeTask(taskSubmit, task, null); | |||
@@ -108,8 +108,8 @@ public class InternalCeQueueImplTest { | |||
@Test | |||
public void submit_populates_component_name_and_key_of_CeTask_if_component_exists() { | |||
ComponentDto componentDto = insertComponent(newComponentDto("PROJECT_1")); | |||
CeTaskSubmit taskSubmit = createTaskSubmit(CeTaskTypes.REPORT, componentDto.uuid(), null); | |||
ComponentDto componentDto = insertComponent(newProjectDto("PROJECT_1")); | |||
CeTaskSubmit taskSubmit = createTaskSubmit(CeTaskTypes.REPORT, componentDto, null); | |||
CeTask task = underTest.submit(taskSubmit); | |||
@@ -127,7 +127,7 @@ public class InternalCeQueueImplTest { | |||
@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 taskSubmit1 = createTaskSubmit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1"), "rob"); | |||
CeTaskSubmit taskSubmit2 = createTaskSubmit("some type"); | |||
List<CeTask> tasks = underTest.massSubmit(asList(taskSubmit1, taskSubmit2)); | |||
@@ -141,9 +141,9 @@ public class InternalCeQueueImplTest { | |||
@Test | |||
public void massSubmit_populates_component_name_and_key_of_CeTask_if_component_exists() { | |||
ComponentDto componentDto1 = insertComponent(newComponentDto("PROJECT_1")); | |||
CeTaskSubmit taskSubmit1 = createTaskSubmit(CeTaskTypes.REPORT, componentDto1.uuid(), null); | |||
CeTaskSubmit taskSubmit2 = createTaskSubmit("something", "non existing component uuid", null); | |||
ComponentDto componentDto1 = insertComponent(newProjectDto("PROJECT_1")); | |||
CeTaskSubmit taskSubmit1 = createTaskSubmit(CeTaskTypes.REPORT, componentDto1, null); | |||
CeTaskSubmit taskSubmit2 = createTaskSubmit("something", newProjectDto("non existing component uuid"), null); | |||
List<CeTask> tasks = underTest.massSubmit(asList(taskSubmit1, taskSubmit2)); | |||
@@ -162,7 +162,7 @@ public class InternalCeQueueImplTest { | |||
@Test | |||
public void test_remove() { | |||
CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1"); | |||
CeTask task = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1")); | |||
Optional<CeTask> peek = underTest.peek(WORKER_UUID_1); | |||
underTest.remove(peek.get(), CeActivityDto.Status.SUCCESS, null, null); | |||
@@ -196,7 +196,7 @@ public class InternalCeQueueImplTest { | |||
@Test | |||
public void remove_does_not_set_analysisUuid_in_CeActivity_when_CeTaskResult_has_no_analysis_uuid() { | |||
CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1"); | |||
CeTask task = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1")); | |||
Optional<CeTask> peek = underTest.peek(WORKER_UUID_1); | |||
underTest.remove(peek.get(), CeActivityDto.Status.SUCCESS, newTaskResult(null), null); | |||
@@ -208,7 +208,7 @@ public class InternalCeQueueImplTest { | |||
@Test | |||
public void remove_sets_analysisUuid_in_CeActivity_when_CeTaskResult_has_analysis_uuid() { | |||
CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1"); | |||
CeTask task = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1")); | |||
Optional<CeTask> peek = underTest.peek(WORKER_UUID_2); | |||
underTest.remove(peek.get(), CeActivityDto.Status.SUCCESS, newTaskResult(AN_ANALYSIS_UUID), null); | |||
@@ -223,7 +223,7 @@ public class InternalCeQueueImplTest { | |||
public void remove_saves_error_message_and_stacktrace_when_exception_is_provided() { | |||
Throwable error = new NullPointerException("Fake NPE to test persistence to DB"); | |||
CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1"); | |||
CeTask task = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1")); | |||
Optional<CeTask> peek = underTest.peek(WORKER_UUID_1); | |||
underTest.remove(peek.get(), CeActivityDto.Status.FAILED, null, error); | |||
@@ -239,7 +239,7 @@ public class InternalCeQueueImplTest { | |||
public void remove_saves_error_when_TypedMessageException_is_provided() { | |||
Throwable error = new TypedExceptionImpl("aType", "aMessage"); | |||
CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1"); | |||
CeTask task = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1")); | |||
Optional<CeTask> peek = underTest.peek(WORKER_UUID_1); | |||
underTest.remove(peek.get(), CeActivityDto.Status.FAILED, null, error); | |||
@@ -253,7 +253,7 @@ public class InternalCeQueueImplTest { | |||
public void remove_updates_queueStatus_success_even_if_task_does_not_exist_in_DB() { | |||
CEQueueStatus queueStatus = mock(CEQueueStatus.class); | |||
CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1"); | |||
CeTask task = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1")); | |||
db.getDbClient().ceQueueDao().deleteByUuid(db.getSession(), task.getUuid()); | |||
db.commit(); | |||
@@ -271,7 +271,7 @@ public class InternalCeQueueImplTest { | |||
public void remove_updates_queueStatus_failure_even_if_task_does_not_exist_in_DB() { | |||
CEQueueStatus queueStatusMock = mock(CEQueueStatus.class); | |||
CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1"); | |||
CeTask task = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1")); | |||
db.getDbClient().ceQueueDao().deleteByUuid(db.getSession(), task.getUuid()); | |||
db.commit(); | |||
InternalCeQueueImpl underTest = new InternalCeQueueImpl(system2, db.getDbClient(), null, queueStatusMock, null, null); | |||
@@ -288,7 +288,7 @@ public class InternalCeQueueImplTest { | |||
public void cancelWornOuts_does_not_update_queueStatus() { | |||
CEQueueStatus queueStatusMock = mock(CEQueueStatus.class); | |||
CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1"); | |||
CeTask task = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1")); | |||
db.executeUpdateSql("update ce_queue set status = 'PENDING', started_at = 123 where uuid = '" + task.getUuid() + "'"); | |||
db.commit(); | |||
InternalCeQueueImpl underTest = new InternalCeQueueImpl(system2, db.getDbClient(), null, queueStatusMock, null, null); | |||
@@ -334,7 +334,7 @@ public class InternalCeQueueImplTest { | |||
@Test | |||
public void fail_to_remove_if_not_in_queue() { | |||
CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1"); | |||
CeTask task = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1")); | |||
underTest.remove(task, CeActivityDto.Status.SUCCESS, null, null); | |||
expectedException.expect(IllegalStateException.class); | |||
@@ -344,13 +344,32 @@ public class InternalCeQueueImplTest { | |||
@Test | |||
public void test_peek() { | |||
CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1"); | |||
CeTask task = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1")); | |||
Optional<CeTask> peek = underTest.peek(WORKER_UUID_1); | |||
assertThat(peek.isPresent()).isTrue(); | |||
assertThat(peek.get().getUuid()).isEqualTo(task.getUuid()); | |||
assertThat(peek.get().getType()).isEqualTo(CeTaskTypes.REPORT); | |||
assertThat(peek.get().getComponentUuid()).isEqualTo("PROJECT_1"); | |||
assertThat(peek.get().getComponent()).contains(new CeTask.Component("PROJECT_1", null, null)); | |||
assertThat(peek.get().getMainComponent()).contains(peek.get().getComponent().get()); | |||
// no more pending tasks | |||
peek = underTest.peek(WORKER_UUID_2); | |||
assertThat(peek.isPresent()).isFalse(); | |||
} | |||
@Test | |||
public void peek_populates_name_and_key_for_existing_component_and_main_component() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
ComponentDto branch = db.components().insertProjectBranch(project); | |||
CeTask task = submit(CeTaskTypes.REPORT, branch); | |||
Optional<CeTask> peek = underTest.peek(WORKER_UUID_1); | |||
assertThat(peek.isPresent()).isTrue(); | |||
assertThat(peek.get().getUuid()).isEqualTo(task.getUuid()); | |||
assertThat(peek.get().getType()).isEqualTo(CeTaskTypes.REPORT); | |||
assertThat(peek.get().getComponent()).contains(new CeTask.Component(branch.uuid(), branch.getDbKey(), branch.name())); | |||
assertThat(peek.get().getMainComponent()).contains(new CeTask.Component(project.uuid(), project.getDbKey(), project.name())); | |||
// no more pending tasks | |||
peek = underTest.peek(WORKER_UUID_2); | |||
@@ -359,7 +378,7 @@ public class InternalCeQueueImplTest { | |||
@Test | |||
public void peek_is_paused_then_resumed() { | |||
CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1"); | |||
CeTask task = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1")); | |||
underTest.pauseWorkers(); | |||
Optional<CeTask> peek = underTest.peek(WORKER_UUID_1); | |||
@@ -385,7 +404,7 @@ public class InternalCeQueueImplTest { | |||
@Test | |||
public void peek_nothing_if_application_status_stopping() { | |||
submit(CeTaskTypes.REPORT, "PROJECT_1"); | |||
submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1")); | |||
when(computeEngineStatus.getStatus()).thenReturn(STOPPING); | |||
Optional<CeTask> peek = underTest.peek(WORKER_UUID_1); | |||
@@ -468,7 +487,7 @@ public class InternalCeQueueImplTest { | |||
@Test | |||
public void cancel_pending() { | |||
CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1"); | |||
CeTask task = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1")); | |||
CeQueueDto queueDto = db.getDbClient().ceQueueDao().selectByUuid(db.getSession(), task.getUuid()).get(); | |||
underTest.cancel(db.getSession(), queueDto); | |||
@@ -480,7 +499,7 @@ public class InternalCeQueueImplTest { | |||
@Test | |||
public void fail_to_cancel_if_in_progress() { | |||
CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1"); | |||
CeTask task = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1")); | |||
underTest.peek(WORKER_UUID_2); | |||
CeQueueDto queueDto = db.getDbClient().ceQueueDao().selectByUuid(db.getSession(), task.getUuid()).get(); | |||
@@ -492,9 +511,9 @@ public class InternalCeQueueImplTest { | |||
@Test | |||
public void cancelAll_pendings_but_not_in_progress() { | |||
CeTask inProgressTask = submit(CeTaskTypes.REPORT, "PROJECT_1"); | |||
CeTask pendingTask1 = submit(CeTaskTypes.REPORT, "PROJECT_2"); | |||
CeTask pendingTask2 = submit(CeTaskTypes.REPORT, "PROJECT_3"); | |||
CeTask inProgressTask = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_1")); | |||
CeTask pendingTask1 = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_2")); | |||
CeTask pendingTask2 = submit(CeTaskTypes.REPORT, newProjectDto("PROJECT_3")); | |||
underTest.peek(WORKER_UUID_2); | |||
int canceledCount = underTest.cancelAll(); | |||
@@ -608,14 +627,16 @@ public class InternalCeQueueImplTest { | |||
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(); | |||
if (componentDto != null) { | |||
CeTask.Component component = task.getComponent().get(); | |||
assertThat(component.getUuid()).isEqualTo(componentDto.uuid()); | |||
assertThat(component.getKey()).contains(componentDto.getDbKey()); | |||
assertThat(component.getName()).contains(componentDto.name()); | |||
} else if (taskSubmit.getComponent().isPresent()) { | |||
assertThat(task.getComponent()).contains(new CeTask.Component(taskSubmit.getComponent().get().getUuid(), null, null)); | |||
} else { | |||
assertThat(task.getComponentKey()).isEqualTo(componentDto.getDbKey()); | |||
assertThat(task.getComponentName()).isEqualTo(componentDto.name()); | |||
assertThat(task.getComponent()).isEmpty(); | |||
} | |||
assertThat(task.getSubmitterUuid()).isEqualTo(taskSubmit.getSubmitterUuid()); | |||
} | |||
@@ -625,30 +646,39 @@ public class InternalCeQueueImplTest { | |||
assertThat(queueDto.isPresent()).isTrue(); | |||
CeQueueDto dto = queueDto.get(); | |||
assertThat(dto.getTaskType()).isEqualTo(taskSubmit.getType()); | |||
assertThat(dto.getComponentUuid()).isEqualTo(taskSubmit.getComponentUuid()); | |||
Optional<CeTaskSubmit.Component> component = taskSubmit.getComponent(); | |||
if (component.isPresent()) { | |||
assertThat(dto.getMainComponentUuid()).isEqualTo(component.get().getMainComponentUuid()); | |||
assertThat(dto.getComponentUuid()).isEqualTo(component.get().getUuid()); | |||
} else { | |||
assertThat(dto.getMainComponentUuid()).isNull(); | |||
assertThat(dto.getComponentUuid()).isNull(); | |||
} | |||
assertThat(dto.getSubmitterUuid()).isEqualTo(taskSubmit.getSubmitterUuid()); | |||
assertThat(dto.getCreatedAt()).isEqualTo(dto.getUpdatedAt()).isNotNull(); | |||
} | |||
private ComponentDto newComponentDto(String uuid) { | |||
private ComponentDto newProjectDto(String uuid) { | |||
return ComponentTesting.newPublicProjectDto(db.getDefaultOrganization(), uuid).setName("name_" + uuid).setDbKey("key_" + uuid); | |||
} | |||
private CeTask submit(String reportType, String componentUuid) { | |||
return underTest.submit(createTaskSubmit(reportType, componentUuid, null)); | |||
private CeTask submit(String reportType, ComponentDto componentDto) { | |||
return underTest.submit(createTaskSubmit(reportType, componentDto, null)); | |||
} | |||
private CeTaskSubmit createTaskSubmit(String type) { | |||
return createTaskSubmit(type, null, null); | |||
} | |||
private CeTaskSubmit createTaskSubmit(String type, @Nullable String componentUuid, @Nullable String submitterUuid) { | |||
return underTest.prepareSubmit() | |||
private CeTaskSubmit createTaskSubmit(String type, @Nullable ComponentDto componentDto, @Nullable String submitterUuid) { | |||
CeTaskSubmit.Builder builder = underTest.prepareSubmit() | |||
.setType(type) | |||
.setComponentUuid(componentUuid) | |||
.setSubmitterUuid(submitterUuid) | |||
.setCharacteristics(emptyMap()) | |||
.build(); | |||
.setCharacteristics(emptyMap()); | |||
if (componentDto != null) { | |||
builder.setComponent(CeTaskSubmit.Component.fromDto(componentDto)); | |||
} | |||
return builder.build(); | |||
} | |||
private CeTaskResult newTaskResult(@Nullable String analysisUuid) { |
@@ -107,13 +107,13 @@ public class CeTaskProcessorRepositoryImplTest { | |||
} | |||
private static CeTask createCeTask(String ceTaskType, String key) { | |||
CeTask.Component component = new CeTask.Component("uuid_" + key, key, "name_" + key); | |||
return new CeTask.Builder() | |||
.setOrganizationUuid("org1") | |||
.setType(ceTaskType) | |||
.setUuid("task_uuid_" + key) | |||
.setComponentKey(key) | |||
.setComponentUuid("uuid_" + key) | |||
.setComponentName("name_" + key) | |||
.setComponent(component) | |||
.setMainComponent(component) | |||
.build(); | |||
} | |||
@@ -554,10 +554,12 @@ public class CeWorkerImplTest { | |||
for (int i = 0; i < characteristics.length; i += 2) { | |||
characteristicMap.put(characteristics[i], characteristics[i + 1]); | |||
} | |||
CeTask.Component component = new CeTask.Component("PROJECT_1", null, null); | |||
return new CeTask.Builder() | |||
.setOrganizationUuid("org1") | |||
.setUuid("TASK_1").setType(CeTaskTypes.REPORT) | |||
.setComponentUuid("PROJECT_1") | |||
.setComponent(component) | |||
.setMainComponent(component) | |||
.setSubmitterUuid(submitterLogin) | |||
.setCharacteristics(characteristicMap) | |||
.build(); |
@@ -669,6 +669,8 @@ CREATE TABLE "CE_QUEUE" ( | |||
"UUID" VARCHAR(40) NOT NULL, | |||
"TASK_TYPE" VARCHAR(15) NOT NULL, | |||
"COMPONENT_UUID" VARCHAR(40) NULL, | |||
"TMP_COMPONENT_UUID" VARCHAR(40) NULL, | |||
"TMP_MAIN_COMPONENT_UUID" VARCHAR(40) NULL, | |||
"STATUS" VARCHAR(15) NOT NULL, | |||
"SUBMITTER_UUID" VARCHAR(255) NULL, | |||
"WORKER_UUID" VARCHAR(40) NULL, | |||
@@ -679,6 +681,8 @@ CREATE TABLE "CE_QUEUE" ( | |||
); | |||
CREATE UNIQUE INDEX "CE_QUEUE_UUID" ON "CE_QUEUE" ("UUID"); | |||
CREATE INDEX "CE_QUEUE_COMPONENT_UUID" ON "CE_QUEUE" ("COMPONENT_UUID"); | |||
CREATE INDEX "CE_QUEUE_TMP_CPNT_UUID" ON "CE_QUEUE" ("TMP_COMPONENT_UUID"); | |||
CREATE INDEX "CE_QUEUE_TMP_MAIN_CPNT_UUID" ON "CE_QUEUE" ("TMP_MAIN_COMPONENT_UUID"); | |||
CREATE INDEX "CE_QUEUE_STATUS" ON "CE_QUEUE" ("STATUS"); | |||
@@ -687,10 +691,16 @@ CREATE TABLE "CE_ACTIVITY" ( | |||
"UUID" VARCHAR(40) NOT NULL, | |||
"TASK_TYPE" VARCHAR(15) NOT NULL, | |||
"COMPONENT_UUID" VARCHAR(40) NULL, | |||
"TMP_COMPONENT_UUID" VARCHAR(40) NULL, | |||
"TMP_MAIN_COMPONENT_UUID" VARCHAR(40) NULL, | |||
"ANALYSIS_UUID" VARCHAR(50) NULL, | |||
"STATUS" VARCHAR(15) NOT NULL, | |||
"IS_LAST" BOOLEAN NOT NULL, | |||
"IS_LAST_KEY" VARCHAR(55) NOT NULL, | |||
"TMP_IS_LAST" BOOLEAN, | |||
"TMP_IS_LAST_KEY" VARCHAR(55), | |||
"TMP_MAIN_IS_LAST" BOOLEAN, | |||
"TMP_MAIN_IS_LAST_KEY" VARCHAR(55), | |||
"SUBMITTER_UUID" VARCHAR(255) NULL, | |||
"WORKER_UUID" VARCHAR(40) NULL, | |||
"EXECUTION_COUNT" INTEGER NOT NULL, | |||
@@ -706,8 +716,14 @@ CREATE TABLE "CE_ACTIVITY" ( | |||
); | |||
CREATE UNIQUE INDEX "CE_ACTIVITY_UUID" ON "CE_ACTIVITY" ("UUID"); | |||
CREATE INDEX "CE_ACTIVITY_COMPONENT_UUID" ON "CE_ACTIVITY" ("COMPONENT_UUID"); | |||
CREATE INDEX "CE_ACTIVITY_TMP_CPNT_UUID" ON "CE_ACTIVITY" ("TMP_COMPONENT_UUID"); | |||
CREATE INDEX "CE_ACTIVITY_TMP_MAIN_CPNT_UUID" ON "CE_ACTIVITY" ("TMP_MAIN_COMPONENT_UUID"); | |||
CREATE INDEX "CE_ACTIVITY_ISLASTKEY" ON "CE_ACTIVITY" ("IS_LAST_KEY"); | |||
CREATE INDEX "CE_ACTIVITY_ISLAST_STATUS" ON "CE_ACTIVITY" ("IS_LAST", "STATUS"); | |||
CREATE INDEX "CE_ACTIVITY_T_ISLAST_KEY" ON "CE_ACTIVITY" ("TMP_IS_LAST_KEY"); | |||
CREATE INDEX "CE_ACTIVITY_T_ISLAST" ON "CE_ACTIVITY" ("TMP_IS_LAST", "STATUS"); | |||
CREATE INDEX "CE_ACTIVITY_T_MAIN_ISLAST_KEY" ON "CE_ACTIVITY" ("TMP_MAIN_IS_LAST_KEY"); | |||
CREATE INDEX "CE_ACTIVITY_T_MAIN_ISLAST" ON "CE_ACTIVITY" ("TMP_MAIN_IS_LAST", "STATUS"); | |||
CREATE TABLE "CE_TASK_CHARACTERISTICS" ( |
@@ -46,11 +46,12 @@ public class CeActivityDao implements Dao { | |||
public void insert(DbSession dbSession, CeActivityDto dto) { | |||
dto.setCreatedAt(system2.now()); | |||
dto.setUpdatedAt(system2.now()); | |||
dto.setIsLast(dto.getStatus() != CeActivityDto.Status.CANCELED); | |||
boolean isLast = dto.getStatus() != CeActivityDto.Status.CANCELED; | |||
dto.setIsLast(isLast); | |||
CeActivityMapper ceActivityMapper = mapper(dbSession); | |||
if (dto.getIsLast()) { | |||
ceActivityMapper.updateIsLastToFalseForLastKey(dto.getIsLastKey(), dto.getUpdatedAt()); | |||
if (isLast) { | |||
ceActivityMapper.clearIsLast(dto.getIsLastKey(), dto.getMainIsLastKey(), dto.getUpdatedAt()); | |||
} | |||
ceActivityMapper.insert(dto); | |||
} | |||
@@ -67,15 +68,15 @@ public class CeActivityDao implements Dao { | |||
* Ordered by id desc -> newest to oldest | |||
*/ | |||
public List<CeActivityDto> selectByQuery(DbSession dbSession, CeTaskQuery query, Pagination pagination) { | |||
if (query.isShortCircuitedByComponentUuids()) { | |||
if (query.isShortCircuitedByMainComponentUuids()) { | |||
return Collections.emptyList(); | |||
} | |||
return mapper(dbSession).selectByQuery(query, pagination); | |||
} | |||
public int countLastByStatusAndComponentUuid(DbSession dbSession, CeActivityDto.Status status, @Nullable String componentUuid) { | |||
return mapper(dbSession).countLastByStatusAndComponentUuid(status, componentUuid); | |||
public int countLastByStatusAndMainComponentUuid(DbSession dbSession, CeActivityDto.Status status, @Nullable String mainComponentUuid) { | |||
return mapper(dbSession).countLastByStatusAndMainComponentUuid(status, mainComponentUuid); | |||
} | |||
private static CeActivityMapper mapper(DbSession dbSession) { |
@@ -23,6 +23,7 @@ import com.google.common.base.Strings; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.component.ComponentDto; | |||
import static com.google.common.base.Preconditions.checkArgument; | |||
import static java.lang.String.format; | |||
@@ -36,12 +37,28 @@ public class CeActivityDto { | |||
} | |||
private String uuid; | |||
/** | |||
* Can be {@code null} when task is not associated to any data in table PROJECTS, but must always be non {@code null} | |||
* at the same time as {@link #mainComponentUuid}. | |||
* <p> | |||
* The component uuid of a any component (project or not) is its own UUID. | |||
*/ | |||
private String componentUuid; | |||
/** | |||
* Can be {@code null} when task is not associated to any data in table PROJECTS, but must always be non {@code null} | |||
* at the same time as {@link #componentUuid}. | |||
* <p> | |||
* The main component uuid of the main branch of project is its own UUID. For other branches of a project, it is the | |||
* project UUID of the main branch of that project ({@link ComponentDto#getMainBranchProjectUuid()}). | |||
*/ | |||
private String mainComponentUuid; | |||
private String analysisUuid; | |||
private Status status; | |||
private String taskType; | |||
private boolean isLast; | |||
private String isLastKey; | |||
private boolean mainIsLast; | |||
private String mainIsLastKey; | |||
private String submitterUuid; | |||
private String workerUuid; | |||
private long submittedAt; | |||
@@ -91,7 +108,9 @@ public class CeActivityDto { | |||
this.uuid = queueDto.getUuid(); | |||
this.taskType = queueDto.getTaskType(); | |||
this.componentUuid = queueDto.getComponentUuid(); | |||
this.mainComponentUuid = queueDto.getMainComponentUuid(); | |||
this.isLastKey = format("%s%s", taskType, Strings.nullToEmpty(componentUuid)); | |||
this.mainIsLastKey = format("%s%s", taskType, Strings.nullToEmpty(mainComponentUuid)); | |||
this.submitterUuid = queueDto.getSubmitterUuid(); | |||
this.workerUuid = queueDto.getWorkerUuid(); | |||
this.submittedAt = queueDto.getCreatedAt(); | |||
@@ -102,8 +121,8 @@ public class CeActivityDto { | |||
return uuid; | |||
} | |||
public CeActivityDto setUuid(String s) { | |||
checkArgument(s.length() <= 40, "Value is too long for column CE_ACTIVITY.UUID: %s", s); | |||
public CeActivityDto setUuid(@Nullable String s) { | |||
validateUuid(s, "UUID"); | |||
this.uuid = s; | |||
return this; | |||
} | |||
@@ -123,11 +142,26 @@ public class CeActivityDto { | |||
} | |||
public CeActivityDto setComponentUuid(@Nullable String s) { | |||
checkArgument(s == null || s.length() <= 40, "Value is too long for column CE_ACTIVITY.COMPONENT_UUID: %s", s); | |||
validateUuid(s, "COMPONENT_UUID"); | |||
this.componentUuid = s; | |||
return this; | |||
} | |||
@CheckForNull | |||
public String getMainComponentUuid() { | |||
return mainComponentUuid; | |||
} | |||
public CeActivityDto setMainComponentUuid(@Nullable String s) { | |||
validateUuid(s, "MAIN_COMPONENT_UUID"); | |||
this.mainComponentUuid = s; | |||
return this; | |||
} | |||
private static void validateUuid(@Nullable String s, String columnName) { | |||
checkArgument(s == null || s.length() <= 40, "Value is too long for column CE_ACTIVITY.%s: %s", columnName, s); | |||
} | |||
public Status getStatus() { | |||
return status; | |||
} | |||
@@ -143,6 +177,7 @@ public class CeActivityDto { | |||
CeActivityDto setIsLast(boolean b) { | |||
this.isLast = b; | |||
this.mainIsLast = b; | |||
return this; | |||
} | |||
@@ -150,6 +185,14 @@ public class CeActivityDto { | |||
return isLastKey; | |||
} | |||
public boolean getMainIsLast() { | |||
return mainIsLast; | |||
} | |||
public String getMainIsLastKey() { | |||
return mainIsLastKey; | |||
} | |||
@CheckForNull | |||
public String getSubmitterUuid() { | |||
return submitterUuid; | |||
@@ -277,11 +320,14 @@ public class CeActivityDto { | |||
return "CeActivityDto{" + | |||
"uuid='" + uuid + '\'' + | |||
", componentUuid='" + componentUuid + '\'' + | |||
", mainComponentUuid='" + mainComponentUuid + '\'' + | |||
", analysisUuid='" + analysisUuid + '\'' + | |||
", status=" + status + | |||
", taskType='" + taskType + '\'' + | |||
", isLast=" + isLast + | |||
", isLastKey='" + isLastKey + '\'' + | |||
", mainIsLast=" + mainIsLast + | |||
", mainIsLastKey='" + mainIsLastKey + '\'' + | |||
", submitterUuid='" + submitterUuid + '\'' + | |||
", workerUuid='" + workerUuid + '\'' + | |||
", submittedAt=" + submittedAt + |
@@ -30,17 +30,15 @@ public interface CeActivityMapper { | |||
@CheckForNull | |||
CeActivityDto selectByUuid(@Param("uuid") String uuid); | |||
List<CeActivityDto> selectByComponentUuid(@Param("componentUuid") String componentUuid); | |||
List<CeActivityDto> selectByQuery(@Param("query") CeTaskQuery query, @Param("pagination") Pagination pagination); | |||
List<CeActivityDto> selectOlderThan(@Param("beforeDate") long beforeDate); | |||
int countLastByStatusAndComponentUuid(@Param("status") CeActivityDto.Status status, @Nullable @Param("componentUuid") String componentUuid); | |||
int countLastByStatusAndMainComponentUuid(@Param("status") CeActivityDto.Status status, @Nullable @Param("mainComponentUuid") String mainComponentUuid); | |||
void insert(CeActivityDto dto); | |||
void updateIsLastToFalseForLastKey(@Param("isLastKey") String isLastKey, @Param("updatedAt") long updatedAt); | |||
void clearIsLast(@Param("isLastKey") String isLastKey, @Param("mainIsLastKey") String mainIsLastKey, @Param("updatedAt") long updatedAt); | |||
void deleteByUuids(@Param("uuids") List<String> uuids); | |||
} |
@@ -55,7 +55,7 @@ public class CeQueueDao implements Dao { | |||
} | |||
public List<CeQueueDto> selectByQueryInDescOrder(DbSession dbSession, CeTaskQuery query, int pageSize) { | |||
if (query.isShortCircuitedByComponentUuids() | |||
if (query.isShortCircuitedByMainComponentUuids() | |||
|| query.isOnlyCurrents() | |||
|| query.getMaxExecutedAt() != null) { | |||
return emptyList(); | |||
@@ -65,7 +65,7 @@ public class CeQueueDao implements Dao { | |||
} | |||
public int countByQuery(DbSession dbSession, CeTaskQuery query) { | |||
if (query.isShortCircuitedByComponentUuids() | |||
if (query.isShortCircuitedByMainComponentUuids() | |||
|| query.isOnlyCurrents() | |||
|| query.getMaxExecutedAt() != null) { | |||
return 0; | |||
@@ -77,8 +77,8 @@ public class CeQueueDao implements Dao { | |||
/** | |||
* Ordered by ascending id: oldest to newest | |||
*/ | |||
public List<CeQueueDto> selectByComponentUuid(DbSession session, String componentUuid) { | |||
return mapper(session).selectByComponentUuid(componentUuid); | |||
public List<CeQueueDto> selectByMainComponentUuid(DbSession session, String projectUuid) { | |||
return mapper(session).selectByMainComponentUuid(projectUuid); | |||
} | |||
public Optional<CeQueueDto> selectByUuid(DbSession session, String uuid) { | |||
@@ -131,30 +131,30 @@ public class CeQueueDao implements Dao { | |||
} | |||
public int countByStatus(DbSession dbSession, CeQueueDto.Status status) { | |||
return mapper(dbSession).countByStatusAndComponentUuid(status, null); | |||
return mapper(dbSession).countByStatusAndMainComponentUuid(status, null); | |||
} | |||
public int countByStatusAndComponentUuid(DbSession dbSession, CeQueueDto.Status status, @Nullable String componentUuid) { | |||
return mapper(dbSession).countByStatusAndComponentUuid(status, componentUuid); | |||
public int countByStatusAndMainComponentUuid(DbSession dbSession, CeQueueDto.Status status, @Nullable String mainComponentUuid) { | |||
return mapper(dbSession).countByStatusAndMainComponentUuid(status, mainComponentUuid); | |||
} | |||
/** | |||
* Counts entries in the queue with the specified status for each specified component uuid. | |||
* Counts entries in the queue with the specified status for each specified main component uuid. | |||
* | |||
* The returned map doesn't contain any entry for component uuid for which there is no entry in the queue (ie. | |||
* The returned map doesn't contain any entry for main component uuids for which there is no entry in the queue (ie. | |||
* all entries have a value >= 0). | |||
*/ | |||
public Map<String, Integer> countByStatusAndComponentUuids(DbSession dbSession, CeQueueDto.Status status, Set<String> componentUuids) { | |||
if (componentUuids.isEmpty()) { | |||
public Map<String, Integer> countByStatusAndMainComponentUuids(DbSession dbSession, CeQueueDto.Status status, Set<String> projectUuids) { | |||
if (projectUuids.isEmpty()) { | |||
return emptyMap(); | |||
} | |||
ImmutableMap.Builder<String, Integer> builder = ImmutableMap.builder(); | |||
executeLargeUpdates( | |||
componentUuids, | |||
projectUuids, | |||
uuids -> { | |||
List<QueueCount> i = mapper(dbSession).countByStatusAndComponentUuids(status, componentUuids); | |||
i.forEach(o -> builder.put(o.getComponentUuid(), o.getTotal())); | |||
List<QueueCount> i = mapper(dbSession).countByStatusAndMainComponentUuids(status, projectUuids); | |||
i.forEach(o -> builder.put(o.getMainComponentUuid(), o.getTotal())); | |||
}); | |||
return builder.build(); | |||
} |
@@ -21,8 +21,11 @@ package org.sonar.db.ce; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import org.sonar.db.component.ComponentDto; | |||
import static com.google.common.base.MoreObjects.firstNonNull; | |||
import static com.google.common.base.Preconditions.checkArgument; | |||
import static java.util.Objects.requireNonNull; | |||
public class CeQueueDto { | |||
@@ -32,7 +35,21 @@ public class CeQueueDto { | |||
private String uuid; | |||
private String taskType; | |||
/** | |||
* Can be {@code null} when task is not associated to any data in table PROJECTS, but must always be non {@code null} | |||
* at the same time as {@link #mainComponentUuid}. | |||
* <p> | |||
* The component uuid of a any component (project or not) is its own UUID. | |||
*/ | |||
private String componentUuid; | |||
/** | |||
* Can be {@code null} when task is not associated to any data in table PROJECTS, but must always be non {@code null} | |||
* at the same time as {@link #componentUuid}. | |||
* <p> | |||
* The main component uuid of the main branch of project is its own UUID. For other branches of a project, it is the | |||
* project UUID of the main branch of that project ({@link ComponentDto#getMainBranchProjectUuid()}). | |||
*/ | |||
private String mainComponentUuid; | |||
private Status status; | |||
private String submitterUuid; | |||
/** | |||
@@ -48,22 +65,52 @@ public class CeQueueDto { | |||
} | |||
public CeQueueDto setUuid(String s) { | |||
checkArgument(s.length() <= 40, "Value of UUID is too long: %s", s); | |||
checkUuid(s, "UUID"); | |||
this.uuid = s; | |||
return this; | |||
} | |||
/** | |||
* Helper methods which sets both {@link #componentUuid} and {@link #mainComponentUuid} from the specified | |||
* {@link ComponentDto}. | |||
*/ | |||
public CeQueueDto setComponent(@Nullable ComponentDto component) { | |||
if (component == null) { | |||
this.componentUuid = null; | |||
this.mainComponentUuid = null; | |||
} else { | |||
this.componentUuid = requireNonNull(component.uuid()); | |||
this.mainComponentUuid = firstNonNull(component.getMainBranchProjectUuid(), component.uuid()); | |||
} | |||
return this; | |||
} | |||
@CheckForNull | |||
public String getComponentUuid() { | |||
return componentUuid; | |||
} | |||
public CeQueueDto setComponentUuid(@Nullable String s) { | |||
checkArgument(s == null || s.length() <= 40, "Value of component UUID is too long: %s", s); | |||
checkUuid(s, "COMPONENT_UUID"); | |||
this.componentUuid = s; | |||
return this; | |||
} | |||
@CheckForNull | |||
public String getMainComponentUuid() { | |||
return mainComponentUuid; | |||
} | |||
public CeQueueDto setMainComponentUuid(@Nullable String s) { | |||
checkUuid(s, "MAIN_COMPONENT_UUID"); | |||
this.mainComponentUuid = s; | |||
return this; | |||
} | |||
private static void checkUuid(@Nullable String s, String columnName) { | |||
checkArgument(s == null || s.length() <= 40, "Value is too long for column CE_QUEUE.%s: %s", columnName, s); | |||
} | |||
public Status getStatus() { | |||
return status; | |||
} | |||
@@ -101,8 +148,9 @@ public class CeQueueDto { | |||
/** | |||
* Accessed by MyBatis through reflexion. Field is otherwise read-only. | |||
*/ | |||
private void setWorkerUuid(@Nullable String workerUuid) { | |||
protected CeQueueDto setWorkerUuid(@Nullable String workerUuid) { | |||
this.workerUuid = workerUuid; | |||
return this; | |||
} | |||
@CheckForNull | |||
@@ -113,8 +161,9 @@ public class CeQueueDto { | |||
/** | |||
* Accessed by MyBatis through reflexion. Field is otherwise read-only. | |||
*/ | |||
private void setStartedAt(@Nullable Long l) { | |||
protected CeQueueDto setStartedAt(@Nullable Long l) { | |||
this.startedAt = l; | |||
return this; | |||
} | |||
public long getCreatedAt() { | |||
@@ -141,6 +190,7 @@ public class CeQueueDto { | |||
"uuid='" + uuid + '\'' + | |||
", taskType='" + taskType + '\'' + | |||
", componentUuid='" + componentUuid + '\'' + | |||
", mainComponentUuid='" + mainComponentUuid + '\'' + | |||
", status=" + status + | |||
", submitterLogin='" + submitterUuid + '\'' + | |||
", workerUuid='" + workerUuid + '\'' + |
@@ -29,7 +29,7 @@ import org.sonar.db.Pagination; | |||
public interface CeQueueMapper { | |||
List<CeQueueDto> selectByComponentUuid(@Param("componentUuid") String componentUuid); | |||
List<CeQueueDto> selectByMainComponentUuid(@Param("mainComponentUuid") String mainComponentUuid); | |||
List<CeQueueDto> selectAllInAscOrder(); | |||
@@ -62,9 +62,9 @@ public interface CeQueueMapper { | |||
*/ | |||
void resetAllInProgressTasks(@Param("updatedAt") long updatedAt); | |||
int countByStatusAndComponentUuid(@Param("status") CeQueueDto.Status status, @Nullable @Param("componentUuid") String componentUuid); | |||
int countByStatusAndMainComponentUuid(@Param("status") CeQueueDto.Status status, @Nullable @Param("mainComponentUuid") String mainComponentUuid); | |||
List<QueueCount> countByStatusAndComponentUuids(@Param("status") CeQueueDto.Status status, @Param("componentUuids") Set<String> componentUuids); | |||
List<QueueCount> countByStatusAndMainComponentUuids(@Param("status") CeQueueDto.Status status, @Param("mainComponentUuids") Set<String> mainComponentUuids); | |||
void insert(CeQueueDto dto); | |||
@@ -36,31 +36,31 @@ public class CeTaskQuery { | |||
private boolean onlyCurrents = false; | |||
// SONAR-7681 a public implementation of List must be used in MyBatis - potential concurrency exceptions otherwise | |||
private ArrayList<String> componentUuids; | |||
private ArrayList<String> mainComponentUuids; | |||
private ArrayList<String> statuses; | |||
private String type; | |||
private Long minSubmittedAt; | |||
private Long maxExecutedAt; | |||
@CheckForNull | |||
public List<String> getComponentUuids() { | |||
return componentUuids; | |||
public List<String> getMainComponentUuids() { | |||
return mainComponentUuids; | |||
} | |||
public CeTaskQuery setComponentUuids(@Nullable List<String> l) { | |||
this.componentUuids = l == null ? null : newArrayList(l); | |||
public CeTaskQuery setMainComponentUuids(@Nullable List<String> l) { | |||
this.mainComponentUuids = l == null ? null : newArrayList(l); | |||
return this; | |||
} | |||
public boolean isShortCircuitedByComponentUuids() { | |||
return componentUuids != null && (componentUuids.isEmpty() || componentUuids.size() > MAX_COMPONENT_UUIDS); | |||
public boolean isShortCircuitedByMainComponentUuids() { | |||
return mainComponentUuids != null && (mainComponentUuids.isEmpty() || mainComponentUuids.size() > MAX_COMPONENT_UUIDS); | |||
} | |||
public CeTaskQuery setComponentUuid(@Nullable String s) { | |||
public CeTaskQuery setMainComponentUuid(@Nullable String s) { | |||
if (s == null) { | |||
this.componentUuids = null; | |||
this.mainComponentUuids = null; | |||
} else { | |||
this.componentUuids = newArrayList(s); | |||
this.mainComponentUuids = newArrayList(s); | |||
} | |||
return this; | |||
} |
@@ -21,11 +21,11 @@ package org.sonar.db.ce; | |||
public class QueueCount { | |||
// set by reflection by MyBatis | |||
private String componentUuid; | |||
private String mainComponentUuid; | |||
private int total; | |||
public String getComponentUuid() { | |||
return componentUuid; | |||
public String getMainComponentUuid() { | |||
return mainComponentUuid; | |||
} | |||
public int getTotal() { |
@@ -112,7 +112,7 @@ public class ComponentDao implements Dao { | |||
/** | |||
* @throws IllegalArgumentException if parameter query#getComponentIds() has more than {@link org.sonar.db.DatabaseUtils#PARTITION_SIZE_FOR_ORACLE} values | |||
* @throws IllegalArgumentException if parameter query#getComponentKeys() has more than {@link org.sonar.db.DatabaseUtils#PARTITION_SIZE_FOR_ORACLE} values | |||
* @throws IllegalArgumentException if parameter query#getComponentUuids() has more than {@link org.sonar.db.DatabaseUtils#PARTITION_SIZE_FOR_ORACLE} values | |||
* @throws IllegalArgumentException if parameter query#getMainComponentUuids() has more than {@link org.sonar.db.DatabaseUtils#PARTITION_SIZE_FOR_ORACLE} values | |||
*/ | |||
public List<ComponentDto> selectByQuery(DbSession dbSession, String organizationUuid, ComponentQuery query, int offset, int limit) { | |||
requireNonNull(organizationUuid, "organizationUuid can't be null"); | |||
@@ -130,7 +130,7 @@ public class ComponentDao implements Dao { | |||
/** | |||
* @throws IllegalArgumentException if parameter query#getComponentIds() has more than {@link org.sonar.db.DatabaseUtils#PARTITION_SIZE_FOR_ORACLE} values | |||
* @throws IllegalArgumentException if parameter query#getComponentKeys() has more than {@link org.sonar.db.DatabaseUtils#PARTITION_SIZE_FOR_ORACLE} values | |||
* @throws IllegalArgumentException if parameter query#getComponentUuids() has more than {@link org.sonar.db.DatabaseUtils#PARTITION_SIZE_FOR_ORACLE} values | |||
* @throws IllegalArgumentException if parameter query#getMainComponentUuids() has more than {@link org.sonar.db.DatabaseUtils#PARTITION_SIZE_FOR_ORACLE} values | |||
*/ | |||
public int countByQuery(DbSession session, String organizationUuid, ComponentQuery query) { | |||
requireNonNull(organizationUuid, "organizationUuid can't be null"); |
@@ -19,7 +19,8 @@ | |||
ca.id, | |||
ca.uuid, | |||
ca.task_type as taskType, | |||
ca.component_uuid as componentUuid, | |||
ca.tmp_component_uuid as componentUuid, | |||
ca.tmp_main_component_uuid as mainComponentUuid, | |||
ca.analysis_uuid as analysisUuid, | |||
ca.status as status, | |||
ca.submitter_uuid as submitterUuid, | |||
@@ -29,8 +30,10 @@ | |||
ca.executed_at as executedAt, | |||
ca.created_at as createdAt, | |||
ca.updated_at as updatedAt, | |||
ca.is_last as isLast, | |||
ca.is_last_key as isLastKey, | |||
ca.tmp_is_last as isLast, | |||
ca.tmp_is_last_key as isLastKey, | |||
ca.tmp_main_is_last as mainIsLast, | |||
ca.tmp_main_is_last_key as mainIsLastKey, | |||
ca.execution_time_ms as executionTimeMs, | |||
ca.error_message as errorMessage, | |||
ca.error_type as errorType, | |||
@@ -83,11 +86,11 @@ | |||
left outer join ce_scanner_context csc on csc.task_uuid = ca.uuid | |||
<where> | |||
<if test="query.onlyCurrents"> | |||
and ca.is_last=${_true} | |||
and ca.tmp_main_is_last=${_true} | |||
</if> | |||
<if test="query.componentUuids != null and query.componentUuids.size()>0"> | |||
and ca.component_uuid in | |||
<foreach collection="query.componentUuids" open="(" close=")" item="cUuid" separator=","> | |||
<if test="query.mainComponentUuids != null and query.mainComponentUuids.size()>0"> | |||
and ca.tmp_main_component_uuid in | |||
<foreach collection="query.mainComponentUuids" open="(" close=")" item="cUuid" separator=","> | |||
#{cUuid,jdbcType=VARCHAR} | |||
</foreach> | |||
</if> | |||
@@ -118,26 +121,32 @@ | |||
ca.created_at < #{beforeDate,jdbcType=BIGINT} | |||
</select> | |||
<select id="countLastByStatusAndComponentUuid" resultType="int"> | |||
<select id="countLastByStatusAndMainComponentUuid" resultType="int"> | |||
select | |||
count(1) | |||
from | |||
ce_activity | |||
where | |||
status=#{status,jdbcType=VARCHAR} | |||
and is_last=${_true} | |||
<if test="componentUuid!=null"> | |||
and component_uuid=#{componentUuid,jdbcType=VARCHAR} | |||
tmp_main_is_last=${_true} | |||
and status=#{status,jdbcType=VARCHAR} | |||
<if test="mainComponentUuid!=null"> | |||
and tmp_main_component_uuid=#{mainComponentUuid,jdbcType=VARCHAR} | |||
</if> | |||
</select> | |||
<insert id="insert" parameterType="org.sonar.db.ce.CeActivityDto" useGeneratedKeys="false"> | |||
insert into ce_activity ( | |||
uuid, | |||
tmp_component_uuid, | |||
tmp_main_component_uuid, | |||
component_uuid, | |||
analysis_uuid, | |||
status, | |||
task_type, | |||
tmp_is_last, | |||
tmp_is_last_key, | |||
tmp_main_is_last, | |||
tmp_main_is_last_key, | |||
is_last, | |||
is_last_key, | |||
submitter_uuid, | |||
@@ -156,11 +165,17 @@ | |||
values ( | |||
#{uuid,jdbcType=VARCHAR}, | |||
#{componentUuid,jdbcType=VARCHAR}, | |||
#{mainComponentUuid,jdbcType=VARCHAR}, | |||
#{mainComponentUuid,jdbcType=VARCHAR}, | |||
#{analysisUuid,jdbcType=VARCHAR}, | |||
#{status,jdbcType=VARCHAR}, | |||
#{taskType,jdbcType=VARCHAR}, | |||
#{isLast,jdbcType=BOOLEAN}, | |||
#{isLastKey,jdbcType=VARCHAR}, | |||
#{mainIsLast,jdbcType=BOOLEAN}, | |||
#{mainIsLastKey,jdbcType=VARCHAR}, | |||
#{mainIsLast,jdbcType=BOOLEAN}, | |||
#{mainIsLastKey,jdbcType=VARCHAR}, | |||
#{submitterUuid,jdbcType=VARCHAR}, | |||
#{submittedAt,jdbcType=BIGINT}, | |||
#{workerUuid,jdbcType=VARCHAR}, | |||
@@ -176,11 +191,16 @@ | |||
) | |||
</insert> | |||
<update id="updateIsLastToFalseForLastKey" parameterType="map"> | |||
update ce_activity | |||
set is_last=${_false}, | |||
updated_at=#{updatedAt,jdbcType=BIGINT} | |||
where is_last=${_true} and is_last_key=#{isLastKey,jdbcType=VARCHAR} | |||
<update id="clearIsLast" parameterType="map"> | |||
update ce_activity set | |||
tmp_is_last=${_false}, | |||
tmp_main_is_last=${_false}, | |||
is_last=${_false}, | |||
updated_at=#{updatedAt,jdbcType=BIGINT} | |||
where | |||
(tmp_is_last=${_true} and tmp_is_last_key=#{isLastKey,jdbcType=VARCHAR}) | |||
or | |||
(tmp_main_is_last=${_true} and tmp_main_is_last_key=#{mainIsLastKey,jdbcType=VARCHAR}) | |||
</update> | |||
<delete id="deleteByUuids" parameterType="string"> |
@@ -6,7 +6,8 @@ | |||
<sql id="columns"> | |||
cq.uuid, | |||
cq.task_type as taskType, | |||
cq.component_uuid as componentUuid, | |||
cq.tmp_component_uuid as componentUuid, | |||
cq.tmp_main_component_uuid as mainComponentUuid, | |||
cq.status as status, | |||
cq.submitter_uuid as submitterUuid, | |||
cq.worker_uuid as workerUuid, | |||
@@ -36,31 +37,31 @@ | |||
cq.uuid=#{uuid,jdbcType=VARCHAR} | |||
</select> | |||
<select id="countByStatusAndComponentUuid" parameterType="map" resultType="int"> | |||
<select id="countByStatusAndMainComponentUuid" parameterType="map" resultType="int"> | |||
select | |||
count(1) | |||
from | |||
ce_queue | |||
where | |||
status=#{status,jdbcType=VARCHAR} | |||
<if test="componentUuid!=null"> | |||
and component_uuid=#{componentUuid,jdbcType=VARCHAR} | |||
<if test="mainComponentUuid!=null"> | |||
and tmp_main_component_uuid=#{mainComponentUuid,jdbcType=VARCHAR} | |||
</if> | |||
</select> | |||
<select id="countByStatusAndComponentUuids" resultType="org.sonar.db.ce.QueueCount"> | |||
<select id="countByStatusAndMainComponentUuids" resultType="org.sonar.db.ce.QueueCount"> | |||
select | |||
component_uuid as componentUuid, | |||
tmp_main_component_uuid as mainComponentUuid, | |||
count(1) as total | |||
from | |||
ce_queue | |||
where | |||
status=#{status,jdbcType=VARCHAR} | |||
and component_uuid in | |||
<foreach collection="componentUuids" open="(" close=")" item="cUuid" separator=","> | |||
#{cUuid,jdbcType=VARCHAR} | |||
and tmp_main_component_uuid in | |||
<foreach collection="mainComponentUuids" open="(" close=")" item="mainComponentUuid" separator=","> | |||
#{mainComponentUuid,jdbcType=VARCHAR} | |||
</foreach> | |||
group by component_uuid | |||
group by tmp_main_component_uuid | |||
</select> | |||
<select id="countAll" resultType="int"> | |||
@@ -70,13 +71,13 @@ | |||
ce_queue | |||
</select> | |||
<select id="selectByComponentUuid" parameterType="String" resultType="org.sonar.db.ce.CeQueueDto"> | |||
<select id="selectByMainComponentUuid" parameterType="String" resultType="org.sonar.db.ce.CeQueueDto"> | |||
select | |||
<include refid="columns"/> | |||
from | |||
ce_queue cq | |||
where | |||
cq.component_uuid=#{componentUuid,jdbcType=VARCHAR} | |||
cq.tmp_main_component_uuid=#{mainComponentUuid,jdbcType=VARCHAR} | |||
<include refid="orderByDateAndId"/> | |||
</select> | |||
@@ -105,10 +106,10 @@ | |||
from | |||
ce_queue cq | |||
<where> | |||
<if test="query.componentUuids != null and query.componentUuids.size()>0"> | |||
and cq.component_uuid in | |||
<foreach collection="query.componentUuids" open="(" close=")" item="cUuid" separator=","> | |||
#{cUuid,jdbcType=VARCHAR} | |||
<if test="query.mainComponentUuids != null and query.mainComponentUuids.size()>0"> | |||
and cq.tmp_main_component_uuid in | |||
<foreach collection="query.mainComponentUuids" open="(" close=")" item="mainComponentUuid" separator=","> | |||
#{mainComponentUuid,jdbcType=VARCHAR} | |||
</foreach> | |||
</if> | |||
<if test="query.statuses != null"> | |||
@@ -176,7 +177,7 @@ | |||
from | |||
ce_queue cq2 | |||
where | |||
cq.component_uuid=cq2.component_uuid | |||
cq.tmp_main_component_uuid=cq2.tmp_main_component_uuid | |||
and cq2.status <> 'PENDING' | |||
) | |||
</sql> | |||
@@ -211,7 +212,9 @@ | |||
( | |||
uuid, | |||
task_type, | |||
tmp_component_uuid, | |||
component_uuid, | |||
tmp_main_component_uuid, | |||
status, | |||
submitter_uuid, | |||
execution_count, | |||
@@ -222,6 +225,8 @@ | |||
#{uuid,jdbcType=VARCHAR}, | |||
#{taskType,jdbcType=VARCHAR}, | |||
#{componentUuid,jdbcType=VARCHAR}, | |||
#{mainComponentUuid,jdbcType=VARCHAR}, | |||
#{mainComponentUuid,jdbcType=VARCHAR}, | |||
#{status,jdbcType=VARCHAR}, | |||
#{submitterUuid,jdbcType=VARCHAR}, | |||
0, |
@@ -315,45 +315,45 @@ | |||
<delete id="deleteCeScannerContextOfCeActivityByProjectUuid"> | |||
delete from ce_scanner_context | |||
where | |||
task_uuid in (select uuid from ce_activity where component_uuid=#{projectUuid,jdbcType=VARCHAR}) | |||
task_uuid in (select uuid from ce_activity where tmp_main_component_uuid=#{projectUuid,jdbcType=VARCHAR}) | |||
</delete> | |||
<delete id="deleteCeTaskCharacteristicsOfCeActivityByProjectUuid"> | |||
delete from ce_task_characteristics | |||
where | |||
task_uuid in (select uuid from ce_activity where component_uuid=#{projectUuid,jdbcType=VARCHAR}) | |||
task_uuid in (select uuid from ce_activity where tmp_main_component_uuid=#{projectUuid,jdbcType=VARCHAR}) | |||
</delete> | |||
<delete id="deleteCeTaskInputOfCeActivityByProjectUuid"> | |||
delete from ce_task_input | |||
where | |||
task_uuid in (select uuid from ce_activity where component_uuid=#{projectUuid,jdbcType=VARCHAR}) | |||
task_uuid in (select uuid from ce_activity where tmp_main_component_uuid=#{projectUuid,jdbcType=VARCHAR}) | |||
</delete> | |||
<delete id="deleteCeActivityByProjectUuid"> | |||
delete from ce_activity where component_uuid=#{projectUuid,jdbcType=VARCHAR} | |||
delete from ce_activity where tmp_main_component_uuid=#{projectUuid,jdbcType=VARCHAR} | |||
</delete> | |||
<delete id="deleteCeScannerContextOfCeQueueByProjectUuid"> | |||
delete from ce_scanner_context | |||
where | |||
task_uuid in (select uuid from ce_queue where component_uuid=#{projectUuid,jdbcType=VARCHAR}) | |||
task_uuid in (select uuid from ce_queue where tmp_main_component_uuid=#{projectUuid,jdbcType=VARCHAR}) | |||
</delete> | |||
<delete id="deleteCeTaskCharacteristicsOfCeQueueByProjectUuid"> | |||
delete from ce_task_characteristics | |||
where | |||
task_uuid in (select uuid from ce_queue where component_uuid=#{projectUuid,jdbcType=VARCHAR}) | |||
task_uuid in (select uuid from ce_queue where tmp_main_component_uuid=#{projectUuid,jdbcType=VARCHAR}) | |||
</delete> | |||
<delete id="deleteCeTaskInputOfCeQueueByProjectUuid"> | |||
delete from ce_task_input | |||
where | |||
task_uuid in (select uuid from ce_queue where component_uuid=#{projectUuid,jdbcType=VARCHAR}) | |||
task_uuid in (select uuid from ce_queue where tmp_main_component_uuid=#{projectUuid,jdbcType=VARCHAR}) | |||
</delete> | |||
<delete id="deleteCeQueueByProjectUuid"> | |||
delete from ce_queue where component_uuid=#{projectUuid,jdbcType=VARCHAR} | |||
delete from ce_queue where tmp_main_component_uuid=#{projectUuid,jdbcType=VARCHAR} | |||
</delete> | |||
<delete id="deleteWebhooksByProjectUuid"> |
@@ -26,6 +26,7 @@ import java.util.Collections; | |||
import java.util.List; | |||
import java.util.Optional; | |||
import javax.annotation.Nonnull; | |||
import javax.annotation.Nullable; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.sonar.api.utils.internal.TestSystem2; | |||
@@ -37,6 +38,7 @@ import org.sonar.db.Pagination; | |||
import static java.util.Collections.singleton; | |||
import static java.util.Collections.singletonList; | |||
import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.sonar.db.Pagination.forPage; | |||
import static org.sonar.db.ce.CeActivityDto.Status.FAILED; | |||
@@ -47,6 +49,10 @@ import static org.sonar.db.ce.CeTaskTypes.REPORT; | |||
public class CeActivityDaoTest { | |||
private static final String MAINCOMPONENT_1 = randomAlphabetic(12); | |||
private static final String MAINCOMPONENT_2 = randomAlphabetic(13); | |||
private static final String COMPONENT_1 = randomAlphabetic(14); | |||
private TestSystem2 system2 = new TestSystem2().setNow(1_450_000_000_000L); | |||
@Rule | |||
@@ -57,19 +63,22 @@ public class CeActivityDaoTest { | |||
@Test | |||
public void test_insert() { | |||
CeActivityDto inserted = insert("TASK_1", REPORT, "PROJECT_1", CeActivityDto.Status.SUCCESS); | |||
CeActivityDto inserted = insert("TASK_1", REPORT, COMPONENT_1, MAINCOMPONENT_1, CeActivityDto.Status.SUCCESS); | |||
Optional<CeActivityDto> saved = underTest.selectByUuid(db.getSession(), "TASK_1"); | |||
assertThat(saved).isPresent(); | |||
CeActivityDto dto = saved.get(); | |||
assertThat(dto.getUuid()).isEqualTo("TASK_1"); | |||
assertThat(dto.getComponentUuid()).isEqualTo("PROJECT_1"); | |||
assertThat(dto.getMainComponentUuid()).isEqualTo(MAINCOMPONENT_1); | |||
assertThat(dto.getComponentUuid()).isEqualTo(COMPONENT_1); | |||
assertThat(dto.getStatus()).isEqualTo(CeActivityDto.Status.SUCCESS); | |||
assertThat(dto.getSubmitterUuid()).isEqualTo("submitter uuid"); | |||
assertThat(dto.getSubmittedAt()).isEqualTo(1_450_000_000_000L); | |||
assertThat(dto.getWorkerUuid()).isEqualTo("worker uuid"); | |||
assertThat(dto.getIsLast()).isTrue(); | |||
assertThat(dto.getIsLastKey()).isEqualTo("REPORTPROJECT_1"); | |||
assertThat(dto.getMainIsLast()).isTrue(); | |||
assertThat(dto.getIsLastKey()).isEqualTo("REPORT" + COMPONENT_1); | |||
assertThat(dto.getMainIsLastKey()).isEqualTo("REPORT" + MAINCOMPONENT_1); | |||
assertThat(dto.getCreatedAt()).isEqualTo(1_450_000_000_000L); | |||
assertThat(dto.getStartedAt()).isEqualTo(1_500_000_000_000L); | |||
assertThat(dto.getExecutedAt()).isEqualTo(1_500_000_000_500L); | |||
@@ -84,7 +93,7 @@ public class CeActivityDaoTest { | |||
@Test | |||
public void test_insert_of_errorMessage_of_1_000_chars() { | |||
CeActivityDto dto = createActivityDto("TASK_1", REPORT, "PROJECT_1", CeActivityDto.Status.FAILED) | |||
CeActivityDto dto = createActivityDto("TASK_1", REPORT, COMPONENT_1, MAINCOMPONENT_1, CeActivityDto.Status.FAILED) | |||
.setErrorMessage(Strings.repeat("x", 1_000)); | |||
underTest.insert(db.getSession(), dto); | |||
@@ -95,7 +104,7 @@ public class CeActivityDaoTest { | |||
@Test | |||
public void test_insert_of_errorMessage_of_1_001_chars_is_truncated_to_1000() { | |||
String expected = Strings.repeat("x", 1_000); | |||
CeActivityDto dto = createActivityDto("TASK_1", REPORT, "PROJECT_1", CeActivityDto.Status.FAILED) | |||
CeActivityDto dto = createActivityDto("TASK_1", REPORT, COMPONENT_1, MAINCOMPONENT_1, CeActivityDto.Status.FAILED) | |||
.setErrorMessage(expected + "y"); | |||
underTest.insert(db.getSession(), dto); | |||
@@ -105,7 +114,7 @@ public class CeActivityDaoTest { | |||
@Test | |||
public void test_insert_error_message_and_stacktrace() { | |||
CeActivityDto dto = createActivityDto("TASK_1", REPORT, "PROJECT_1", CeActivityDto.Status.FAILED) | |||
CeActivityDto dto = createActivityDto("TASK_1", REPORT, COMPONENT_1, MAINCOMPONENT_1, CeActivityDto.Status.FAILED) | |||
.setErrorStacktrace("error stack"); | |||
underTest.insert(db.getSession(), dto); | |||
@@ -118,7 +127,7 @@ public class CeActivityDaoTest { | |||
@Test | |||
public void test_insert_error_message_only() { | |||
CeActivityDto dto = createActivityDto("TASK_1", REPORT, "PROJECT_1", CeActivityDto.Status.FAILED); | |||
CeActivityDto dto = createActivityDto("TASK_1", REPORT, COMPONENT_1, MAINCOMPONENT_1, CeActivityDto.Status.FAILED); | |||
underTest.insert(db.getSession(), dto); | |||
Optional<CeActivityDto> saved = underTest.selectByUuid(db.getSession(), "TASK_1"); | |||
@@ -129,22 +138,22 @@ public class CeActivityDaoTest { | |||
@Test | |||
public void insert_must_set_relevant_is_last_field() { | |||
// only a single task on PROJECT_1 -> is_last=true | |||
insert("TASK_1", REPORT, "PROJECT_1", CeActivityDto.Status.SUCCESS); | |||
// only a single task on MAINCOMPONENT_1 -> is_last=true | |||
insert("TASK_1", REPORT, MAINCOMPONENT_1, CeActivityDto.Status.SUCCESS); | |||
assertThat(underTest.selectByUuid(db.getSession(), "TASK_1").get().getIsLast()).isTrue(); | |||
// only a single task on PROJECT_2 -> is_last=true | |||
insert("TASK_2", REPORT, "PROJECT_2", CeActivityDto.Status.SUCCESS); | |||
// only a single task on MAINCOMPONENT_2 -> is_last=true | |||
insert("TASK_2", REPORT, MAINCOMPONENT_2, CeActivityDto.Status.SUCCESS); | |||
assertThat(underTest.selectByUuid(db.getSession(), "TASK_2").get().getIsLast()).isTrue(); | |||
// two tasks on PROJECT_1, the most recent one is TASK_3 | |||
insert("TASK_3", REPORT, "PROJECT_1", FAILED); | |||
// two tasks on MAINCOMPONENT_1, the most recent one is TASK_3 | |||
insert("TASK_3", REPORT, MAINCOMPONENT_1, FAILED); | |||
assertThat(underTest.selectByUuid(db.getSession(), "TASK_1").get().getIsLast()).isFalse(); | |||
assertThat(underTest.selectByUuid(db.getSession(), "TASK_2").get().getIsLast()).isTrue(); | |||
assertThat(underTest.selectByUuid(db.getSession(), "TASK_3").get().getIsLast()).isTrue(); | |||
// inserting a cancelled task does not change the last task | |||
insert("TASK_4", REPORT, "PROJECT_1", CeActivityDto.Status.CANCELED); | |||
insert("TASK_4", REPORT, MAINCOMPONENT_1, CeActivityDto.Status.CANCELED); | |||
assertThat(underTest.selectByUuid(db.getSession(), "TASK_1").get().getIsLast()).isFalse(); | |||
assertThat(underTest.selectByUuid(db.getSession(), "TASK_2").get().getIsLast()).isTrue(); | |||
assertThat(underTest.selectByUuid(db.getSession(), "TASK_3").get().getIsLast()).isTrue(); | |||
@@ -153,9 +162,9 @@ public class CeActivityDaoTest { | |||
@Test | |||
public void test_selectByQuery() { | |||
insert("TASK_1", REPORT, "PROJECT_1", CeActivityDto.Status.SUCCESS); | |||
insert("TASK_2", REPORT, "PROJECT_1", FAILED); | |||
insert("TASK_3", REPORT, "PROJECT_2", CeActivityDto.Status.SUCCESS); | |||
insert("TASK_1", REPORT, MAINCOMPONENT_1, CeActivityDto.Status.SUCCESS); | |||
insert("TASK_2", REPORT, MAINCOMPONENT_1, FAILED); | |||
insert("TASK_3", REPORT, MAINCOMPONENT_2, CeActivityDto.Status.SUCCESS); | |||
insert("TASK_4", "views", null, CeActivityDto.Status.SUCCESS); | |||
// no filters | |||
@@ -164,7 +173,7 @@ public class CeActivityDaoTest { | |||
assertThat(dtos).extracting("uuid").containsExactly("TASK_4", "TASK_3", "TASK_2", "TASK_1"); | |||
// select by component uuid | |||
query = new CeTaskQuery().setComponentUuid("PROJECT_1"); | |||
query = new CeTaskQuery().setMainComponentUuid(MAINCOMPONENT_1); | |||
dtos = underTest.selectByQuery(db.getSession(), query, forPage(1).andSize(100)); | |||
assertThat(dtos).extracting("uuid").containsExactly("TASK_2", "TASK_1"); | |||
@@ -182,17 +191,17 @@ public class CeActivityDaoTest { | |||
assertThat(dtos).extracting("uuid").containsExactly("TASK_4"); | |||
// select by multiple conditions | |||
query = new CeTaskQuery().setType(REPORT).setOnlyCurrents(true).setComponentUuid("PROJECT_1"); | |||
query = new CeTaskQuery().setType(REPORT).setOnlyCurrents(true).setMainComponentUuid(MAINCOMPONENT_1); | |||
dtos = underTest.selectByQuery(db.getSession(), query, forPage(1).andSize(100)); | |||
assertThat(dtos).extracting("uuid").containsExactly("TASK_2"); | |||
} | |||
@Test | |||
public void selectByQuery_does_not_populate_errorStacktrace_field() { | |||
insert("TASK_1", REPORT, "PROJECT_1", FAILED); | |||
underTest.insert(db.getSession(), createActivityDto("TASK_2", REPORT, "PROJECT_1", FAILED).setErrorStacktrace("some stack")); | |||
insert("TASK_1", REPORT, MAINCOMPONENT_1, FAILED); | |||
underTest.insert(db.getSession(), createActivityDto("TASK_2", REPORT, COMPONENT_1, MAINCOMPONENT_1, FAILED).setErrorStacktrace("some stack")); | |||
List<CeActivityDto> dtos = underTest.selectByQuery(db.getSession(), new CeTaskQuery().setComponentUuid("PROJECT_1"), forPage(1).andSize(100)); | |||
List<CeActivityDto> dtos = underTest.selectByQuery(db.getSession(), new CeTaskQuery().setMainComponentUuid(MAINCOMPONENT_1), forPage(1).andSize(100)); | |||
assertThat(dtos) | |||
.hasSize(2) | |||
@@ -201,21 +210,21 @@ public class CeActivityDaoTest { | |||
@Test | |||
public void selectByQuery_populates_hasScannerContext_flag() { | |||
insert("TASK_1", REPORT, "PROJECT_1", SUCCESS); | |||
CeActivityDto dto2 = insert("TASK_2", REPORT, "PROJECT_2", SUCCESS); | |||
insert("TASK_1", REPORT, MAINCOMPONENT_1, SUCCESS); | |||
CeActivityDto dto2 = insert("TASK_2", REPORT, MAINCOMPONENT_2, SUCCESS); | |||
insertScannerContext(dto2.getUuid()); | |||
CeActivityDto dto = underTest.selectByQuery(db.getSession(), new CeTaskQuery().setComponentUuid("PROJECT_1"), forPage(1).andSize(100)).iterator().next(); | |||
CeActivityDto dto = underTest.selectByQuery(db.getSession(), new CeTaskQuery().setMainComponentUuid(MAINCOMPONENT_1), forPage(1).andSize(100)).iterator().next(); | |||
assertThat(dto.isHasScannerContext()).isFalse(); | |||
dto = underTest.selectByQuery(db.getSession(), new CeTaskQuery().setComponentUuid("PROJECT_2"), forPage(1).andSize(100)).iterator().next(); | |||
dto = underTest.selectByQuery(db.getSession(), new CeTaskQuery().setMainComponentUuid(MAINCOMPONENT_2), forPage(1).andSize(100)).iterator().next(); | |||
assertThat(dto.isHasScannerContext()).isTrue(); | |||
} | |||
@Test | |||
public void selectByQuery_is_paginated_and_return_results_sorted_from_last_to_first() { | |||
insert("TASK_1", REPORT, "PROJECT_1", CeActivityDto.Status.SUCCESS); | |||
insert("TASK_2", REPORT, "PROJECT_1", CeActivityDto.Status.FAILED); | |||
insert("TASK_3", REPORT, "PROJECT_2", CeActivityDto.Status.SUCCESS); | |||
insert("TASK_1", REPORT, MAINCOMPONENT_1, CeActivityDto.Status.SUCCESS); | |||
insert("TASK_2", REPORT, MAINCOMPONENT_1, CeActivityDto.Status.FAILED); | |||
insert("TASK_3", REPORT, MAINCOMPONENT_2, CeActivityDto.Status.SUCCESS); | |||
insert("TASK_4", "views", null, CeActivityDto.Status.SUCCESS); | |||
assertThat(selectPageOfUuids(forPage(1).andSize(1))).containsExactly("TASK_4"); | |||
@@ -229,10 +238,10 @@ public class CeActivityDaoTest { | |||
@Test | |||
public void selectByQuery_no_results_if_shortcircuited_by_component_uuids() { | |||
insert("TASK_1", REPORT, "PROJECT_1", CeActivityDto.Status.SUCCESS); | |||
insert("TASK_1", REPORT, MAINCOMPONENT_1, CeActivityDto.Status.SUCCESS); | |||
CeTaskQuery query = new CeTaskQuery(); | |||
query.setComponentUuids(Collections.emptyList()); | |||
query.setMainComponentUuids(Collections.emptyList()); | |||
assertThat(underTest.selectByQuery(db.getSession(), query, forPage(1).andSize(1))).isEmpty(); | |||
} | |||
@@ -291,8 +300,8 @@ public class CeActivityDaoTest { | |||
@Test | |||
public void selectOlderThan_does_not_populate_errorStacktrace() { | |||
insert("TASK_1", REPORT, "PROJECT_1", FAILED); | |||
underTest.insert(db.getSession(), createActivityDto("TASK_2", REPORT, "PROJECT_1", FAILED).setErrorStacktrace("some stack")); | |||
insert("TASK_1", REPORT, MAINCOMPONENT_1, FAILED); | |||
underTest.insert(db.getSession(), createActivityDto("TASK_2", REPORT, COMPONENT_1, MAINCOMPONENT_1, FAILED).setErrorStacktrace("some stack")); | |||
List<CeActivityDto> dtos = underTest.selectOlderThan(db.getSession(), system2.now() + 1_000_000L); | |||
@@ -303,9 +312,9 @@ public class CeActivityDaoTest { | |||
@Test | |||
public void deleteByUuids() { | |||
insert("TASK_1", "REPORT", "COMPONENT1", CeActivityDto.Status.SUCCESS); | |||
insert("TASK_2", "REPORT", "COMPONENT1", CeActivityDto.Status.SUCCESS); | |||
insert("TASK_3", "REPORT", "COMPONENT1", CeActivityDto.Status.SUCCESS); | |||
insert("TASK_1", "REPORT", MAINCOMPONENT_1, CeActivityDto.Status.SUCCESS); | |||
insert("TASK_2", "REPORT", MAINCOMPONENT_1, CeActivityDto.Status.SUCCESS); | |||
insert("TASK_3", "REPORT", MAINCOMPONENT_1, CeActivityDto.Status.SUCCESS); | |||
underTest.deleteByUuids(db.getSession(), ImmutableSet.of("TASK_1", "TASK_3")); | |||
assertThat(underTest.selectByUuid(db.getSession(), "TASK_1").isPresent()).isFalse(); | |||
@@ -315,7 +324,7 @@ public class CeActivityDaoTest { | |||
@Test | |||
public void deleteByUuids_does_nothing_if_uuid_does_not_exist() { | |||
insert("TASK_1", "REPORT", "COMPONENT1", CeActivityDto.Status.SUCCESS); | |||
insert("TASK_1", "REPORT", MAINCOMPONENT_1, CeActivityDto.Status.SUCCESS); | |||
// must not fail | |||
underTest.deleteByUuids(db.getSession(), singleton("TASK_2")); | |||
@@ -324,33 +333,38 @@ public class CeActivityDaoTest { | |||
} | |||
@Test | |||
public void count_last_by_status_and_component_uuid() { | |||
insert("TASK_1", CeTaskTypes.REPORT, "COMPONENT1", CeActivityDto.Status.SUCCESS); | |||
public void count_last_by_status_and_main_component_uuid() { | |||
insert("TASK_1", CeTaskTypes.REPORT, MAINCOMPONENT_1, CeActivityDto.Status.SUCCESS); | |||
// component 2 | |||
insert("TASK_2", CeTaskTypes.REPORT, "COMPONENT2", CeActivityDto.Status.SUCCESS); | |||
insert("TASK_2", CeTaskTypes.REPORT, MAINCOMPONENT_2, CeActivityDto.Status.SUCCESS); | |||
// status failed | |||
insert("TASK_3", CeTaskTypes.REPORT, "COMPONENT1", CeActivityDto.Status.FAILED); | |||
insert("TASK_3", CeTaskTypes.REPORT, MAINCOMPONENT_1, CeActivityDto.Status.FAILED); | |||
// status canceled | |||
insert("TASK_4", CeTaskTypes.REPORT, "COMPONENT1", CeActivityDto.Status.CANCELED); | |||
insert("TASK_5", CeTaskTypes.REPORT, "COMPONENT1", CeActivityDto.Status.SUCCESS); | |||
insert("TASK_4", CeTaskTypes.REPORT, MAINCOMPONENT_1, CeActivityDto.Status.CANCELED); | |||
insert("TASK_5", CeTaskTypes.REPORT, MAINCOMPONENT_1, CeActivityDto.Status.SUCCESS); | |||
db.commit(); | |||
assertThat(underTest.countLastByStatusAndComponentUuid(dbSession, SUCCESS, "COMPONENT1")).isEqualTo(1); | |||
assertThat(underTest.countLastByStatusAndComponentUuid(dbSession, SUCCESS, null)).isEqualTo(2); | |||
assertThat(underTest.countLastByStatusAndMainComponentUuid(dbSession, SUCCESS, MAINCOMPONENT_1)).isEqualTo(1); | |||
assertThat(underTest.countLastByStatusAndMainComponentUuid(dbSession, SUCCESS, null)).isEqualTo(2); | |||
} | |||
private CeActivityDto insert(String uuid, String type, @Nullable String mainComponentUuid, CeActivityDto.Status status) { | |||
return insert(uuid, type, mainComponentUuid, mainComponentUuid, status); | |||
} | |||
private CeActivityDto insert(String uuid, String type, String componentUuid, CeActivityDto.Status status) { | |||
CeActivityDto dto = createActivityDto(uuid, type, componentUuid, status); | |||
private CeActivityDto insert(String uuid, String type, String componentUuid, @Nullable String mainComponentUuid, CeActivityDto.Status status) { | |||
CeActivityDto dto = createActivityDto(uuid, type, componentUuid, mainComponentUuid, status); | |||
underTest.insert(db.getSession(), dto); | |||
return dto; | |||
} | |||
private CeActivityDto createActivityDto(String uuid, String type, String componentUuid, CeActivityDto.Status status) { | |||
private CeActivityDto createActivityDto(String uuid, String type, @Nullable String componentUuid, @Nullable String mainComponentUuid, CeActivityDto.Status status) { | |||
CeQueueDto creating = new CeQueueDto(); | |||
creating.setUuid(uuid); | |||
creating.setStatus(PENDING); | |||
creating.setTaskType(type); | |||
creating.setComponentUuid(componentUuid); | |||
creating.setMainComponentUuid(mainComponentUuid); | |||
creating.setSubmitterUuid("submitter uuid"); | |||
creating.setCreatedAt(1_300_000_000_000L); | |||
@@ -23,7 +23,9 @@ import com.tngtech.java.junit.dataprovider.DataProvider; | |||
import com.tngtech.java.junit.dataprovider.DataProviderRunner; | |||
import com.tngtech.java.junit.dataprovider.UseDataProvider; | |||
import java.util.Random; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.junit.runner.RunWith; | |||
import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; | |||
@@ -31,8 +33,79 @@ import static org.assertj.core.api.Assertions.assertThat; | |||
@RunWith(DataProviderRunner.class) | |||
public class CeActivityDtoTest { | |||
private static final String STR_40_CHARS = "0123456789012345678901234567890123456789"; | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
private CeActivityDto underTest = new CeActivityDto(); | |||
@Test | |||
public void constructor_from_CeQueueDto_populates_fields() { | |||
long now = new Random().nextLong(); | |||
CeQueueDto ceQueueDto = new CeQueueDto() | |||
.setUuid(randomAlphanumeric(10)) | |||
.setTaskType(randomAlphanumeric(11)) | |||
.setComponentUuid(randomAlphanumeric(12)) | |||
.setMainComponentUuid(randomAlphanumeric(13)) | |||
.setSubmitterUuid(randomAlphanumeric(14)) | |||
.setWorkerUuid(randomAlphanumeric(15)) | |||
.setCreatedAt(now + 9_999) | |||
.setStartedAt(now + 865); | |||
CeActivityDto underTest = new CeActivityDto(ceQueueDto); | |||
assertThat(underTest.getUuid()).isEqualTo(ceQueueDto.getUuid()); | |||
assertThat(underTest.getTaskType()).isEqualTo(ceQueueDto.getTaskType()); | |||
assertThat(underTest.getComponentUuid()).isEqualTo(ceQueueDto.getComponentUuid()); | |||
assertThat(underTest.getMainComponentUuid()).isEqualTo(ceQueueDto.getMainComponentUuid()); | |||
assertThat(underTest.getIsLastKey()).isEqualTo(ceQueueDto.getTaskType() + ceQueueDto.getComponentUuid()); | |||
assertThat(underTest.getIsLast()).isFalse(); | |||
assertThat(underTest.getMainIsLastKey()).isEqualTo(ceQueueDto.getTaskType() + ceQueueDto.getMainComponentUuid()); | |||
assertThat(underTest.getMainIsLast()).isFalse(); | |||
assertThat(underTest.getSubmitterUuid()).isEqualTo(ceQueueDto.getSubmitterUuid()); | |||
assertThat(underTest.getWorkerUuid()).isEqualTo(ceQueueDto.getWorkerUuid()); | |||
assertThat(underTest.getSubmittedAt()).isEqualTo(ceQueueDto.getCreatedAt()); | |||
assertThat(underTest.getStartedAt()).isEqualTo(ceQueueDto.getStartedAt()); | |||
assertThat(underTest.getStatus()).isNull(); | |||
} | |||
@Test | |||
public void setComponentUuid_accepts_null_empty_and_string_40_chars_or_less() { | |||
underTest.setComponentUuid(null); | |||
underTest.setComponentUuid(""); | |||
underTest.setComponentUuid("bar"); | |||
underTest.setComponentUuid(STR_40_CHARS); | |||
} | |||
@Test | |||
public void setComponentUuid_throws_IAE_if_value_is_41_chars() { | |||
String str_41_chars = STR_40_CHARS + "a"; | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("Value is too long for column CE_ACTIVITY.COMPONENT_UUID: " + str_41_chars); | |||
underTest.setComponentUuid(str_41_chars); | |||
} | |||
@Test | |||
public void setMainComponentUuid_accepts_null_empty_and_string_40_chars_or_less() { | |||
underTest.setMainComponentUuid(null); | |||
underTest.setMainComponentUuid(""); | |||
underTest.setMainComponentUuid("bar"); | |||
underTest.setMainComponentUuid(STR_40_CHARS); | |||
} | |||
@Test | |||
public void setMainComponentUuid_throws_IAE_if_value_is_41_chars() { | |||
String str_41_chars = STR_40_CHARS + "a"; | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("Value is too long for column CE_ACTIVITY.MAIN_COMPONENT_UUID: " + str_41_chars); | |||
underTest.setMainComponentUuid(str_41_chars); | |||
} | |||
@Test | |||
@UseDataProvider("stringsWithChar0") | |||
public void setStacktrace_filters_out_char_zero(String withChar0, String expected) { |
@@ -27,6 +27,7 @@ import java.util.HashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Optional; | |||
import java.util.Random; | |||
import java.util.stream.Stream; | |||
import javax.annotation.Nullable; | |||
import org.junit.Rule; | |||
@@ -54,8 +55,8 @@ public class CeQueueDaoTest { | |||
private static final long INIT_TIME = 1_450_000_000_000L; | |||
private static final String TASK_UUID_1 = "TASK_1"; | |||
private static final String TASK_UUID_2 = "TASK_2"; | |||
private static final String COMPONENT_UUID_1 = "PROJECT_1"; | |||
private static final String COMPONENT_UUID_2 = "PROJECT_2"; | |||
private static final String MAIN_COMPONENT_UUID_1 = "PROJECT_1"; | |||
private static final String MAIN_COMPONENT_UUID_2 = "PROJECT_2"; | |||
private static final String TASK_UUID_3 = "TASK_3"; | |||
private static final String SELECT_QUEUE_UUID_AND_STATUS_QUERY = "select uuid,status from ce_queue"; | |||
private static final String SUBMITTER_LOGIN = "submitter uuid"; | |||
@@ -79,7 +80,7 @@ public class CeQueueDaoTest { | |||
long now = 1_334_333L; | |||
CeQueueDto dto = new CeQueueDto() | |||
.setTaskType(CeTaskTypes.REPORT) | |||
.setComponentUuid(COMPONENT_UUID_1) | |||
.setComponentUuid(MAIN_COMPONENT_UUID_1) | |||
.setStatus(PENDING) | |||
.setSubmitterUuid(SUBMITTER_LOGIN); | |||
@@ -99,7 +100,7 @@ public class CeQueueDaoTest { | |||
CeQueueDto saved = underTest.selectByUuid(db.getSession(), uuid).get(); | |||
assertThat(saved.getUuid()).isEqualTo(uuid); | |||
assertThat(saved.getTaskType()).isEqualTo(CeTaskTypes.REPORT); | |||
assertThat(saved.getComponentUuid()).isEqualTo(COMPONENT_UUID_1); | |||
assertThat(saved.getComponentUuid()).isEqualTo(MAIN_COMPONENT_UUID_1); | |||
assertThat(saved.getStatus()).isEqualTo(PENDING); | |||
assertThat(saved.getSubmitterUuid()).isEqualTo(SUBMITTER_LOGIN); | |||
assertThat(saved.getWorkerUuid()).isNull(); | |||
@@ -110,7 +111,7 @@ public class CeQueueDaoTest { | |||
CeQueueDto saved = underTest.selectByUuid(db.getSession(), uuid4).get(); | |||
assertThat(saved.getUuid()).isEqualTo(uuid4); | |||
assertThat(saved.getTaskType()).isEqualTo(CeTaskTypes.REPORT); | |||
assertThat(saved.getComponentUuid()).isEqualTo(COMPONENT_UUID_1); | |||
assertThat(saved.getComponentUuid()).isEqualTo(MAIN_COMPONENT_UUID_1); | |||
assertThat(saved.getStatus()).isEqualTo(PENDING); | |||
assertThat(saved.getSubmitterUuid()).isEqualTo(SUBMITTER_LOGIN); | |||
assertThat(saved.getWorkerUuid()).isNull(); | |||
@@ -121,13 +122,14 @@ public class CeQueueDaoTest { | |||
@Test | |||
public void test_selectByUuid() { | |||
insertPending(TASK_UUID_1, COMPONENT_UUID_1); | |||
CeQueueDto ceQueueDto = insertPending(TASK_UUID_1, MAIN_COMPONENT_UUID_1); | |||
assertThat(underTest.selectByUuid(db.getSession(), "TASK_UNKNOWN").isPresent()).isFalse(); | |||
CeQueueDto saved = underTest.selectByUuid(db.getSession(), TASK_UUID_1).get(); | |||
assertThat(saved.getUuid()).isEqualTo(TASK_UUID_1); | |||
assertThat(saved.getTaskType()).isEqualTo(CeTaskTypes.REPORT); | |||
assertThat(saved.getComponentUuid()).isEqualTo(COMPONENT_UUID_1); | |||
assertThat(saved.getMainComponentUuid()).isEqualTo(MAIN_COMPONENT_UUID_1); | |||
assertThat(saved.getComponentUuid()).isEqualTo(ceQueueDto.getComponentUuid()); | |||
assertThat(saved.getStatus()).isEqualTo(PENDING); | |||
assertThat(saved.getSubmitterUuid()).isEqualTo("henri"); | |||
assertThat(saved.getWorkerUuid()).isNull(); | |||
@@ -137,20 +139,20 @@ public class CeQueueDaoTest { | |||
} | |||
@Test | |||
public void test_selectByComponentUuid() { | |||
insertPending(TASK_UUID_1, COMPONENT_UUID_1); | |||
insertPending(TASK_UUID_2, COMPONENT_UUID_1); | |||
public void test_selectByMainComponentUuid() { | |||
insertPending(TASK_UUID_1, MAIN_COMPONENT_UUID_1); | |||
insertPending(TASK_UUID_2, MAIN_COMPONENT_UUID_1); | |||
insertPending(TASK_UUID_3, "PROJECT_2"); | |||
assertThat(underTest.selectByComponentUuid(db.getSession(), "UNKNOWN")).isEmpty(); | |||
assertThat(underTest.selectByComponentUuid(db.getSession(), COMPONENT_UUID_1)).extracting("uuid").containsOnly(TASK_UUID_1, TASK_UUID_2); | |||
assertThat(underTest.selectByComponentUuid(db.getSession(), "PROJECT_2")).extracting("uuid").containsOnly(TASK_UUID_3); | |||
assertThat(underTest.selectByMainComponentUuid(db.getSession(), "UNKNOWN")).isEmpty(); | |||
assertThat(underTest.selectByMainComponentUuid(db.getSession(), MAIN_COMPONENT_UUID_1)).extracting("uuid").containsOnly(TASK_UUID_1, TASK_UUID_2); | |||
assertThat(underTest.selectByMainComponentUuid(db.getSession(), "PROJECT_2")).extracting("uuid").containsOnly(TASK_UUID_3); | |||
} | |||
@Test | |||
public void test_selectAllInAscOrder() { | |||
insertPending(TASK_UUID_1, COMPONENT_UUID_1); | |||
insertPending(TASK_UUID_2, COMPONENT_UUID_1); | |||
insertPending(TASK_UUID_1, MAIN_COMPONENT_UUID_1); | |||
insertPending(TASK_UUID_2, MAIN_COMPONENT_UUID_1); | |||
insertPending(TASK_UUID_3, "PROJECT_2"); | |||
assertThat(underTest.selectAllInAscOrder(db.getSession())).extracting("uuid").containsOnly(TASK_UUID_1, TASK_UUID_2, TASK_UUID_3); | |||
@@ -186,8 +188,8 @@ public class CeQueueDaoTest { | |||
@Test | |||
public void test_delete() { | |||
insertPending(TASK_UUID_1, COMPONENT_UUID_1); | |||
insertPending(TASK_UUID_2, COMPONENT_UUID_1); | |||
insertPending(TASK_UUID_1, MAIN_COMPONENT_UUID_1); | |||
insertPending(TASK_UUID_2, MAIN_COMPONENT_UUID_1); | |||
int deletedCount = underTest.deleteByUuid(db.getSession(), "UNKNOWN"); | |||
assertThat(deletedCount).isEqualTo(0); | |||
@@ -204,8 +206,8 @@ public class CeQueueDaoTest { | |||
@Test | |||
public void test_delete_with_expected_status() { | |||
insertPending(TASK_UUID_1, COMPONENT_UUID_1); | |||
insertInProgress(TASK_UUID_2, COMPONENT_UUID_1); | |||
insertPending(TASK_UUID_1, MAIN_COMPONENT_UUID_1); | |||
insertInProgress(TASK_UUID_2, MAIN_COMPONENT_UUID_1); | |||
int deletedCount = underTest.deleteByUuid(db.getSession(), "UNKNOWN", null); | |||
assertThat(deletedCount).isEqualTo(0); | |||
@@ -340,15 +342,15 @@ public class CeQueueDaoTest { | |||
assertThat(underTest.peek(db.getSession(), WORKER_UUID_1).isPresent()).isFalse(); | |||
// not pending, but in progress | |||
makeInProgress(WORKER_UUID_1, 2_232_222L, insertPending(TASK_UUID_1, COMPONENT_UUID_1)); | |||
makeInProgress(WORKER_UUID_1, 2_232_222L, insertPending(TASK_UUID_1, MAIN_COMPONENT_UUID_1)); | |||
assertThat(underTest.peek(db.getSession(), WORKER_UUID_1).isPresent()).isFalse(); | |||
} | |||
@Test | |||
public void peek_oldest_pending() { | |||
insertPending(TASK_UUID_1, COMPONENT_UUID_1); | |||
insertPending(TASK_UUID_1, MAIN_COMPONENT_UUID_1); | |||
system2.setNow(INIT_TIME + 3_000_000); | |||
insertPending(TASK_UUID_2, COMPONENT_UUID_2); | |||
insertPending(TASK_UUID_2, MAIN_COMPONENT_UUID_2); | |||
assertThat(db.countRowsOfTable("ce_queue")).isEqualTo(2); | |||
verifyCeQueueStatuses(TASK_UUID_1, PENDING, TASK_UUID_2, PENDING); | |||
@@ -374,15 +376,16 @@ public class CeQueueDaoTest { | |||
} | |||
@Test | |||
public void do_not_peek_multiple_tasks_on_same_project_at_the_same_time() { | |||
public void do_not_peek_multiple_tasks_on_same_main_component_at_the_same_time() { | |||
// two pending tasks on the same project | |||
insertPending(TASK_UUID_1, COMPONENT_UUID_1); | |||
insertPending(TASK_UUID_1, MAIN_COMPONENT_UUID_1); | |||
system2.setNow(INIT_TIME + 3_000_000); | |||
insertPending(TASK_UUID_2, COMPONENT_UUID_1); | |||
insertPending(TASK_UUID_2, MAIN_COMPONENT_UUID_1); | |||
Optional<CeQueueDto> peek = underTest.peek(db.getSession(), WORKER_UUID_1); | |||
assertThat(peek).isPresent(); | |||
assertThat(peek.get().getUuid()).isEqualTo(TASK_UUID_1); | |||
assertThat(peek.get().getMainComponentUuid()).isEqualTo(MAIN_COMPONENT_UUID_1); | |||
assertThat(peek.get().getWorkerUuid()).isEqualTo(WORKER_UUID_1); | |||
verifyCeQueueStatuses(TASK_UUID_1, IN_PROGRESS, TASK_UUID_2, PENDING); | |||
@@ -401,42 +404,42 @@ public class CeQueueDaoTest { | |||
public void select_by_query() { | |||
// task status not in query | |||
insertPending(newCeQueueDto(TASK_UUID_1) | |||
.setComponentUuid(COMPONENT_UUID_1) | |||
.setMainComponentUuid(MAIN_COMPONENT_UUID_1) | |||
.setStatus(IN_PROGRESS) | |||
.setTaskType(CeTaskTypes.REPORT) | |||
.setCreatedAt(100_000L)); | |||
// too early | |||
insertPending(newCeQueueDto(TASK_UUID_3) | |||
.setComponentUuid(COMPONENT_UUID_1) | |||
.setMainComponentUuid(MAIN_COMPONENT_UUID_1) | |||
.setStatus(PENDING) | |||
.setTaskType(CeTaskTypes.REPORT) | |||
.setCreatedAt(90_000L)); | |||
// task type not in query | |||
insertPending(newCeQueueDto("TASK_4") | |||
.setComponentUuid("PROJECT_2") | |||
.setMainComponentUuid("PROJECT_2") | |||
.setStatus(PENDING) | |||
.setTaskType("ANOTHER_TYPE") | |||
.setCreatedAt(100_000L)); | |||
// correct | |||
insertPending(newCeQueueDto(TASK_UUID_2) | |||
.setComponentUuid(COMPONENT_UUID_1) | |||
.setMainComponentUuid(MAIN_COMPONENT_UUID_1) | |||
.setStatus(PENDING) | |||
.setTaskType(CeTaskTypes.REPORT) | |||
.setCreatedAt(100_000L)); | |||
// correct submitted later | |||
insertPending(newCeQueueDto("TASK_5") | |||
.setComponentUuid(COMPONENT_UUID_1) | |||
.setMainComponentUuid(MAIN_COMPONENT_UUID_1) | |||
.setStatus(PENDING) | |||
.setTaskType(CeTaskTypes.REPORT) | |||
.setCreatedAt(120_000L)); | |||
// select by component uuid, status, task type and minimum submitted at | |||
CeTaskQuery query = new CeTaskQuery() | |||
.setComponentUuids(newArrayList(COMPONENT_UUID_1, "PROJECT_2")) | |||
.setMainComponentUuids(newArrayList(MAIN_COMPONENT_UUID_1, "PROJECT_2")) | |||
.setStatuses(singletonList(PENDING.name())) | |||
.setType(CeTaskTypes.REPORT) | |||
.setMinSubmittedAt(100_000L); | |||
@@ -451,7 +454,7 @@ public class CeQueueDaoTest { | |||
@Test | |||
public void select_by_query_returns_empty_list_when_only_current() { | |||
insertPending(newCeQueueDto(TASK_UUID_1) | |||
.setComponentUuid(COMPONENT_UUID_1) | |||
.setComponentUuid(MAIN_COMPONENT_UUID_1) | |||
.setStatus(IN_PROGRESS) | |||
.setTaskType(CeTaskTypes.REPORT) | |||
.setCreatedAt(100_000L)); | |||
@@ -468,7 +471,7 @@ public class CeQueueDaoTest { | |||
@Test | |||
public void select_by_query_returns_empty_list_when_max_submitted_at() { | |||
insertPending(newCeQueueDto(TASK_UUID_1) | |||
.setComponentUuid(COMPONENT_UUID_1) | |||
.setComponentUuid(MAIN_COMPONENT_UUID_1) | |||
.setStatus(IN_PROGRESS) | |||
.setTaskType(CeTaskTypes.REPORT) | |||
.setCreatedAt(100_000L)); | |||
@@ -483,14 +486,14 @@ public class CeQueueDaoTest { | |||
} | |||
@Test | |||
public void select_by_query_returns_empty_list_when_empty_list_of_component_uuid() { | |||
public void select_by_query_returns_empty_list_when_empty_list_of_main_component_uuid() { | |||
insertPending(newCeQueueDto(TASK_UUID_1) | |||
.setComponentUuid(COMPONENT_UUID_1) | |||
.setComponentUuid(MAIN_COMPONENT_UUID_1) | |||
.setStatus(IN_PROGRESS) | |||
.setTaskType(CeTaskTypes.REPORT) | |||
.setCreatedAt(100_000L)); | |||
CeTaskQuery query = new CeTaskQuery().setComponentUuids(Collections.emptyList()); | |||
CeTaskQuery query = new CeTaskQuery().setMainComponentUuids(Collections.emptyList()); | |||
List<CeQueueDto> result = underTest.selectByQueryInDescOrder(db.getSession(), query, 1_000); | |||
int total = underTest.countByQuery(db.getSession(), query); | |||
@@ -500,57 +503,57 @@ public class CeQueueDaoTest { | |||
} | |||
@Test | |||
public void count_by_status_and_component_uuid() { | |||
public void count_by_status_and_main_component_uuid() { | |||
// task retrieved in the queue | |||
insertPending(newCeQueueDto(TASK_UUID_1) | |||
.setComponentUuid(COMPONENT_UUID_1) | |||
.setMainComponentUuid(MAIN_COMPONENT_UUID_1) | |||
.setStatus(IN_PROGRESS) | |||
.setTaskType(CeTaskTypes.REPORT) | |||
.setCreatedAt(100_000L)); | |||
// on component uuid 2, not returned | |||
insertPending(newCeQueueDto(TASK_UUID_2) | |||
.setComponentUuid(COMPONENT_UUID_2) | |||
.setMainComponentUuid(MAIN_COMPONENT_UUID_2) | |||
.setStatus(IN_PROGRESS) | |||
.setTaskType(CeTaskTypes.REPORT) | |||
.setCreatedAt(100_000L)); | |||
// pending status, not returned | |||
insertPending(newCeQueueDto(TASK_UUID_3) | |||
.setComponentUuid(COMPONENT_UUID_1) | |||
.setMainComponentUuid(MAIN_COMPONENT_UUID_1) | |||
.setStatus(PENDING) | |||
.setTaskType(CeTaskTypes.REPORT) | |||
.setCreatedAt(100_000L)); | |||
assertThat(underTest.countByStatusAndComponentUuid(db.getSession(), IN_PROGRESS, COMPONENT_UUID_1)).isEqualTo(1); | |||
assertThat(underTest.countByStatusAndMainComponentUuid(db.getSession(), IN_PROGRESS, MAIN_COMPONENT_UUID_1)).isEqualTo(1); | |||
assertThat(underTest.countByStatus(db.getSession(), IN_PROGRESS)).isEqualTo(2); | |||
} | |||
@Test | |||
public void count_by_status_and_component_uuids() { | |||
public void count_by_status_and_main_component_uuids() { | |||
// task retrieved in the queue | |||
insertPending(newCeQueueDto(TASK_UUID_1) | |||
.setComponentUuid(COMPONENT_UUID_1) | |||
.setMainComponentUuid(MAIN_COMPONENT_UUID_1) | |||
.setStatus(IN_PROGRESS) | |||
.setTaskType(CeTaskTypes.REPORT) | |||
.setCreatedAt(100_000L)); | |||
// on component uuid 2, not returned | |||
insertPending(newCeQueueDto(TASK_UUID_2) | |||
.setComponentUuid(COMPONENT_UUID_2) | |||
.setMainComponentUuid(MAIN_COMPONENT_UUID_2) | |||
.setStatus(IN_PROGRESS) | |||
.setTaskType(CeTaskTypes.REPORT) | |||
.setCreatedAt(100_000L)); | |||
// pending status, not returned | |||
insertPending(newCeQueueDto(TASK_UUID_3) | |||
.setComponentUuid(COMPONENT_UUID_1) | |||
.setMainComponentUuid(MAIN_COMPONENT_UUID_1) | |||
.setStatus(PENDING) | |||
.setTaskType(CeTaskTypes.REPORT) | |||
.setCreatedAt(100_000L)); | |||
assertThat(underTest.countByStatusAndComponentUuids(db.getSession(), IN_PROGRESS, ImmutableSet.of())).isEmpty(); | |||
assertThat(underTest.countByStatusAndComponentUuids(db.getSession(), IN_PROGRESS, ImmutableSet.of("non existing component uuid"))).isEmpty(); | |||
assertThat(underTest.countByStatusAndComponentUuids(db.getSession(), IN_PROGRESS, ImmutableSet.of(COMPONENT_UUID_1, COMPONENT_UUID_2))) | |||
.containsOnly(entry(COMPONENT_UUID_1, 1), entry(COMPONENT_UUID_2, 1)); | |||
assertThat(underTest.countByStatusAndComponentUuids(db.getSession(), PENDING, ImmutableSet.of(COMPONENT_UUID_1, COMPONENT_UUID_2))) | |||
.containsOnly(entry(COMPONENT_UUID_1, 1)); | |||
assertThat(underTest.countByStatusAndMainComponentUuids(db.getSession(), IN_PROGRESS, ImmutableSet.of())).isEmpty(); | |||
assertThat(underTest.countByStatusAndMainComponentUuids(db.getSession(), IN_PROGRESS, ImmutableSet.of("non existing component uuid"))).isEmpty(); | |||
assertThat(underTest.countByStatusAndMainComponentUuids(db.getSession(), IN_PROGRESS, ImmutableSet.of(MAIN_COMPONENT_UUID_1, MAIN_COMPONENT_UUID_2))) | |||
.containsOnly(entry(MAIN_COMPONENT_UUID_1, 1), entry(MAIN_COMPONENT_UUID_2, 1)); | |||
assertThat(underTest.countByStatusAndMainComponentUuids(db.getSession(), PENDING, ImmutableSet.of(MAIN_COMPONENT_UUID_1, MAIN_COMPONENT_UUID_2))) | |||
.containsOnly(entry(MAIN_COMPONENT_UUID_1, 1)); | |||
assertThat(underTest.countByStatus(db.getSession(), IN_PROGRESS)).isEqualTo(2); | |||
} | |||
@@ -570,11 +573,13 @@ public class CeQueueDaoTest { | |||
return dto; | |||
} | |||
private CeQueueDto insertPending(String uuid, String componentUuid) { | |||
private int pendingComponentUuidGenerator = new Random().nextInt(200); | |||
private CeQueueDto insertPending(String uuid, String mainComponentUuid) { | |||
CeQueueDto dto = new CeQueueDto(); | |||
dto.setUuid(uuid); | |||
dto.setTaskType(CeTaskTypes.REPORT); | |||
dto.setComponentUuid(componentUuid); | |||
dto.setMainComponentUuid(mainComponentUuid); | |||
dto.setComponentUuid("uuid_" + pendingComponentUuidGenerator++); | |||
dto.setStatus(PENDING); | |||
dto.setSubmitterUuid("henri"); | |||
underTest.insert(db.getSession(), dto); |
@@ -47,11 +47,29 @@ public class CeQueueDtoTest { | |||
String str_41_chars = STR_40_CHARS + "a"; | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("Value of component UUID is too long: " + str_41_chars); | |||
expectedException.expectMessage("Value is too long for column CE_QUEUE.COMPONENT_UUID: " + str_41_chars); | |||
underTest.setComponentUuid(str_41_chars); | |||
} | |||
@Test | |||
public void setMainComponentUuid_accepts_null_empty_and_string_40_chars_or_less() { | |||
underTest.setMainComponentUuid(null); | |||
underTest.setMainComponentUuid(""); | |||
underTest.setMainComponentUuid("bar"); | |||
underTest.setMainComponentUuid(STR_40_CHARS); | |||
} | |||
@Test | |||
public void setMainComponentUuid_throws_IAE_if_value_is_41_chars() { | |||
String str_41_chars = STR_40_CHARS + "a"; | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("Value is too long for column CE_QUEUE.MAIN_COMPONENT_UUID: " + str_41_chars); | |||
underTest.setMainComponentUuid(str_41_chars); | |||
} | |||
@Test | |||
public void setTaskType_throws_NPE_if_argument_is_null() { | |||
expectedException.expect(NullPointerException.class); |
@@ -38,6 +38,7 @@ public class CeQueueTesting { | |||
return new CeQueueDto() | |||
.setUuid(uuid) | |||
.setComponentUuid(randomAlphanumeric(40)) | |||
.setMainComponentUuid(randomAlphanumeric(39)) | |||
.setStatus(CeQueueDto.Status.PENDING) | |||
.setTaskType(CeTaskTypes.REPORT) | |||
.setSubmitterUuid(randomAlphanumeric(255)) |
@@ -33,22 +33,22 @@ public class CeTaskQueryTest { | |||
@Test | |||
public void no_filter_on_component_uuids_by_default() { | |||
assertThat(underTest.getComponentUuids()).isNull(); | |||
assertThat(underTest.isShortCircuitedByComponentUuids()).isFalse(); | |||
assertThat(underTest.getMainComponentUuids()).isNull(); | |||
assertThat(underTest.isShortCircuitedByMainComponentUuids()).isFalse(); | |||
} | |||
@Test | |||
public void filter_on_component_uuid() { | |||
underTest.setComponentUuid("UUID1"); | |||
assertThat(underTest.getComponentUuids()).containsOnly("UUID1"); | |||
assertThat(underTest.isShortCircuitedByComponentUuids()).isFalse(); | |||
underTest.setMainComponentUuid("UUID1"); | |||
assertThat(underTest.getMainComponentUuids()).containsOnly("UUID1"); | |||
assertThat(underTest.isShortCircuitedByMainComponentUuids()).isFalse(); | |||
} | |||
@Test | |||
public void filter_on_multiple_component_uuids() { | |||
underTest.setComponentUuids(asList("UUID1", "UUID2")); | |||
assertThat(underTest.getComponentUuids()).containsOnly("UUID1", "UUID2"); | |||
assertThat(underTest.isShortCircuitedByComponentUuids()).isFalse(); | |||
underTest.setMainComponentUuids(asList("UUID1", "UUID2")); | |||
assertThat(underTest.getMainComponentUuids()).containsOnly("UUID1", "UUID2"); | |||
assertThat(underTest.isShortCircuitedByMainComponentUuids()).isFalse(); | |||
} | |||
/** | |||
@@ -57,9 +57,9 @@ public class CeTaskQueryTest { | |||
*/ | |||
@Test | |||
public void short_circuited_if_empty_component_uuid_filter() { | |||
underTest.setComponentUuids(Collections.emptyList()); | |||
assertThat(underTest.getComponentUuids()).isEmpty(); | |||
assertThat(underTest.isShortCircuitedByComponentUuids()).isTrue(); | |||
underTest.setMainComponentUuids(Collections.emptyList()); | |||
assertThat(underTest.getMainComponentUuids()).isEmpty(); | |||
assertThat(underTest.isShortCircuitedByMainComponentUuids()).isTrue(); | |||
} | |||
/** | |||
@@ -72,8 +72,8 @@ public class CeTaskQueryTest { | |||
for (int i = 0; i < CeTaskQuery.MAX_COMPONENT_UUIDS + 2; i++) { | |||
uuids.add(String.valueOf(i)); | |||
} | |||
underTest.setComponentUuids(uuids); | |||
assertThat(underTest.getComponentUuids()).hasSize(CeTaskQuery.MAX_COMPONENT_UUIDS + 2); | |||
assertThat(underTest.isShortCircuitedByComponentUuids()).isTrue(); | |||
underTest.setMainComponentUuids(uuids); | |||
assertThat(underTest.getMainComponentUuids()).hasSize(CeTaskQuery.MAX_COMPONENT_UUIDS + 2); | |||
assertThat(underTest.isShortCircuitedByMainComponentUuids()).isTrue(); | |||
} | |||
} |
@@ -63,6 +63,7 @@ import org.sonar.db.source.FileSourceDto; | |||
import org.sonar.db.webhook.WebhookDeliveryLiteDto; | |||
import org.sonar.db.webhook.WebhookDto; | |||
import static com.google.common.base.MoreObjects.firstNonNull; | |||
import static java.util.Arrays.asList; | |||
import static java.util.Collections.emptyList; | |||
import static java.util.Collections.singletonList; | |||
@@ -905,6 +906,7 @@ public class PurgeDaoTest { | |||
queueDto.setUuid(Uuids.create()); | |||
queueDto.setTaskType(REPORT); | |||
queueDto.setComponentUuid(component.uuid()); | |||
queueDto.setMainComponentUuid(firstNonNull(component.getMainBranchProjectUuid(), component.uuid())); | |||
queueDto.setSubmitterUuid("submitter uuid"); | |||
queueDto.setCreatedAt(1_300_000_000_000L); | |||
queueDto.setStatus(status); | |||
@@ -929,6 +931,7 @@ public class PurgeDaoTest { | |||
.setUuid(UuidFactoryFast.getInstance().create()) | |||
.setTaskType("foo") | |||
.setComponentUuid(project.uuid()) | |||
.setMainComponentUuid(firstNonNull(project.getMainBranchProjectUuid(), project.uuid())) | |||
.setStatus(Status.PENDING) | |||
.setCreatedAt(1_2323_222L) | |||
.setUpdatedAt(1_2323_222L); |
@@ -0,0 +1,31 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 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.server.platform.db.migration.version.v74; | |||
import org.sonar.db.Database; | |||
import org.sonar.server.platform.db.migration.SupportsBlueGreen; | |||
@SupportsBlueGreen | |||
public class AddTmpColumnsToCeActivity extends AddTmpColumnsToCeTable { | |||
public AddTmpColumnsToCeActivity(Database db) { | |||
super(db, "ce_activity"); | |||
} | |||
} |
@@ -0,0 +1,31 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 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.server.platform.db.migration.version.v74; | |||
import org.sonar.db.Database; | |||
import org.sonar.server.platform.db.migration.SupportsBlueGreen; | |||
@SupportsBlueGreen | |||
public class AddTmpColumnsToCeQueue extends AddTmpColumnsToCeTable { | |||
public AddTmpColumnsToCeQueue(Database db) { | |||
super(db, "ce_queue"); | |||
} | |||
} |
@@ -0,0 +1,70 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 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.server.platform.db.migration.version.v74; | |||
import java.sql.SQLException; | |||
import org.sonar.db.Database; | |||
import org.sonar.server.platform.db.migration.def.VarcharColumnDef; | |||
import org.sonar.server.platform.db.migration.sql.AddColumnsBuilder; | |||
import org.sonar.server.platform.db.migration.sql.CreateIndexBuilder; | |||
import org.sonar.server.platform.db.migration.step.DdlChange; | |||
import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.newVarcharColumnDefBuilder; | |||
abstract class AddTmpColumnsToCeTable extends DdlChange { | |||
private static final VarcharColumnDef COLUMN_TMP_COMPONENT_UUID = newVarcharColumnDefBuilder() | |||
.setColumnName("tmp_component_uuid") | |||
.setLimit(VarcharColumnDef.UUID_SIZE) | |||
.setIsNullable(true) | |||
.build(); | |||
private static final VarcharColumnDef COLUMN_TMP_MAIN_COMPONENT_UUID = newVarcharColumnDefBuilder() | |||
.setColumnName("tmp_main_component_uuid") | |||
.setLimit(VarcharColumnDef.UUID_SIZE) | |||
.setIsNullable(true) | |||
.build(); | |||
private final String tableName; | |||
public AddTmpColumnsToCeTable(Database db, String tableName) { | |||
super(db); | |||
this.tableName = tableName; | |||
} | |||
@Override | |||
public void execute(Context context) throws SQLException { | |||
context.execute(new AddColumnsBuilder(getDialect(), tableName) | |||
.addColumn(COLUMN_TMP_MAIN_COMPONENT_UUID) | |||
.addColumn(COLUMN_TMP_COMPONENT_UUID) | |||
.build()); | |||
// create indexes | |||
context.execute(new CreateIndexBuilder(getDialect()) | |||
.setTable(tableName) | |||
.setName(tableName + "_tmp_cpnt_uuid") | |||
.addColumn(COLUMN_TMP_COMPONENT_UUID) | |||
.setUnique(false) | |||
.build()); | |||
context.execute(new CreateIndexBuilder(getDialect()) | |||
.setTable(tableName) | |||
.setName(tableName + "_tmp_main_cpnt_uuid") | |||
.addColumn(COLUMN_TMP_MAIN_COMPONENT_UUID) | |||
.setUnique(false) | |||
.build()); | |||
} | |||
} |
@@ -0,0 +1,105 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 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.server.platform.db.migration.version.v74; | |||
import java.sql.SQLException; | |||
import org.sonar.db.Database; | |||
import org.sonar.server.platform.db.migration.SupportsBlueGreen; | |||
import org.sonar.server.platform.db.migration.def.BooleanColumnDef; | |||
import org.sonar.server.platform.db.migration.def.VarcharColumnDef; | |||
import org.sonar.server.platform.db.migration.sql.AddColumnsBuilder; | |||
import org.sonar.server.platform.db.migration.sql.CreateIndexBuilder; | |||
import org.sonar.server.platform.db.migration.step.DdlChange; | |||
import static org.sonar.server.platform.db.migration.def.BooleanColumnDef.newBooleanColumnDefBuilder; | |||
import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.UUID_SIZE; | |||
import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.newVarcharColumnDefBuilder; | |||
@SupportsBlueGreen | |||
public class AddTmpLastKeyColumnsToCeActivity extends DdlChange { | |||
private static final String TABLE_NAME = "ce_activity"; | |||
private static final int TASK_TYPE_COLUMN_SIZE = 15; | |||
private static final BooleanColumnDef COLUMN_TMP_IS_LAST = newBooleanColumnDefBuilder() | |||
.setColumnName("tmp_is_last") | |||
.setIsNullable(true) | |||
.build(); | |||
private static final VarcharColumnDef COLUMN_TMP_IS_LAST_KEY = newVarcharColumnDefBuilder() | |||
.setColumnName("tmp_is_last_key") | |||
.setLimit(UUID_SIZE + TASK_TYPE_COLUMN_SIZE) | |||
.setIsNullable(true) | |||
.build(); | |||
private static final BooleanColumnDef COLUMN_TMP_MAIN_IS_LAST = newBooleanColumnDefBuilder() | |||
.setColumnName("tmp_main_is_last") | |||
.setIsNullable(true) | |||
.build(); | |||
private static final VarcharColumnDef COLUMN_TMP_MAIN_IS_LAST_KEY = newVarcharColumnDefBuilder() | |||
.setColumnName("tmp_main_is_last_key") | |||
.setLimit(UUID_SIZE + TASK_TYPE_COLUMN_SIZE) | |||
.setIsNullable(true) | |||
.build(); | |||
private static final VarcharColumnDef COLUMN_STATUS = newVarcharColumnDefBuilder() | |||
.setColumnName("status") | |||
.setLimit(15) | |||
.setIsNullable(false) | |||
.build(); | |||
public AddTmpLastKeyColumnsToCeActivity(Database db) { | |||
super(db); | |||
} | |||
@Override | |||
public void execute(Context context) throws SQLException { | |||
context.execute(new AddColumnsBuilder(getDialect(), TABLE_NAME) | |||
.addColumn(COLUMN_TMP_IS_LAST) | |||
.addColumn(COLUMN_TMP_IS_LAST_KEY) | |||
.addColumn(COLUMN_TMP_MAIN_IS_LAST) | |||
.addColumn(COLUMN_TMP_MAIN_IS_LAST_KEY) | |||
.build()); | |||
// create indexes | |||
context.execute(new CreateIndexBuilder(getDialect()) | |||
.setTable(TABLE_NAME) | |||
.setName(TABLE_NAME + "_t_islast_key") | |||
.addColumn(COLUMN_TMP_IS_LAST_KEY) | |||
.setUnique(false) | |||
.build()); | |||
context.execute(new CreateIndexBuilder(getDialect()) | |||
.setTable(TABLE_NAME) | |||
.setName(TABLE_NAME + "_t_islast") | |||
.addColumn(COLUMN_TMP_IS_LAST) | |||
.addColumn(COLUMN_STATUS) | |||
.setUnique(false) | |||
.build()); | |||
context.execute(new CreateIndexBuilder(getDialect()) | |||
.setTable(TABLE_NAME) | |||
.setName(TABLE_NAME + "_t_main_islast_key") | |||
.addColumn(COLUMN_TMP_MAIN_IS_LAST_KEY) | |||
.setUnique(false) | |||
.build()); | |||
context.execute(new CreateIndexBuilder(getDialect()) | |||
.setTable(TABLE_NAME) | |||
.setName(TABLE_NAME + "_t_main_islast") | |||
.addColumn(COLUMN_TMP_MAIN_IS_LAST) | |||
.addColumn(COLUMN_STATUS) | |||
.setUnique(false) | |||
.build()); | |||
} | |||
} |
@@ -32,6 +32,12 @@ public class DbVersion74 implements DbVersion { | |||
.add(2302, "Populate IS_AD_HOC in RULES", PopulateIsAdHocOnRules.class) | |||
.add(2303, "Set IS_EXTERNAL and IS_AD_HOC not nullable in RULES", SetIsExternalAndIsAdHocNotNullableInRules.class) | |||
.add(2304, "Add ad hoc related columns in RULES_METADATA", AddAdHocColumnsInInRulesMetadata.class) | |||
.add(2305, "Add CE_QUEUE.MAIN_COMPONENT_UUID 1/5", AddTmpColumnsToCeQueue.class) | |||
.add(2306, "Add CE_ACTIVITY.MAIN_COMPONENT_UUID 1/5", AddTmpColumnsToCeActivity.class) | |||
.add(2307, "Populate CE_QUEUE.MAIN_COMPONENT_UUID 2/5", PopulateTmpColumnsToCeQueue.class) | |||
.add(2308, "Populate CE_ACTIVITY.MAIN_COMPONENT_UUID 2/5", PopulateTmpColumnsToCeActivity.class) | |||
.add(2309, "Add CE_ACTIVITY.MAIN_LAST_KEY 1/6", AddTmpLastKeyColumnsToCeActivity.class) | |||
.add(2310, "Populate CE_ACTIVITY.MAIN_LAST_KEY 2/6", PopulateTmpLastKeyColumnsToCeActivity.class) | |||
; | |||
} | |||
} |
@@ -0,0 +1,104 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 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.server.platform.db.migration.version.v74; | |||
import java.sql.SQLException; | |||
import org.sonar.api.config.Configuration; | |||
import org.sonar.db.Database; | |||
import org.sonar.server.platform.db.migration.SupportsBlueGreen; | |||
import org.sonar.server.platform.db.migration.step.DataChange; | |||
import org.sonar.server.platform.db.migration.step.MassUpdate; | |||
import org.sonar.server.platform.db.migration.step.Select; | |||
import org.sonar.server.platform.db.migration.step.SqlStatement; | |||
@SupportsBlueGreen | |||
public class PopulateTmpColumnsToCeActivity extends DataChange { | |||
private final Configuration configuration; | |||
public PopulateTmpColumnsToCeActivity(Database db, Configuration configuration) { | |||
super(db); | |||
this.configuration = configuration; | |||
} | |||
@Override | |||
protected void execute(Context context) throws SQLException { | |||
if (configuration.getBoolean("sonar.sonarcloud.enabled").orElse(false)) { | |||
// data migration will be done in background so that interruption of service | |||
// is reduced during upgrade | |||
return; | |||
} | |||
// activity of long and short branches | |||
populateCeActivityTmpColumns(context, "Archived tasks of branches", | |||
"select" + | |||
" cea.uuid, p.uuid, cea.component_uuid" + | |||
" from ce_activity cea" + | |||
" inner join projects mp on mp.uuid = cea.component_uuid" + | |||
" inner join ce_task_characteristics ctc1 on ctc1.task_uuid = cea.uuid and ctc1.kee = 'branchType'" + | |||
" inner join ce_task_characteristics ctc2 on ctc2.task_uuid = cea.uuid and ctc2.kee = 'branch'" + | |||
" inner join projects p on p.kee = concat(mp.kee, ':BRANCH:', ctc2.text_value)" + | |||
" where" + | |||
" cea.component_uuid is not null" + | |||
" and (cea.tmp_component_uuid is null or cea.tmp_main_component_uuid is null)"); | |||
// activity of PRs | |||
populateCeActivityTmpColumns(context, "Archived tasks of PRs", | |||
"select" + | |||
" cea.uuid, p.uuid, cea.component_uuid" + | |||
" from ce_activity cea" + | |||
" inner join projects mp on mp.uuid = cea.component_uuid " + | |||
" inner join ce_task_characteristics ctc1 on ctc1.task_uuid = cea.uuid and ctc1.kee = 'pullRequest'" + | |||
" inner join projects p on p.kee = concat(mp.kee, ':PULL_REQUEST:', ctc1.text_value)" + | |||
" where" + | |||
" cea.component_uuid is not null" + | |||
" and (cea.tmp_component_uuid is null or cea.tmp_main_component_uuid is null)"); | |||
// all activities which tmp columns are not populated yet (will include main and deprecated branches) | |||
// both tmp columns will be set to CE_ACTIVITY.COMPONENT_UUID | |||
// do not join on PROJECTS to also catch orphans | |||
populateCeActivityTmpColumns(context, "Archived tasks of main and deprecated branches", | |||
"select" + | |||
" cea.uuid, cea.component_uuid, cea.component_uuid" + | |||
" from ce_activity cea" + | |||
" where" + | |||
" cea.component_uuid is not null" + | |||
" and (cea.tmp_component_uuid is null or cea.tmp_main_component_uuid is null)"); | |||
} | |||
private static void populateCeActivityTmpColumns(Context context, String rowPluralName, String sql) throws SQLException { | |||
MassUpdate massUpdate = context.prepareMassUpdate(); | |||
massUpdate.select(sql); | |||
massUpdate.update("update ce_activity set tmp_component_uuid=?, tmp_main_component_uuid=? where uuid=?"); | |||
massUpdate.rowPluralName(rowPluralName); | |||
massUpdate.execute(PopulateTmpColumnsToCeActivity::handleUpdate); | |||
} | |||
private static boolean handleUpdate(Select.Row row, SqlStatement update) throws SQLException { | |||
String uuid = row.getString(1); | |||
String componentUuuid = row.getString(2); | |||
String mainComponentUuuid = row.getString(3); | |||
update.setString(1, componentUuuid); | |||
update.setString(2, mainComponentUuuid); | |||
update.setString(3, uuid); | |||
return true; | |||
} | |||
} |
@@ -0,0 +1,135 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 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.server.platform.db.migration.version.v74; | |||
import java.sql.SQLException; | |||
import org.sonar.db.Database; | |||
import org.sonar.server.platform.db.migration.SupportsBlueGreen; | |||
import org.sonar.server.platform.db.migration.step.DataChange; | |||
import org.sonar.server.platform.db.migration.step.MassUpdate; | |||
import org.sonar.server.platform.db.migration.step.Select; | |||
import org.sonar.server.platform.db.migration.step.SqlStatement; | |||
@SupportsBlueGreen | |||
public class PopulateTmpColumnsToCeQueue extends DataChange { | |||
public PopulateTmpColumnsToCeQueue(Database db) { | |||
super(db); | |||
} | |||
@Override | |||
protected void execute(Context context) throws SQLException { | |||
// queued task of long and short branches which have already been analyzed at least once | |||
populateCeQueueTmpColumns(context, "queued tasks of branches", | |||
"select" + | |||
" cq.uuid, p.uuid, cq.component_uuid" + | |||
" from ce_queue cq" + | |||
" inner join projects mp on mp.uuid = cq.component_uuid" + | |||
" inner join ce_task_characteristics ctc1 on ctc1.task_uuid = cq.uuid and ctc1.kee = 'branchType'" + | |||
" inner join ce_task_characteristics ctc2 on ctc2.task_uuid = cq.uuid and ctc2.kee = 'branch'" + | |||
" inner join projects p on p.kee = concat(mp.kee, ':BRANCH:', ctc2.text_value)" + | |||
" where" + | |||
" cq.component_uuid is not null" + | |||
" and (cq.tmp_component_uuid is null or cq.tmp_main_component_uuid is null)"); | |||
// queued task of pull request which have already been analyzed at least once | |||
populateCeQueueTmpColumns(context, "queued tasks of PRs", | |||
" select" + | |||
" cq.uuid, p.uuid, cq.component_uuid" + | |||
" from ce_queue cq" + | |||
" inner join projects mp on mp.uuid = cq.component_uuid " + | |||
" inner join ce_task_characteristics ctc1 on ctc1.task_uuid = cq.uuid and ctc1.kee = 'pullRequest'" + | |||
" inner join projects p on p.kee = concat(mp.kee, ':PULL_REQUEST:', ctc1.text_value)" + | |||
" where" + | |||
" cq.component_uuid is not null" + | |||
" and (cq.tmp_component_uuid is null or cq.tmp_main_component_uuid is null)"); | |||
// queued task of long and short branches which have never been analyzed must be deleted | |||
deleteFromCeQueue(context, "queued tasks of never analyzed branches", | |||
"select" + | |||
" cq.uuid" + | |||
" from ce_queue cq" + | |||
" inner join projects mp on mp.uuid = cq.component_uuid" + | |||
" inner join ce_task_characteristics ctc1 on ctc1.task_uuid = cq.uuid and ctc1.kee = 'branchType'" + | |||
" inner join ce_task_characteristics ctc2 on ctc2.task_uuid = cq.uuid and ctc2.kee = 'branch'" + | |||
" where" + | |||
" cq.component_uuid is not null" + | |||
" and (cq.tmp_component_uuid is null or cq.tmp_main_component_uuid is null)" + | |||
" and not exists (select 1 from projects p where p.kee = concat(mp.kee, ':BRANCH:', ctc2.text_value))"); | |||
// queued of pull request which have never been analyzed must be deleted | |||
deleteFromCeQueue(context, "queued tasks of never analyzed PRs", | |||
"select" + | |||
" cq.uuid" + | |||
" from ce_queue cq" + | |||
" inner join projects mp on mp.uuid = cq.component_uuid " + | |||
" inner join ce_task_characteristics ctc1 on ctc1.task_uuid = cq.uuid and ctc1.kee = 'pullRequest'" + | |||
" where" + | |||
" cq.component_uuid is not null" + | |||
" and (cq.tmp_component_uuid is null or cq.tmp_main_component_uuid is null)" + | |||
" and not exists (select 1 from projects p where p.kee = concat(mp.kee, ':PULL_REQUEST:', ctc1.text_value))"); | |||
// all queue which tmp columns are not populated yet (will include main and deprecated branches) | |||
// both tmp columns will be set to CE_QUEUE.COMPONENT_UUID | |||
// do not join on PROJECTS to also catch orphans (there are many for branch and PRs due to SONAR-10642) | |||
populateCeQueueTmpColumns(context, "queued tasks of main and deprecated branches", | |||
"select" + | |||
" cq.uuid, cq.component_uuid, cq.component_uuid" + | |||
" from ce_queue cq" + | |||
" where" + | |||
" cq.component_uuid is not null" + | |||
" and (cq.tmp_component_uuid is null or cq.tmp_main_component_uuid is null)"); | |||
} | |||
private static void populateCeQueueTmpColumns(Context context, String pluralName, String selectSQL) throws SQLException { | |||
MassUpdate massUpdate = context.prepareMassUpdate(); | |||
massUpdate.select(selectSQL); | |||
massUpdate.update("update ce_queue set tmp_component_uuid=?, tmp_main_component_uuid=? where uuid=?"); | |||
massUpdate.rowPluralName(pluralName); | |||
massUpdate.execute(PopulateTmpColumnsToCeQueue::handleUpdate); | |||
} | |||
private static boolean handleUpdate(Select.Row row, SqlStatement update) throws SQLException { | |||
String uuid = row.getString(1); | |||
String componentUuuid = row.getString(2); | |||
String mainComponentUuuid = row.getString(3); | |||
update.setString(1, componentUuuid); | |||
update.setString(2, mainComponentUuuid); | |||
update.setString(3, uuid); | |||
return true; | |||
} | |||
private static void deleteFromCeQueue(Context context, String pluralName, String sql) throws SQLException { | |||
MassUpdate massUpdate = context.prepareMassUpdate(); | |||
massUpdate.select(sql); | |||
massUpdate.update("delete from ce_queue where uuid = ?"); | |||
massUpdate.rowPluralName(pluralName); | |||
massUpdate.execute(PopulateTmpColumnsToCeQueue::handleDelete); | |||
} | |||
private static boolean handleDelete(Select.Row row, SqlStatement update) throws SQLException { | |||
String uuid = row.getString(1); | |||
update.setString(1, uuid); | |||
return true; | |||
} | |||
} |
@@ -0,0 +1,83 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 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.server.platform.db.migration.version.v74; | |||
import java.sql.SQLException; | |||
import org.sonar.api.config.Configuration; | |||
import org.sonar.db.Database; | |||
import org.sonar.server.platform.db.migration.SupportsBlueGreen; | |||
import org.sonar.server.platform.db.migration.step.DataChange; | |||
import org.sonar.server.platform.db.migration.step.MassUpdate; | |||
import org.sonar.server.platform.db.migration.step.Select; | |||
import org.sonar.server.platform.db.migration.step.SqlStatement; | |||
@SupportsBlueGreen | |||
public class PopulateTmpLastKeyColumnsToCeActivity extends DataChange { | |||
private final Configuration configuration; | |||
public PopulateTmpLastKeyColumnsToCeActivity(Database db, Configuration configuration) { | |||
super(db); | |||
this.configuration = configuration; | |||
} | |||
@Override | |||
protected void execute(Context context) throws SQLException { | |||
if (configuration.getBoolean("sonar.sonarcloud.enabled").orElse(false)) { | |||
// data migration will be done in background so that interruption of service | |||
// is reduced during upgrade | |||
return; | |||
} | |||
MassUpdate massUpdate = context.prepareMassUpdate(); | |||
massUpdate.select("select" + | |||
" cea.uuid, cea.task_type, cea.component_uuid, cea.tmp_component_uuid, cea.tmp_main_component_uuid" + | |||
" from ce_activity cea" + | |||
" where" + | |||
" cea.tmp_is_last is null" + | |||
" or cea.tmp_is_last_key is null" + | |||
" or cea.tmp_main_is_last is null" + | |||
" or cea.tmp_main_is_last_key is null"); | |||
massUpdate.update("update ce_activity" + | |||
" set" + | |||
" tmp_is_last=?" + | |||
" ,tmp_is_last_key=?" + | |||
" ,tmp_main_is_last=?" + | |||
" ,tmp_main_is_last_key=?" + | |||
" where uuid=?"); | |||
massUpdate.rowPluralName("rows of ce_activity"); | |||
massUpdate.execute(PopulateTmpLastKeyColumnsToCeActivity::handleUpdate); | |||
} | |||
private static boolean handleUpdate(Select.Row row, SqlStatement update) throws SQLException { | |||
String uuid = row.getString(1); | |||
String taskType = row.getString(2); | |||
String oldComponentUuid = row.getString(3); | |||
String componentUuuid = row.getString(4); | |||
String mainComponentUuuid = row.getString(5); | |||
update.setBoolean(1, false); | |||
update.setString(2, oldComponentUuid == null ? taskType : (taskType + componentUuuid)); | |||
update.setBoolean(3, false); | |||
update.setString(4, oldComponentUuid == null ? taskType : (taskType + mainComponentUuuid)); | |||
update.setString(5, uuid); | |||
return true; | |||
} | |||
} |
@@ -0,0 +1,56 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 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.server.platform.db.migration.version.v74; | |||
import java.sql.SQLException; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.db.CoreDbTester; | |||
import static java.sql.Types.VARCHAR; | |||
public class AddTmpColumnsToCeActivityTest { | |||
@Rule | |||
public final CoreDbTester db = CoreDbTester.createForSchema(AddTmpColumnsToCeActivityTest.class, "ce_activity.sql"); | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
private AddTmpColumnsToCeActivity underTest = new AddTmpColumnsToCeActivity(db.database()); | |||
@Test | |||
public void columns_and_indexes_are_added_to_table() throws SQLException { | |||
underTest.execute(); | |||
db.assertColumnDefinition("ce_activity", "tmp_component_uuid", VARCHAR, 40, true); | |||
db.assertColumnDefinition("ce_activity", "tmp_main_component_uuid", VARCHAR, 40, true); | |||
db.assertIndex("ce_activity", "ce_activity_tmp_cpnt_uuid", "tmp_component_uuid"); | |||
db.assertIndex("ce_activity", "ce_activity_tmp_main_cpnt_uuid", "tmp_main_component_uuid"); | |||
} | |||
@Test | |||
public void migration_is_not_reentrant() throws SQLException { | |||
underTest.execute(); | |||
expectedException.expect(IllegalStateException.class); | |||
underTest.execute(); | |||
} | |||
} |
@@ -0,0 +1,56 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 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.server.platform.db.migration.version.v74; | |||
import java.sql.SQLException; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.db.CoreDbTester; | |||
import static java.sql.Types.VARCHAR; | |||
public class AddTmpColumnsToCeQueueTest { | |||
@Rule | |||
public final CoreDbTester db = CoreDbTester.createForSchema(AddTmpColumnsToCeQueueTest.class, "ce_queue.sql"); | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
private AddTmpColumnsToCeQueue underTest = new AddTmpColumnsToCeQueue(db.database()); | |||
@Test | |||
public void columns_and_indexes_are_added_to_table() throws SQLException { | |||
underTest.execute(); | |||
db.assertColumnDefinition("ce_queue", "tmp_component_uuid", VARCHAR, 40, true); | |||
db.assertColumnDefinition("ce_queue", "tmp_main_component_uuid", VARCHAR, 40, true); | |||
db.assertIndex("ce_queue", "ce_queue_tmp_cpnt_uuid", "tmp_component_uuid"); | |||
db.assertIndex("ce_queue", "ce_queue_tmp_main_cpnt_uuid", "tmp_main_component_uuid"); | |||
} | |||
@Test | |||
public void migration_is_not_reentrant() throws SQLException { | |||
underTest.execute(); | |||
expectedException.expect(IllegalStateException.class); | |||
underTest.execute(); | |||
} | |||
} |
@@ -0,0 +1,62 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 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.server.platform.db.migration.version.v74; | |||
import java.sql.SQLException; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.db.CoreDbTester; | |||
import static java.sql.Types.BOOLEAN; | |||
import static java.sql.Types.VARCHAR; | |||
public class AddTmpLastKeyColumnsToCeActivityTest { | |||
@Rule | |||
public final CoreDbTester db = CoreDbTester.createForSchema(AddTmpLastKeyColumnsToCeActivityTest.class, "ce_activity.sql"); | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
private AddTmpLastKeyColumnsToCeActivity underTest = new AddTmpLastKeyColumnsToCeActivity(db.database()); | |||
@Test | |||
public void columns_and_indexes_are_added_to_table() throws SQLException { | |||
underTest.execute(); | |||
db.assertColumnDefinition("ce_activity", "tmp_is_last", BOOLEAN, null, true); | |||
db.assertColumnDefinition("ce_activity", "tmp_is_last_key", VARCHAR, 55, true); | |||
db.assertColumnDefinition("ce_activity", "tmp_main_is_last", BOOLEAN, null, true); | |||
db.assertColumnDefinition("ce_activity", "tmp_main_is_last_key", VARCHAR, 55, true); | |||
db.assertIndex("ce_activity", "ce_activity_t_islast_key", "tmp_is_last_key"); | |||
db.assertIndex("ce_activity", "ce_activity_t_main_islast", "tmp_main_is_last", "status"); | |||
db.assertIndex("ce_activity", "ce_activity_t_main_islast_key", "tmp_main_is_last_key"); | |||
db.assertIndex("ce_activity", "ce_activity_t_main_islast", "tmp_main_is_last", "status"); | |||
} | |||
@Test | |||
public void migration_is_not_reentrant() throws SQLException { | |||
underTest.execute(); | |||
expectedException.expect(IllegalStateException.class); | |||
underTest.execute(); | |||
} | |||
} |
@@ -35,6 +35,6 @@ public class DbVersion74Test { | |||
@Test | |||
public void verify_migration_count() { | |||
verifyMigrationCount(underTest, 5); | |||
verifyMigrationCount(underTest, 11); | |||
} | |||
} |
@@ -0,0 +1,233 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 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.server.platform.db.migration.version.v74; | |||
import com.google.common.collect.ImmutableMap; | |||
import com.tngtech.java.junit.dataprovider.DataProvider; | |||
import com.tngtech.java.junit.dataprovider.DataProviderRunner; | |||
import com.tngtech.java.junit.dataprovider.UseDataProvider; | |||
import java.sql.SQLException; | |||
import java.util.Collections; | |||
import java.util.Map; | |||
import java.util.Random; | |||
import java.util.stream.Stream; | |||
import javax.annotation.Nullable; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.runner.RunWith; | |||
import org.sonar.api.config.internal.MapSettings; | |||
import org.sonar.db.CoreDbTester; | |||
import static java.util.Arrays.stream; | |||
import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
@RunWith(DataProviderRunner.class) | |||
public class PopulateTmpColumnsToCeActivityTest { | |||
private static final Map<String, String> NO_CHARACTERISTICS = Collections.emptyMap(); | |||
@Rule | |||
public CoreDbTester db = CoreDbTester.createForSchema(PopulateTmpColumnsToCeActivityTest.class, "ce_activity.sql"); | |||
private MapSettings settings = new MapSettings(); | |||
private PopulateTmpColumnsToCeActivity underTest = new PopulateTmpColumnsToCeActivity(db.database(), settings.asConfig()); | |||
@Test | |||
public void execute_has_no_effect_on_empty_table() throws SQLException { | |||
underTest.execute(); | |||
assertThat(rowsInCeActivity()).isEmpty(); | |||
} | |||
@Test | |||
public void execute_has_no_effect_on_empty_table_on_sonarcloud() throws SQLException { | |||
settings.setProperty("sonar.sonarcloud.enabled", true); | |||
underTest.execute(); | |||
assertThat(rowsInCeActivity()).isEmpty(); | |||
} | |||
@Test | |||
@UseDataProvider("characteriticsOfMainBranchesAndPr") | |||
public void execute_populates_tmp_columns_with_component_uuid_if_task_has_no_row_in_PROJECTS(Map<String, String> characteristics) throws SQLException { | |||
Row[] notUpdatedRows = Stream.of( | |||
// not updated because no component_uuid | |||
new Row(newUuid(), null, null, null), | |||
new Row(newUuid(), null, randomAlphabetic(2), null), | |||
new Row(newUuid(), null, randomAlphabetic(3), randomAlphabetic(4)), | |||
new Row(newUuid(), null, null, randomAlphabetic(5)), | |||
// not updated because both target fields are already set (re-entrance) | |||
new Row(newUuid(), randomAlphabetic(14), randomAlphabetic(6), randomAlphabetic(7))) | |||
.toArray(Row[]::new); | |||
Row[] updatedRows = { | |||
new Row(newUuid(), randomAlphabetic(12), null, null), | |||
new Row(newUuid(), randomAlphabetic(13), randomAlphabetic(5), null), | |||
new Row(newUuid(), randomAlphabetic(14), null, randomAlphabetic(6)), | |||
}; | |||
stream(notUpdatedRows).forEach(row -> insertCeActivity(row, characteristics)); | |||
stream(updatedRows).forEach(row -> insertCeActivity(row, characteristics)); | |||
underTest.execute(); | |||
assertThat(rowsInCeActivity()) | |||
.hasSize(notUpdatedRows.length + updatedRows.length) | |||
.contains(notUpdatedRows) | |||
.contains(stream(updatedRows) | |||
.map(row -> new Row(row.taskUuid, row.componentUuid, row.componentUuid, row.componentUuid)) | |||
.toArray(Row[]::new)); | |||
} | |||
@DataProvider | |||
public static Object[][] characteriticsOfMainBranchesAndPr() { | |||
return new Object[][] { | |||
{NO_CHARACTERISTICS}, | |||
{branchCharacteristics("LONG", randomAlphabetic(15))}, | |||
{branchCharacteristics("SHORT", randomAlphabetic(16))}, | |||
{branchCharacteristics(randomAlphabetic(17), randomAlphabetic(18))}, | |||
{prCharacteristics(randomAlphabetic(19))}, | |||
}; | |||
} | |||
@Test | |||
public void execute_populates_tmp_columns_with_component_uuid_for_existing_main_branch() throws SQLException { | |||
String mainComponentUuid = randomAlphabetic(2); | |||
insertProjects(mainComponentUuid, randomAlphabetic(3)); | |||
String taskUuid = insertCeActivity(new Row(newUuid(), mainComponentUuid, null, null), NO_CHARACTERISTICS); | |||
underTest.execute(); | |||
assertThat(rowsInCeActivity()) | |||
.containsOnly(new Row(taskUuid, mainComponentUuid, mainComponentUuid, mainComponentUuid)); | |||
} | |||
@Test | |||
public void execute_deletes_populates_branches_of_task_without_row_in_PROJECTS_with_COMPONENT_UUID_and_those_with_row_in_PROJECTS_by_KEE() throws SQLException { | |||
String mainComponentUuid = randomAlphabetic(2); | |||
String mainComponentKey = randomAlphabetic(3); | |||
String branchUuid = randomAlphabetic(4); | |||
String branchType1 = randomAlphabetic(5); | |||
String branchName1 = randomAlphabetic(6); | |||
String branchType2 = randomAlphabetic(7); | |||
String branchName2 = randomAlphabetic(8); | |||
insertProjects(mainComponentUuid, mainComponentKey); | |||
insertProjects(branchUuid, mainComponentKey + ":BRANCH:" + branchName2); | |||
String orphanTaskUuid = insertCeActivity(new Row(newUuid(), mainComponentUuid, null, null), branchCharacteristics(branchType1, branchName1)); | |||
String regularTaskUuid = insertCeActivity(new Row(newUuid(), mainComponentUuid, null, null), branchCharacteristics(branchType2, branchName2)); | |||
underTest.execute(); | |||
assertThat(rowsInCeActivity()) | |||
.containsOnly( | |||
new Row(orphanTaskUuid, mainComponentUuid, mainComponentUuid, mainComponentUuid), | |||
new Row(regularTaskUuid, mainComponentUuid, branchUuid, mainComponentUuid)); | |||
} | |||
@Test | |||
public void execute_deletes_populates_prs_of_task_without_row_in_PROJECTS_with_COMPONENT_UUID_and_those_with_row_in_PROJECTS_by_KEE() throws SQLException { | |||
String mainComponentUuid = randomAlphabetic(2); | |||
String mainComponentKey = randomAlphabetic(3); | |||
String prUuid = randomAlphabetic(4); | |||
String prName1 = randomAlphabetic(6); | |||
String prName2 = randomAlphabetic(8); | |||
insertProjects(mainComponentUuid, mainComponentKey); | |||
insertProjects(prUuid, mainComponentKey + ":PULL_REQUEST:" + prName2); | |||
String orphanTaskUuid = insertCeActivity(new Row(newUuid(), mainComponentUuid, null, null), prCharacteristics(prName1)); | |||
String regularTaskUuid = insertCeActivity(new Row(newUuid(), mainComponentUuid, null, null), prCharacteristics(prName2)); | |||
underTest.execute(); | |||
assertThat(rowsInCeActivity()) | |||
.containsOnly( | |||
new Row(orphanTaskUuid, mainComponentUuid, mainComponentUuid, mainComponentUuid), | |||
new Row(regularTaskUuid, mainComponentUuid, prUuid, mainComponentUuid)); | |||
} | |||
private Stream<Row> rowsInCeActivity() { | |||
return db.select("select" + | |||
" uuid as \"UUID\", component_uuid as \"COMPONENT_UUID\", tmp_component_uuid as \"TMP_COMPONENT_UUID\", tmp_main_component_UUID as \"TMP_MAIN_COMPONENT_UUID\"" + | |||
" from ce_activity") | |||
.stream() | |||
.map(row -> new Row( | |||
(String) row.get("UUID"), | |||
(String) row.get("COMPONENT_UUID"), | |||
(String) row.get("TMP_COMPONENT_UUID"), | |||
(String) row.get("TMP_MAIN_COMPONENT_UUID"))); | |||
} | |||
private String insertCeActivity(Row row, Map<String, String> characteristics) { | |||
String uuid = insertCeActivity(row.taskUuid, row.componentUuid, row.tmpComponentUuid, row.tmpMainComponentUuid); | |||
characteristics.forEach((key, value) -> insertCeCharacteristic(uuid, key, value)); | |||
return uuid; | |||
} | |||
private String insertCeActivity(String uuid, @Nullable String componentUuid, @Nullable String tmpComponentUuid, @Nullable String tmpMainComponentUuid) { | |||
Random random = new Random(); | |||
db.executeInsert("ce_activity", | |||
"UUID", uuid, | |||
"TASK_TYPE", randomAlphabetic(6), | |||
"COMPONENT_UUID", componentUuid, | |||
"TMP_COMPONENT_UUID", tmpComponentUuid, | |||
"TMP_MAIN_COMPONENT_UUID", tmpMainComponentUuid, | |||
"STATUS", randomAlphabetic(7), | |||
"IS_LAST", random.nextBoolean(), | |||
"IS_LAST_KEY", random.nextBoolean(), | |||
"EXECUTION_COUNT", random.nextInt(500), | |||
"SUBMITTED_AT", (long) random.nextInt(500), | |||
"CREATED_AT", (long) random.nextInt(500), | |||
"UPDATED_AT", (long) random.nextInt(500)); | |||
return uuid; | |||
} | |||
private void insertCeCharacteristic(String taskUuid, String key, String value) { | |||
db.executeInsert( | |||
"ce_task_characteristics", | |||
"UUID", newUuid(), | |||
"TASK_UUID", taskUuid, | |||
"KEE", key, | |||
"TEXT_VALUE", value); | |||
} | |||
private void insertProjects(String uuid, String key) { | |||
db.executeInsert( | |||
"PROJECTS", | |||
"UUID", uuid, | |||
"KEE", key, | |||
"ORGANIZATION_UUID", "org_" + uuid, | |||
"ROOT_UUID", uuid + "_root", | |||
"UUID_PATH", uuid + "_path", | |||
"PROJECT_UUID", uuid + "_project", | |||
"PRIVATE", new Random().nextBoolean()); | |||
} | |||
private int uuidGenerator = new Random().nextInt(9000); | |||
private String newUuid() { | |||
return "uuid_" + uuidGenerator++; | |||
} | |||
private static Map<String, String> branchCharacteristics(String branchType, String branchName) { | |||
return ImmutableMap.of("branchType", branchType, "branch", branchName); | |||
} | |||
private static Map<String, String> prCharacteristics(String prName) { | |||
return ImmutableMap.of("pullRequest", prName); | |||
} | |||
} |
@@ -0,0 +1,216 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 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.server.platform.db.migration.version.v74; | |||
import com.google.common.collect.ImmutableMap; | |||
import com.tngtech.java.junit.dataprovider.DataProvider; | |||
import com.tngtech.java.junit.dataprovider.DataProviderRunner; | |||
import com.tngtech.java.junit.dataprovider.UseDataProvider; | |||
import java.sql.SQLException; | |||
import java.util.Collections; | |||
import java.util.Map; | |||
import java.util.Random; | |||
import java.util.stream.Stream; | |||
import javax.annotation.Nullable; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.runner.RunWith; | |||
import org.sonar.db.CoreDbTester; | |||
import static java.util.Arrays.stream; | |||
import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
@RunWith(DataProviderRunner.class) | |||
public class PopulateTmpColumnsToCeQueueTest { | |||
private static final Map<String, String> NO_CHARACTERISTICS = Collections.emptyMap(); | |||
@Rule | |||
public CoreDbTester db = CoreDbTester.createForSchema(PopulateTmpColumnsToCeQueueTest.class, "ce_queue.sql"); | |||
private PopulateTmpColumnsToCeQueue underTest = new PopulateTmpColumnsToCeQueue(db.database()); | |||
@Test | |||
public void no_action_on_empty_table() throws SQLException { | |||
underTest.execute(); | |||
assertThat(db.countRowsOfTable("ce_queue")).isZero(); | |||
} | |||
@Test | |||
@UseDataProvider("characteriticsOfMainBranchesAndPr") | |||
public void execute_populates_tmp_columns_with_component_uuid_if_task_has_no_row_in_PROJECTS(Map<String, String> characteristics) throws SQLException { | |||
Row[] notUpdatedRows = Stream.of( | |||
// not updated because no component_uuid | |||
new Row(newUuid(), null, null, null), | |||
new Row(newUuid(), null, randomAlphabetic(2), null), | |||
new Row(newUuid(), null, randomAlphabetic(3), randomAlphabetic(4)), | |||
new Row(newUuid(), null, null, randomAlphabetic(5)), | |||
// not updated because both target fields are already set (re-entrance) | |||
new Row(newUuid(), randomAlphabetic(14), randomAlphabetic(6), randomAlphabetic(7))) | |||
.toArray(Row[]::new); | |||
Row[] updatedRows = { | |||
new Row(newUuid(), randomAlphabetic(12), null, null), | |||
new Row(newUuid(), randomAlphabetic(13), randomAlphabetic(5), null), | |||
new Row(newUuid(), randomAlphabetic(14), null, randomAlphabetic(6)), | |||
}; | |||
stream(notUpdatedRows).forEach(row -> insertCeQueue(row, characteristics)); | |||
stream(updatedRows).forEach(row -> insertCeQueue(row, characteristics)); | |||
underTest.execute(); | |||
assertThat(rowsInCeQueue()) | |||
.hasSize(notUpdatedRows.length + updatedRows.length) | |||
.contains(notUpdatedRows) | |||
.contains(stream(updatedRows) | |||
.map(row -> new Row(row.taskUuid, row.componentUuid, row.componentUuid, row.componentUuid)) | |||
.toArray(Row[]::new)); | |||
} | |||
@DataProvider | |||
public static Object[][] characteriticsOfMainBranchesAndPr() { | |||
return new Object[][] { | |||
{NO_CHARACTERISTICS}, | |||
{branchCharacteristics("LONG", randomAlphabetic(15))}, | |||
{branchCharacteristics("SHORT", randomAlphabetic(16))}, | |||
{branchCharacteristics(randomAlphabetic(17), randomAlphabetic(18))}, | |||
{prCharacteristics(randomAlphabetic(19))}, | |||
}; | |||
} | |||
@Test | |||
public void execute_populates_tmp_columns_with_component_uuid_for_existing_main_branch() throws SQLException { | |||
String mainComponentUuid = randomAlphabetic(2); | |||
insertProjects(mainComponentUuid, randomAlphabetic(3)); | |||
String taskUuid = insertCeQueue(new Row(newUuid(), mainComponentUuid, null, null), NO_CHARACTERISTICS); | |||
underTest.execute(); | |||
assertThat(rowsInCeQueue()) | |||
.containsOnly(new Row(taskUuid, mainComponentUuid, mainComponentUuid, mainComponentUuid)); | |||
} | |||
@Test | |||
public void execute_deletes_tasks_of_branches_without_row_in_PROJECTS_and_populates_others_matching_row_in_PROJECTS_by_KEE() throws SQLException { | |||
String mainComponentUuid = randomAlphabetic(2); | |||
String mainComponentKey = randomAlphabetic(3); | |||
String branchUuid = randomAlphabetic(4); | |||
String branchType1 = randomAlphabetic(5); | |||
String branchName1 = randomAlphabetic(6); | |||
String branchType2 = randomAlphabetic(7); | |||
String branchName2 = randomAlphabetic(8); | |||
insertProjects(mainComponentUuid, mainComponentKey); | |||
insertProjects(branchUuid, mainComponentKey + ":BRANCH:" + branchName2); | |||
String deletedTaskUuid = insertCeQueue(new Row(newUuid(), mainComponentUuid, null, null), branchCharacteristics(branchType1, branchName1)); | |||
String updatedTaskUuid = insertCeQueue(new Row(newUuid(), mainComponentUuid, null, null), branchCharacteristics(branchType2, branchName2)); | |||
underTest.execute(); | |||
assertThat(rowsInCeQueue()) | |||
.containsOnly(new Row(updatedTaskUuid, mainComponentUuid, branchUuid, mainComponentUuid)); | |||
} | |||
@Test | |||
public void execute_deletes_tasks_of_prs_without_row_in_PROJECTS_and_populates_others_matching_row_in_PROJECTS_by_KEE() throws SQLException { | |||
String mainComponentUuid = randomAlphabetic(2); | |||
String mainComponentKey = randomAlphabetic(3); | |||
String prUuid = randomAlphabetic(4); | |||
String prName1 = randomAlphabetic(6); | |||
String prName2 = randomAlphabetic(8); | |||
insertProjects(mainComponentUuid, mainComponentKey); | |||
insertProjects(prUuid, mainComponentKey + ":PULL_REQUEST:" + prName2); | |||
String deletedTaskUuid = insertCeQueue(new Row(newUuid(), mainComponentUuid, null, null), prCharacteristics(prName1)); | |||
String updatedTaskUuid = insertCeQueue(new Row(newUuid(), mainComponentUuid, null, null), prCharacteristics(prName2)); | |||
underTest.execute(); | |||
assertThat(rowsInCeQueue()) | |||
.containsOnly(new Row(updatedTaskUuid, mainComponentUuid, prUuid, mainComponentUuid)); | |||
} | |||
private Stream<Row> rowsInCeQueue() { | |||
return db.select("select" + | |||
" uuid as \"UUID\", component_uuid as \"COMPONENT_UUID\", tmp_component_uuid as \"TMP_COMPONENT_UUID\", tmp_main_component_UUID as \"TMP_MAIN_COMPONENT_UUID\"" + | |||
" from ce_queue") | |||
.stream() | |||
.map(row -> new Row( | |||
(String) row.get("UUID"), | |||
(String) row.get("COMPONENT_UUID"), | |||
(String) row.get("TMP_COMPONENT_UUID"), | |||
(String) row.get("TMP_MAIN_COMPONENT_UUID"))); | |||
} | |||
private String insertCeQueue(Row row, Map<String, String> characteristics) { | |||
String uuid = insertCeQueue(row.taskUuid, row.componentUuid, row.tmpComponentUuid, row.tmpMainComponentUuid); | |||
characteristics.forEach((key, value) -> insertCeCharacteristic(uuid, key, value)); | |||
return uuid; | |||
} | |||
private String insertCeQueue(String uuid, @Nullable String componentUuid, @Nullable String tmpComponentUuid, @Nullable String tmpMainComponentUuid) { | |||
Random random = new Random(); | |||
db.executeInsert("ce_queue", | |||
"UUID", uuid, | |||
"TASK_TYPE", randomAlphabetic(6), | |||
"COMPONENT_UUID", componentUuid, | |||
"TMP_COMPONENT_UUID", tmpComponentUuid, | |||
"TMP_MAIN_COMPONENT_UUID", tmpMainComponentUuid, | |||
"STATUS", randomAlphabetic(7), | |||
"EXECUTION_COUNT", random.nextInt(500), | |||
"CREATED_AT", (long) random.nextInt(500), | |||
"UPDATED_AT", (long) random.nextInt(500)); | |||
return uuid; | |||
} | |||
private void insertCeCharacteristic(String taskUuid, String key, String value) { | |||
db.executeInsert( | |||
"ce_task_characteristics", | |||
"UUID", newUuid(), | |||
"TASK_UUID", taskUuid, | |||
"KEE", key, | |||
"TEXT_VALUE", value); | |||
} | |||
private void insertProjects(String uuid, String key) { | |||
db.executeInsert( | |||
"PROJECTS", | |||
"UUID", uuid, | |||
"KEE", key, | |||
"ORGANIZATION_UUID", "org_" + uuid, | |||
"ROOT_UUID", uuid + "_root", | |||
"UUID_PATH", uuid + "_path", | |||
"PROJECT_UUID", uuid + "_project", | |||
"PRIVATE", new Random().nextBoolean()); | |||
} | |||
private int uuidGenerator = new Random().nextInt(9000); | |||
private String newUuid() { | |||
return "uuid_" + uuidGenerator++; | |||
} | |||
private static Map<String, String> branchCharacteristics(String branchType, String branchName) { | |||
return ImmutableMap.of("branchType", branchType, "branch", branchName); | |||
} | |||
private static Map<String, String> prCharacteristics(String prName) { | |||
return ImmutableMap.of("pullRequest", prName); | |||
} | |||
} |
@@ -0,0 +1,118 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 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.server.platform.db.migration.version.v74; | |||
import java.sql.SQLException; | |||
import java.util.List; | |||
import java.util.Random; | |||
import javax.annotation.Nullable; | |||
import org.assertj.core.api.AbstractIterableAssert; | |||
import org.assertj.core.api.ObjectAssert; | |||
import org.assertj.core.groups.Tuple; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.sonar.api.config.internal.MapSettings; | |||
import org.sonar.core.util.UuidFactoryFast; | |||
import org.sonar.db.CoreDbTester; | |||
import static com.google.common.base.Preconditions.checkArgument; | |||
import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.tuple; | |||
public class PopulateTmpLastKeyColumnsToCeActivityTest { | |||
@Rule | |||
public CoreDbTester db = CoreDbTester.createForSchema(PopulateTmpLastKeyColumnsToCeActivityTest.class, "ce_activity.sql"); | |||
private MapSettings settings = new MapSettings(); | |||
private PopulateTmpLastKeyColumnsToCeActivity underTest = new PopulateTmpLastKeyColumnsToCeActivity(db.database(), settings.asConfig()); | |||
@Test | |||
public void execute_has_no_effect_on_empty_table() throws SQLException { | |||
underTest.execute(); | |||
assertThat(db.countRowsOfTable("ce_activity")).isZero(); | |||
} | |||
@Test | |||
public void execute_populate_tmp_last_key_columns_from_type_and_component_uuid_columns() throws SQLException { | |||
String type = randomAlphabetic(6); | |||
String oldComponentUuid = randomAlphabetic(7); | |||
String tmpComponentUuid = randomAlphabetic(8); | |||
String tmpMainComponentUuid = randomAlphabetic(9); | |||
String taskWithComponentUuid = insertCeActivity(type, oldComponentUuid, tmpComponentUuid, tmpMainComponentUuid); | |||
String taskWithInconsistentComponentUuid = insertCeActivity(type, null, tmpComponentUuid, tmpMainComponentUuid); | |||
String taskNoComponentUuid = insertCeActivity(type, null, null, null); | |||
underTest.execute(); | |||
assertThatTmpLastKeyAndMainLastKeyOf(taskWithComponentUuid).containsOnly(tuple(type + tmpComponentUuid, type + tmpMainComponentUuid)); | |||
assertThatTmpLastKeyAndMainLastKeyOf(taskWithInconsistentComponentUuid).containsOnly(tuple(type, type)); | |||
assertThatTmpLastKeyAndMainLastKeyOf(taskNoComponentUuid).containsOnly(tuple(type, type)); | |||
assertThatTmpIsLastAndMainIsLastOf(taskWithComponentUuid).containsOnly(tuple(false, false)); | |||
assertThatTmpIsLastAndMainIsLastOf(taskWithInconsistentComponentUuid).containsOnly(tuple(false, false)); | |||
assertThatTmpIsLastAndMainIsLastOf(taskNoComponentUuid).containsOnly(tuple(false, false)); | |||
} | |||
@Test | |||
public void execute_is_reentrant() throws SQLException { | |||
execute_populate_tmp_last_key_columns_from_type_and_component_uuid_columns(); | |||
underTest.execute(); | |||
} | |||
private String insertCeActivity(String type, | |||
@Nullable String oldComponentUuid, | |||
@Nullable String tmpComponentUuid, @Nullable String tmpMainComponentUuid) { | |||
checkArgument((tmpComponentUuid == null) == (tmpMainComponentUuid == null)); | |||
String uuid = UuidFactoryFast.getInstance().create(); | |||
Random random = new Random(); | |||
db.executeInsert( | |||
"ce_activity", | |||
"UUID", uuid, | |||
"TASK_TYPE", type, | |||
"COMPONENT_UUID", oldComponentUuid, | |||
"TMP_COMPONENT_UUID", tmpComponentUuid, | |||
"TMP_MAIN_COMPONENT_UUID", tmpMainComponentUuid, | |||
"STATUS", randomAlphabetic(5), | |||
"IS_LAST", random.nextBoolean(), | |||
"IS_LAST_KEY", randomAlphabetic(12), | |||
"EXECUTION_COUNT", random.nextInt(10), | |||
"SUBMITTED_AT", (long) random.nextInt(5_999), | |||
"CREATED_AT", (long) random.nextInt(5_999), | |||
"UPDATED_AT", (long) random.nextInt(5_999)); | |||
return uuid; | |||
} | |||
private AbstractIterableAssert<?, List<? extends Tuple>, Tuple, ObjectAssert<Tuple>> assertThatTmpLastKeyAndMainLastKeyOf(String uuid) { | |||
return assertThat(db.select("select tmp_is_last_key as \"LAST_KEY\", tmp_main_is_last_key as \"MAIN_LAST_KEY\" from ce_activity where uuid='" + uuid + "'")) | |||
.extracting(t -> (String) t.get("LAST_KEY"), t -> (String) t.get("MAIN_LAST_KEY")); | |||
} | |||
private AbstractIterableAssert<?, List<? extends Tuple>, Tuple, ObjectAssert<Tuple>> assertThatTmpIsLastAndMainIsLastOf(String uuid) { | |||
return assertThat(db.select("select tmp_is_last as \"LAST\", tmp_main_is_last as \"MAIN_LAST\" from ce_activity where uuid='" + uuid + "'")) | |||
.extracting(t -> (Boolean) t.get("LAST"), t -> (Boolean) t.get("MAIN_LAST")); | |||
} | |||
} |
@@ -0,0 +1,67 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 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.server.platform.db.migration.version.v74; | |||
import java.util.Objects; | |||
import javax.annotation.Nullable; | |||
final class Row { | |||
final String taskUuid; | |||
final String componentUuid; | |||
final String tmpComponentUuid; | |||
final String tmpMainComponentUuid; | |||
Row(String taskUuid, @Nullable String componentUuid, @Nullable String tmpComponentUuid, @Nullable String tmpMainComponentUuid) { | |||
this.taskUuid = taskUuid; | |||
this.componentUuid = componentUuid; | |||
this.tmpComponentUuid = tmpComponentUuid; | |||
this.tmpMainComponentUuid = tmpMainComponentUuid; | |||
} | |||
@Override | |||
public boolean equals(Object o) { | |||
if (this == o) { | |||
return true; | |||
} | |||
if (o == null || getClass() != o.getClass()) { | |||
return false; | |||
} | |||
Row row = (Row) o; | |||
return Objects.equals(taskUuid, row.taskUuid) && | |||
Objects.equals(componentUuid, row.componentUuid) && | |||
Objects.equals(tmpComponentUuid, row.tmpComponentUuid) && | |||
Objects.equals(tmpMainComponentUuid, row.tmpMainComponentUuid); | |||
} | |||
@Override | |||
public int hashCode() { | |||
return Objects.hash(taskUuid, componentUuid, tmpComponentUuid, tmpMainComponentUuid); | |||
} | |||
@Override | |||
public String toString() { | |||
return "Row{" + | |||
"uuid='" + taskUuid + '\'' + | |||
", componentUuid='" + componentUuid + '\'' + | |||
", tmpComponentUuid='" + tmpComponentUuid + '\'' + | |||
", tmpMainComponentUuid='" + tmpMainComponentUuid + '\'' + | |||
'}'; | |||
} | |||
} |
@@ -0,0 +1,26 @@ | |||
CREATE TABLE "CE_ACTIVITY" ( | |||
"ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), | |||
"UUID" VARCHAR(40) NOT NULL, | |||
"TASK_TYPE" VARCHAR(15) NOT NULL, | |||
"COMPONENT_UUID" VARCHAR(40) NULL, | |||
"ANALYSIS_UUID" VARCHAR(50) NULL, | |||
"STATUS" VARCHAR(15) NOT NULL, | |||
"IS_LAST" BOOLEAN NOT NULL, | |||
"IS_LAST_KEY" VARCHAR(55) NOT NULL, | |||
"SUBMITTER_UUID" VARCHAR(255) NULL, | |||
"WORKER_UUID" VARCHAR(40) NULL, | |||
"EXECUTION_COUNT" INTEGER NOT NULL, | |||
"SUBMITTED_AT" BIGINT NOT NULL, | |||
"STARTED_AT" BIGINT NULL, | |||
"EXECUTED_AT" BIGINT NULL, | |||
"CREATED_AT" BIGINT NOT NULL, | |||
"UPDATED_AT" BIGINT NOT NULL, | |||
"EXECUTION_TIME_MS" BIGINT NULL, | |||
"ERROR_MESSAGE" VARCHAR(1000), | |||
"ERROR_STACKTRACE" CLOB, | |||
"ERROR_TYPE" VARCHAR(20) | |||
); | |||
CREATE UNIQUE INDEX "CE_ACTIVITY_UUID" ON "CE_ACTIVITY" ("UUID"); | |||
CREATE INDEX "CE_ACTIVITY_COMPONENT_UUID" ON "CE_ACTIVITY" ("COMPONENT_UUID"); | |||
CREATE INDEX "CE_ACTIVITY_ISLASTKEY" ON "CE_ACTIVITY" ("IS_LAST_KEY"); | |||
CREATE INDEX "CE_ACTIVITY_ISLAST_STATUS" ON "CE_ACTIVITY" ("IS_LAST", "STATUS"); |
@@ -0,0 +1,16 @@ | |||
CREATE TABLE "CE_QUEUE" ( | |||
"ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), | |||
"UUID" VARCHAR(40) NOT NULL, | |||
"TASK_TYPE" VARCHAR(15) NOT NULL, | |||
"COMPONENT_UUID" VARCHAR(40) NULL, | |||
"STATUS" VARCHAR(15) NOT NULL, | |||
"SUBMITTER_UUID" VARCHAR(255) NULL, | |||
"WORKER_UUID" VARCHAR(40) NULL, | |||
"EXECUTION_COUNT" INTEGER NOT NULL, | |||
"STARTED_AT" BIGINT NULL, | |||
"CREATED_AT" BIGINT NOT NULL, | |||
"UPDATED_AT" BIGINT NOT NULL | |||
); | |||
CREATE UNIQUE INDEX "CE_QUEUE_UUID" ON "CE_QUEUE" ("UUID"); | |||
CREATE INDEX "CE_QUEUE_COMPONENT_UUID" ON "CE_QUEUE" ("COMPONENT_UUID"); | |||
CREATE INDEX "CE_QUEUE_STATUS" ON "CE_QUEUE" ("STATUS"); |
@@ -0,0 +1,30 @@ | |||
CREATE TABLE "CE_ACTIVITY" ( | |||
"ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), | |||
"UUID" VARCHAR(40) NOT NULL, | |||
"TASK_TYPE" VARCHAR(15) NOT NULL, | |||
"COMPONENT_UUID" VARCHAR(40) NULL, | |||
"TMP_COMPONENT_UUID" VARCHAR(40) NULL, | |||
"TMP_MAIN_COMPONENT_UUID" VARCHAR(40) NULL, | |||
"ANALYSIS_UUID" VARCHAR(50) NULL, | |||
"STATUS" VARCHAR(15) NOT NULL, | |||
"IS_LAST" BOOLEAN NOT NULL, | |||
"IS_LAST_KEY" VARCHAR(55) NOT NULL, | |||
"SUBMITTER_UUID" VARCHAR(255) NULL, | |||
"WORKER_UUID" VARCHAR(40) NULL, | |||
"EXECUTION_COUNT" INTEGER NOT NULL, | |||
"SUBMITTED_AT" BIGINT NOT NULL, | |||
"STARTED_AT" BIGINT NULL, | |||
"EXECUTED_AT" BIGINT NULL, | |||
"CREATED_AT" BIGINT NOT NULL, | |||
"UPDATED_AT" BIGINT NOT NULL, | |||
"EXECUTION_TIME_MS" BIGINT NULL, | |||
"ERROR_MESSAGE" VARCHAR(1000), | |||
"ERROR_STACKTRACE" CLOB, | |||
"ERROR_TYPE" VARCHAR(20) | |||
); | |||
CREATE UNIQUE INDEX "CE_ACTIVITY_UUID" ON "CE_ACTIVITY" ("UUID"); | |||
CREATE INDEX "CE_ACTIVITY_COMPONENT_UUID" ON "CE_ACTIVITY" ("COMPONENT_UUID"); | |||
CREATE INDEX "CE_ACTIVITY_TMP_CMPT_UUID" ON "CE_ACTIVITY" ("TMP_COMPONENT_UUID"); | |||
CREATE INDEX "CE_ACTIVITY_TMP_MAIN_CMPT_UUID" ON "CE_ACTIVITY" ("TMP_MAIN_COMPONENT_UUID"); | |||
CREATE INDEX "CE_ACTIVITY_ISLASTKEY" ON "CE_ACTIVITY" ("IS_LAST_KEY"); | |||
CREATE INDEX "CE_ACTIVITY_ISLAST_STATUS" ON "CE_ACTIVITY" ("IS_LAST", "STATUS"); |
@@ -0,0 +1,87 @@ | |||
CREATE TABLE "CE_ACTIVITY" ( | |||
"ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), | |||
"UUID" VARCHAR(40) NOT NULL, | |||
"TASK_TYPE" VARCHAR(15) NOT NULL, | |||
"COMPONENT_UUID" VARCHAR(40) NULL, | |||
"TMP_COMPONENT_UUID" VARCHAR(40) NULL, | |||
"TMP_MAIN_COMPONENT_UUID" VARCHAR(40) NULL, | |||
"ANALYSIS_UUID" VARCHAR(50) NULL, | |||
"STATUS" VARCHAR(15) NOT NULL, | |||
"IS_LAST" BOOLEAN NOT NULL, | |||
"IS_LAST_KEY" VARCHAR(55) NOT NULL, | |||
"SUBMITTER_UUID" VARCHAR(255) NULL, | |||
"WORKER_UUID" VARCHAR(40) NULL, | |||
"EXECUTION_COUNT" INTEGER NOT NULL, | |||
"SUBMITTED_AT" BIGINT NOT NULL, | |||
"STARTED_AT" BIGINT NULL, | |||
"EXECUTED_AT" BIGINT NULL, | |||
"CREATED_AT" BIGINT NOT NULL, | |||
"UPDATED_AT" BIGINT NOT NULL, | |||
"EXECUTION_TIME_MS" BIGINT NULL, | |||
"ERROR_MESSAGE" VARCHAR(1000), | |||
"ERROR_STACKTRACE" CLOB, | |||
"ERROR_TYPE" VARCHAR(20) | |||
); | |||
CREATE UNIQUE INDEX "CE_ACTIVITY_UUID" ON "CE_ACTIVITY" ("UUID"); | |||
CREATE INDEX "CE_ACTIVITY_COMPONENT_UUID" ON "CE_ACTIVITY" ("COMPONENT_UUID"); | |||
CREATE INDEX "CE_ACTIVITY_TMP_CMPT_UUID" ON "CE_ACTIVITY" ("TMP_COMPONENT_UUID"); | |||
CREATE INDEX "CE_ACTIVITY_TMP_MAIN_CMPT_UUID" ON "CE_ACTIVITY" ("TMP_MAIN_COMPONENT_UUID"); | |||
CREATE INDEX "CE_ACTIVITY_ISLASTKEY" ON "CE_ACTIVITY" ("IS_LAST_KEY"); | |||
CREATE INDEX "CE_ACTIVITY_ISLAST_STATUS" ON "CE_ACTIVITY" ("IS_LAST", "STATUS"); | |||
CREATE TABLE "CE_TASK_CHARACTERISTICS" ( | |||
"UUID" VARCHAR(40) NOT NULL, | |||
"TASK_UUID" VARCHAR(40) NOT NULL, | |||
"KEE" VARCHAR(50) NOT NULL, | |||
"TEXT_VALUE" VARCHAR(4000), | |||
CONSTRAINT "PK_CE_TASK_CHARACTERISTICS" PRIMARY KEY ("UUID") | |||
); | |||
CREATE INDEX "CE_TASK_CHARACTERISTICS_TASK_UUID" ON "CE_TASK_CHARACTERISTICS" ("TASK_UUID"); | |||
CREATE TABLE "PROJECTS" ( | |||
"ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), | |||
"ORGANIZATION_UUID" VARCHAR(40) NOT NULL, | |||
"KEE" VARCHAR(400), | |||
"UUID" VARCHAR(50) NOT NULL, | |||
"UUID_PATH" VARCHAR(1500) NOT NULL, | |||
"ROOT_UUID" VARCHAR(50) NOT NULL, | |||
"PROJECT_UUID" VARCHAR(50) NOT NULL, | |||
"MODULE_UUID" VARCHAR(50), | |||
"MODULE_UUID_PATH" VARCHAR(1500), | |||
"MAIN_BRANCH_PROJECT_UUID" VARCHAR(50), | |||
"NAME" VARCHAR(2000), | |||
"DESCRIPTION" VARCHAR(2000), | |||
"PRIVATE" BOOLEAN NOT NULL, | |||
"TAGS" VARCHAR(500), | |||
"ENABLED" BOOLEAN NOT NULL DEFAULT TRUE, | |||
"SCOPE" VARCHAR(3), | |||
"QUALIFIER" VARCHAR(10), | |||
"DEPRECATED_KEE" VARCHAR(400), | |||
"PATH" VARCHAR(2000), | |||
"LANGUAGE" VARCHAR(20), | |||
"COPY_COMPONENT_UUID" VARCHAR(50), | |||
"LONG_NAME" VARCHAR(2000), | |||
"DEVELOPER_UUID" VARCHAR(50), | |||
"CREATED_AT" TIMESTAMP, | |||
"AUTHORIZATION_UPDATED_AT" BIGINT, | |||
"B_CHANGED" BOOLEAN, | |||
"B_COPY_COMPONENT_UUID" VARCHAR(50), | |||
"B_DESCRIPTION" VARCHAR(2000), | |||
"B_ENABLED" BOOLEAN, | |||
"B_UUID_PATH" VARCHAR(1500), | |||
"B_LANGUAGE" VARCHAR(20), | |||
"B_LONG_NAME" VARCHAR(500), | |||
"B_MODULE_UUID" VARCHAR(50), | |||
"B_MODULE_UUID_PATH" VARCHAR(1500), | |||
"B_NAME" VARCHAR(500), | |||
"B_PATH" VARCHAR(2000), | |||
"B_QUALIFIER" VARCHAR(10) | |||
); | |||
CREATE INDEX "PROJECTS_ORGANIZATION" ON "PROJECTS" ("ORGANIZATION_UUID"); | |||
CREATE UNIQUE INDEX "PROJECTS_KEE" ON "PROJECTS" ("KEE"); | |||
CREATE INDEX "PROJECTS_ROOT_UUID" ON "PROJECTS" ("ROOT_UUID"); | |||
CREATE UNIQUE INDEX "PROJECTS_UUID" ON "PROJECTS" ("UUID"); | |||
CREATE INDEX "PROJECTS_PROJECT_UUID" ON "PROJECTS" ("PROJECT_UUID"); | |||
CREATE INDEX "PROJECTS_MODULE_UUID" ON "PROJECTS" ("MODULE_UUID"); | |||
CREATE INDEX "PROJECTS_QUALIFIER" ON "PROJECTS" ("QUALIFIER"); |
@@ -0,0 +1,77 @@ | |||
CREATE TABLE "CE_QUEUE" ( | |||
"ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), | |||
"UUID" VARCHAR(40) NOT NULL, | |||
"TASK_TYPE" VARCHAR(15) NOT NULL, | |||
"COMPONENT_UUID" VARCHAR(40) NULL, | |||
"TMP_COMPONENT_UUID" VARCHAR(40) NULL, | |||
"TMP_MAIN_COMPONENT_UUID" VARCHAR(40) NULL, | |||
"STATUS" VARCHAR(15) NOT NULL, | |||
"SUBMITTER_UUID" VARCHAR(255) NULL, | |||
"WORKER_UUID" VARCHAR(40) NULL, | |||
"EXECUTION_COUNT" INTEGER NOT NULL, | |||
"STARTED_AT" BIGINT NULL, | |||
"CREATED_AT" BIGINT NOT NULL, | |||
"UPDATED_AT" BIGINT NOT NULL | |||
); | |||
CREATE UNIQUE INDEX "CE_QUEUE_UUID" ON "CE_QUEUE" ("UUID"); | |||
CREATE INDEX "CE_QUEUE_COMPONENT_UUID" ON "CE_QUEUE" ("COMPONENT_UUID"); | |||
CREATE INDEX "CE_QUEUE_TMP_COMPONENT_UUID" ON "CE_QUEUE" ("TMP_COMPONENT_UUID"); | |||
CREATE INDEX "CE_QUEUE_TMP_MAIN_CMPT_UUID" ON "CE_QUEUE" ("TMP_MAIN_COMPONENT_UUID"); | |||
CREATE INDEX "CE_QUEUE_STATUS" ON "CE_QUEUE" ("STATUS"); | |||
CREATE TABLE "CE_TASK_CHARACTERISTICS" ( | |||
"UUID" VARCHAR(40) NOT NULL, | |||
"TASK_UUID" VARCHAR(40) NOT NULL, | |||
"KEE" VARCHAR(50) NOT NULL, | |||
"TEXT_VALUE" VARCHAR(4000), | |||
CONSTRAINT "PK_CE_TASK_CHARACTERISTICS" PRIMARY KEY ("UUID") | |||
); | |||
CREATE INDEX "CE_TASK_CHARACTERISTICS_TASK_UUID" ON "CE_TASK_CHARACTERISTICS" ("TASK_UUID"); | |||
CREATE TABLE "PROJECTS" ( | |||
"ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), | |||
"ORGANIZATION_UUID" VARCHAR(40) NOT NULL, | |||
"KEE" VARCHAR(400), | |||
"UUID" VARCHAR(50) NOT NULL, | |||
"UUID_PATH" VARCHAR(1500) NOT NULL, | |||
"ROOT_UUID" VARCHAR(50) NOT NULL, | |||
"PROJECT_UUID" VARCHAR(50) NOT NULL, | |||
"MODULE_UUID" VARCHAR(50), | |||
"MODULE_UUID_PATH" VARCHAR(1500), | |||
"MAIN_BRANCH_PROJECT_UUID" VARCHAR(50), | |||
"NAME" VARCHAR(2000), | |||
"DESCRIPTION" VARCHAR(2000), | |||
"PRIVATE" BOOLEAN NOT NULL, | |||
"TAGS" VARCHAR(500), | |||
"ENABLED" BOOLEAN NOT NULL DEFAULT TRUE, | |||
"SCOPE" VARCHAR(3), | |||
"QUALIFIER" VARCHAR(10), | |||
"DEPRECATED_KEE" VARCHAR(400), | |||
"PATH" VARCHAR(2000), | |||
"LANGUAGE" VARCHAR(20), | |||
"COPY_COMPONENT_UUID" VARCHAR(50), | |||
"LONG_NAME" VARCHAR(2000), | |||
"DEVELOPER_UUID" VARCHAR(50), | |||
"CREATED_AT" TIMESTAMP, | |||
"AUTHORIZATION_UPDATED_AT" BIGINT, | |||
"B_CHANGED" BOOLEAN, | |||
"B_COPY_COMPONENT_UUID" VARCHAR(50), | |||
"B_DESCRIPTION" VARCHAR(2000), | |||
"B_ENABLED" BOOLEAN, | |||
"B_UUID_PATH" VARCHAR(1500), | |||
"B_LANGUAGE" VARCHAR(20), | |||
"B_LONG_NAME" VARCHAR(500), | |||
"B_MODULE_UUID" VARCHAR(50), | |||
"B_MODULE_UUID_PATH" VARCHAR(1500), | |||
"B_NAME" VARCHAR(500), | |||
"B_PATH" VARCHAR(2000), | |||
"B_QUALIFIER" VARCHAR(10) | |||
); | |||
CREATE INDEX "PROJECTS_ORGANIZATION" ON "PROJECTS" ("ORGANIZATION_UUID"); | |||
CREATE UNIQUE INDEX "PROJECTS_KEE" ON "PROJECTS" ("KEE"); | |||
CREATE INDEX "PROJECTS_ROOT_UUID" ON "PROJECTS" ("ROOT_UUID"); | |||
CREATE UNIQUE INDEX "PROJECTS_UUID" ON "PROJECTS" ("UUID"); | |||
CREATE INDEX "PROJECTS_PROJECT_UUID" ON "PROJECTS" ("PROJECT_UUID"); | |||
CREATE INDEX "PROJECTS_MODULE_UUID" ON "PROJECTS" ("MODULE_UUID"); | |||
CREATE INDEX "PROJECTS_QUALIFIER" ON "PROJECTS" ("QUALIFIER"); |
@@ -0,0 +1,38 @@ | |||
CREATE TABLE "CE_ACTIVITY" ( | |||
"ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), | |||
"UUID" VARCHAR(40) NOT NULL, | |||
"TASK_TYPE" VARCHAR(15) NOT NULL, | |||
"COMPONENT_UUID" VARCHAR(40) NULL, | |||
"TMP_COMPONENT_UUID" VARCHAR(40) NULL, | |||
"TMP_MAIN_COMPONENT_UUID" VARCHAR(40) NULL, | |||
"ANALYSIS_UUID" VARCHAR(50) NULL, | |||
"STATUS" VARCHAR(15) NOT NULL, | |||
"IS_LAST" BOOLEAN NOT NULL, | |||
"IS_LAST_KEY" VARCHAR(55) NOT NULL, | |||
"TMP_IS_LAST" BOOLEAN, | |||
"TMP_IS_LAST_KEY" VARCHAR(55), | |||
"TMP_MAIN_IS_LAST" BOOLEAN, | |||
"TMP_MAIN_IS_LAST_KEY" VARCHAR(55), | |||
"SUBMITTER_UUID" VARCHAR(255) NULL, | |||
"WORKER_UUID" VARCHAR(40) NULL, | |||
"EXECUTION_COUNT" INTEGER NOT NULL, | |||
"SUBMITTED_AT" BIGINT NOT NULL, | |||
"STARTED_AT" BIGINT NULL, | |||
"EXECUTED_AT" BIGINT NULL, | |||
"CREATED_AT" BIGINT NOT NULL, | |||
"UPDATED_AT" BIGINT NOT NULL, | |||
"EXECUTION_TIME_MS" BIGINT NULL, | |||
"ERROR_MESSAGE" VARCHAR(1000), | |||
"ERROR_STACKTRACE" CLOB, | |||
"ERROR_TYPE" VARCHAR(20) | |||
); | |||
CREATE UNIQUE INDEX "CE_ACTIVITY_UUID" ON "CE_ACTIVITY" ("UUID"); | |||
CREATE INDEX "CE_ACTIVITY_COMPONENT_UUID" ON "CE_ACTIVITY" ("COMPONENT_UUID"); | |||
CREATE INDEX "CE_ACTIVITY_TMP_CPNT_UUID" ON "CE_ACTIVITY" ("TMP_COMPONENT_UUID"); | |||
CREATE INDEX "CE_ACTIVITY_TMP_MAIN_CPNT_UUID" ON "CE_ACTIVITY" ("TMP_MAIN_COMPONENT_UUID"); | |||
CREATE INDEX "CE_ACTIVITY_ISLASTKEY" ON "CE_ACTIVITY" ("IS_LAST_KEY"); | |||
CREATE INDEX "CE_ACTIVITY_ISLAST_STATUS" ON "CE_ACTIVITY" ("IS_LAST", "STATUS"); | |||
CREATE INDEX "CE_ACTIVITY_T_ISLAST_KEY" ON "CE_ACTIVITY" ("TMP_IS_LAST_KEY"); | |||
CREATE INDEX "CE_ACTIVITY_T_ISLAST" ON "CE_ACTIVITY" ("TMP_IS_LAST", "STATUS"); | |||
CREATE INDEX "CE_ACTIVITY_T_MAIN_ISLAST_KEY" ON "CE_ACTIVITY" ("TMP_MAIN_IS_LAST_KEY"); | |||
CREATE INDEX "CE_ACTIVITY_T_MAIN_ISLAST" ON "CE_ACTIVITY" ("TMP_MAIN_IS_LAST", "STATUS"); |
@@ -24,6 +24,7 @@ import org.sonar.ce.task.log.CeTaskLogging; | |||
import org.sonar.ce.task.projectanalysis.taskprocessor.ReportTaskProcessor; | |||
import org.sonar.core.platform.Module; | |||
import org.sonar.server.ce.http.CeHttpClientImpl; | |||
import org.sonar.server.ce.queue.BranchSupport; | |||
import org.sonar.server.ce.queue.ReportSubmitter; | |||
public class CeModule extends Module { | |||
@@ -34,6 +35,7 @@ public class CeModule extends Module { | |||
// Queue | |||
CeQueueImpl.class, | |||
BranchSupport.class, | |||
ReportSubmitter.class, | |||
// Core tasks processors |
@@ -0,0 +1,169 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 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.server.ce.queue; | |||
import java.util.Map; | |||
import java.util.Objects; | |||
import java.util.Optional; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import org.sonar.api.server.ServerSide; | |||
import org.sonar.core.component.ComponentKeys; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.organization.OrganizationDto; | |||
import static com.google.common.base.Preconditions.checkArgument; | |||
import static com.google.common.base.Preconditions.checkState; | |||
/** | |||
* Branch code for {@link ReportSubmitter}. | |||
* <p> | |||
* Does not support branches (except deprecated branch feature provided by "sonar.branch") unless an implementation of | |||
* {@link BranchSupportDelegate} is available. | |||
*/ | |||
@ServerSide | |||
public class BranchSupport { | |||
@CheckForNull | |||
private final BranchSupportDelegate delegate; | |||
/** | |||
* Constructor called by Pico when no implementation of {@link BranchSupportDelegate} is available. | |||
*/ | |||
public BranchSupport() { | |||
this(null); | |||
} | |||
public BranchSupport(@Nullable BranchSupportDelegate delegate) { | |||
this.delegate = delegate; | |||
} | |||
ComponentKey createComponentKey(String projectKey, @Nullable String deprecatedBranch, Map<String, String> characteristics) { | |||
if (characteristics.isEmpty()) { | |||
return new ComponentKeyImpl(projectKey, deprecatedBranch, ComponentKeys.createKey(projectKey, deprecatedBranch)); | |||
} else { | |||
checkState(delegate != null, "Current edition does not support branch feature"); | |||
} | |||
checkArgument(deprecatedBranch == null, "Deprecated branch feature can't be used at the same time as new branch support"); | |||
return delegate.createComponentKey(projectKey, characteristics); | |||
} | |||
ComponentDto createBranchComponent(DbSession dbSession, ComponentKey componentKey, OrganizationDto organization, ComponentDto mainComponentDto) { | |||
checkState(delegate != null, "Current edition does not support branch feature"); | |||
return delegate.createBranchComponent(dbSession, componentKey, organization, mainComponentDto); | |||
} | |||
public interface ComponentKey { | |||
String getKey(); | |||
String getDbKey(); | |||
Optional<String> getDeprecatedBranchName(); | |||
Optional<String> getBranchName(); | |||
Optional<String> getPullRequestKey(); | |||
boolean isMainBranch(); | |||
boolean isDeprecatedBranch(); | |||
/** | |||
* @return the {@link ComponentKey} of the main branch for this component. | |||
* If this component is the main branch (ie. {@link #isMainBranch()} returns true), this method returns | |||
* {@code this}. | |||
*/ | |||
ComponentKey getMainBranchComponentKey(); | |||
} | |||
private static final class ComponentKeyImpl implements ComponentKey { | |||
private final String key; | |||
private final String dbKey; | |||
@CheckForNull | |||
private final String deprecatedBranchName; | |||
public ComponentKeyImpl(String key, @Nullable String deprecatedBranchName, String dbKey) { | |||
this.key = key; | |||
this.deprecatedBranchName = deprecatedBranchName; | |||
this.dbKey = dbKey; | |||
} | |||
@Override | |||
public String getKey() { | |||
return key; | |||
} | |||
@Override | |||
public String getDbKey() { | |||
return dbKey; | |||
} | |||
@Override | |||
public Optional<String> getDeprecatedBranchName() { | |||
return Optional.ofNullable(deprecatedBranchName); | |||
} | |||
@Override | |||
public Optional<String> getBranchName() { | |||
return Optional.empty(); | |||
} | |||
@Override | |||
public Optional<String> getPullRequestKey() { | |||
return Optional.empty(); | |||
} | |||
@Override | |||
public boolean isMainBranch() { | |||
return key.equals(dbKey); | |||
} | |||
@Override | |||
public boolean isDeprecatedBranch() { | |||
return deprecatedBranchName != null; | |||
} | |||
@Override | |||
public ComponentKey getMainBranchComponentKey() { | |||
return this; | |||
} | |||
@Override | |||
public boolean equals(Object o) { | |||
if (this == o) { | |||
return true; | |||
} | |||
if (o == null || getClass() != o.getClass()) { | |||
return false; | |||
} | |||
ComponentKeyImpl that = (ComponentKeyImpl) o; | |||
return Objects.equals(key, that.key) && | |||
Objects.equals(dbKey, that.dbKey) && | |||
Objects.equals(deprecatedBranchName, that.deprecatedBranchName); | |||
} | |||
@Override | |||
public int hashCode() { | |||
return Objects.hash(key, dbKey, deprecatedBranchName); | |||
} | |||
} | |||
} |
@@ -0,0 +1,55 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 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.server.ce.queue; | |||
import java.util.Map; | |||
import org.sonar.api.server.ServerSide; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.ce.CeTaskCharacteristicDto; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.organization.OrganizationDto; | |||
import org.sonar.server.ce.queue.BranchSupport.ComponentKey; | |||
@ServerSide | |||
public interface BranchSupportDelegate { | |||
/** | |||
* Creates a {@link ComponentKey} for the specified projectKey and the specified {@code characteristics}. | |||
* | |||
* @throws IllegalArgumentException if {@code characteristics} is empty | |||
* @throws IllegalArgumentException if does not contain a supported value for {@link CeTaskCharacteristicDto#BRANCH_TYPE_KEY BRANCH_TYPE_KEY} | |||
* @throws IllegalArgumentException if does not contain a value for expected | |||
* {@link CeTaskCharacteristicDto#BRANCH_KEY BRANCH_KEY} or {@link CeTaskCharacteristicDto#PULL_REQUEST PULL_REQUEST} | |||
* given the value of {@link CeTaskCharacteristicDto#BRANCH_TYPE_KEY BRANCH_TYPE_KEY} | |||
* @throws IllegalArgumentException if incorrectly contains a value in | |||
* {@link CeTaskCharacteristicDto#BRANCH_KEY BRANCH_KEY} or {@link CeTaskCharacteristicDto#PULL_REQUEST PULL_REQUEST} | |||
* given the value of {@link CeTaskCharacteristicDto#BRANCH_TYPE_KEY BRANCH_TYPE_KEY} | |||
*/ | |||
ComponentKey createComponentKey(String projectKey, Map<String, String> characteristics); | |||
/** | |||
* Creates the ComponentDto for the branch described in {@code componentKey} which belongs to the specified | |||
* {@code mainComponentDto} in the specified {@code organization}. | |||
* | |||
* @throws IllegalArgumentException if arguments are inconsistent (such as {@code mainComponentDto} not having the same | |||
* key as {@code componentKey.getKey()}, ...) | |||
*/ | |||
ComponentDto createBranchComponent(DbSession dbSession, ComponentKey componentKey, | |||
OrganizationDto organization, ComponentDto mainComponentDto); | |||
} |
@@ -31,7 +31,6 @@ import org.sonar.api.server.ServerSide; | |||
import org.sonar.ce.queue.CeQueue; | |||
import org.sonar.ce.queue.CeTaskSubmit; | |||
import org.sonar.ce.task.CeTask; | |||
import org.sonar.core.component.ComponentKeys; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.ce.CeTaskTypes; | |||
@@ -60,31 +59,33 @@ public class ReportSubmitter { | |||
private final ComponentUpdater componentUpdater; | |||
private final PermissionTemplateService permissionTemplateService; | |||
private final DbClient dbClient; | |||
private final BranchSupport branchSupport; | |||
public ReportSubmitter(CeQueue queue, UserSession userSession, ComponentUpdater componentUpdater, | |||
PermissionTemplateService permissionTemplateService, DbClient dbClient) { | |||
PermissionTemplateService permissionTemplateService, DbClient dbClient, BranchSupport branchSupport) { | |||
this.queue = queue; | |||
this.userSession = userSession; | |||
this.componentUpdater = componentUpdater; | |||
this.permissionTemplateService = permissionTemplateService; | |||
this.dbClient = dbClient; | |||
this.branchSupport = branchSupport; | |||
} | |||
/** | |||
* @throws NotFoundException if the organization with the specified key does not exist | |||
* @throws IllegalArgumentException if the organization with the specified key is not the organization of the specified project (when it already exists in DB) | |||
*/ | |||
public CeTask submit(String organizationKey, String projectKey, @Nullable String deprecatedBranch, @Nullable String projectName, Map<String, String> characteristics, | |||
InputStream reportInput) { | |||
public CeTask submit(String organizationKey, String projectKey, @Nullable String deprecatedBranch, @Nullable String projectName, | |||
Map<String, String> characteristics, InputStream reportInput) { | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
OrganizationDto organizationDto = getOrganizationDtoOrFail(dbSession, organizationKey); | |||
String effectiveProjectKey = ComponentKeys.createKey(projectKey, deprecatedBranch); | |||
Optional<ComponentDto> component = dbClient.componentDao().selectByKey(dbSession, effectiveProjectKey); | |||
validateProject(dbSession, component, projectKey); | |||
ensureOrganizationIsConsistent(component, organizationDto); | |||
ComponentDto project = component.orElseGet(() -> createProject(dbSession, organizationDto, projectKey, deprecatedBranch, projectName)); | |||
checkScanPermission(project); | |||
return submitReport(dbSession, reportInput, project, characteristics); | |||
BranchSupport.ComponentKey componentKey = branchSupport.createComponentKey(projectKey, deprecatedBranch, characteristics); | |||
Optional<ComponentDto> existingComponent = dbClient.componentDao().selectByKey(dbSession, componentKey.getDbKey()); | |||
validateProject(dbSession, existingComponent, projectKey); | |||
ensureOrganizationIsConsistent(existingComponent, organizationDto); | |||
ComponentDto component = existingComponent.orElseGet(() -> createComponent(dbSession, organizationDto, componentKey, projectName)); | |||
checkScanPermission(component); | |||
return submitReport(dbSession, reportInput, component, characteristics); | |||
} | |||
} | |||
@@ -135,13 +136,32 @@ public class ReportSubmitter { | |||
} | |||
} | |||
private ComponentDto createProject(DbSession dbSession, OrganizationDto organization, String projectKey, @Nullable String deprecatedBranch, @Nullable String projectName) { | |||
private ComponentDto createComponent(DbSession dbSession, OrganizationDto organization, BranchSupport.ComponentKey componentKey, @Nullable String projectName) { | |||
if (componentKey.isMainBranch() || componentKey.isDeprecatedBranch()) { | |||
ComponentDto project = createProject(dbSession, organization, componentKey, projectName); | |||
componentUpdater.commitAndIndex(dbSession, project); | |||
return project; | |||
} | |||
Optional<ComponentDto> existingMainComponent = dbClient.componentDao().selectByKey(dbSession, componentKey.getKey()); | |||
ComponentDto mainComponentDto = existingMainComponent | |||
.orElseGet(() -> createProject(dbSession, organization, componentKey.getMainBranchComponentKey(), projectName)); | |||
ComponentDto branchComponent = branchSupport.createBranchComponent(dbSession, componentKey, organization, mainComponentDto); | |||
if (existingMainComponent.isPresent()) { | |||
dbSession.commit(); | |||
} else { | |||
componentUpdater.commitAndIndex(dbSession, mainComponentDto); | |||
} | |||
return branchComponent; | |||
} | |||
private ComponentDto createProject(DbSession dbSession, OrganizationDto organization, BranchSupport.ComponentKey componentKey, | |||
@Nullable String projectName) { | |||
userSession.checkPermission(OrganizationPermission.PROVISION_PROJECTS, organization); | |||
Integer userId = userSession.getUserId(); | |||
String effectiveProjectKey = ComponentKeys.createEffectiveKey(projectKey, deprecatedBranch); | |||
boolean wouldCurrentUserHaveScanPermission = permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate( | |||
dbSession, organization.getUuid(), userId, effectiveProjectKey, Qualifiers.PROJECT); | |||
dbSession, organization.getUuid(), userId, componentKey.getDbKey(), Qualifiers.PROJECT); | |||
if (!wouldCurrentUserHaveScanPermission) { | |||
throw insufficientPrivilegesException(); | |||
} | |||
@@ -150,13 +170,13 @@ public class ReportSubmitter { | |||
NewComponent newProject = newComponentBuilder() | |||
.setOrganizationUuid(organization.getUuid()) | |||
.setKey(projectKey) | |||
.setName(defaultIfBlank(projectName, projectKey)) | |||
.setDeprecatedBranch(deprecatedBranch) | |||
.setKey(componentKey.getKey()) | |||
.setName(defaultIfBlank(projectName, componentKey.getKey())) | |||
.setDeprecatedBranch(componentKey.getDeprecatedBranchName().orElse(null)) | |||
.setQualifier(Qualifiers.PROJECT) | |||
.setPrivate(newProjectPrivate) | |||
.build(); | |||
return componentUpdater.create(dbSession, newProject, userId); | |||
return componentUpdater.createWithoutCommit(dbSession, newProject, userId); | |||
} | |||
private CeTask submitReport(DbSession dbSession, InputStream reportInput, ComponentDto project, Map<String, String> characteristics) { | |||
@@ -167,9 +187,10 @@ public class ReportSubmitter { | |||
dbSession.commit(); | |||
submit.setType(CeTaskTypes.REPORT); | |||
submit.setComponentUuid(project.uuid()); | |||
submit.setComponent(CeTaskSubmit.Component.fromDto(project)); | |||
submit.setSubmitterUuid(userSession.getUuid()); | |||
submit.setCharacteristics(characteristics); | |||
return queue.submit(submit.build()); | |||
} | |||
} |
@@ -237,9 +237,9 @@ public class ActivityAction implements CeWsAction { | |||
String componentQuery = request.getQ(); | |||
if (component != null) { | |||
query.setComponentUuid(component.uuid()); | |||
query.setMainComponentUuid(component.uuid()); | |||
} else if (componentQuery != null) { | |||
query.setComponentUuids(loadComponents(dbSession, componentQuery).stream() | |||
query.setMainComponentUuids(loadComponents(dbSession, componentQuery).stream() | |||
.map(ComponentDto::uuid) | |||
.collect(toList())); | |||
} |
@@ -83,9 +83,9 @@ public class ActivityStatusAction implements CeWsAction { | |||
Optional<ComponentDto> component = searchComponent(dbSession, request); | |||
String componentUuid = component.isPresent() ? component.get().uuid() : null; | |||
checkPermissions(component); | |||
int pendingCount = dbClient.ceQueueDao().countByStatusAndComponentUuid(dbSession, CeQueueDto.Status.PENDING, componentUuid); | |||
int inProgressCount = dbClient.ceQueueDao().countByStatusAndComponentUuid(dbSession, CeQueueDto.Status.IN_PROGRESS, componentUuid); | |||
int failingCount = dbClient.ceActivityDao().countLastByStatusAndComponentUuid(dbSession, CeActivityDto.Status.FAILED, componentUuid); | |||
int pendingCount = dbClient.ceQueueDao().countByStatusAndMainComponentUuid(dbSession, CeQueueDto.Status.PENDING, componentUuid); | |||
int inProgressCount = dbClient.ceQueueDao().countByStatusAndMainComponentUuid(dbSession, CeQueueDto.Status.IN_PROGRESS, componentUuid); | |||
int failingCount = dbClient.ceActivityDao().countLastByStatusAndMainComponentUuid(dbSession, CeActivityDto.Status.FAILED, componentUuid); | |||
return ActivityStatusWsResponse.newBuilder() | |||
.setPending(pendingCount) |
@@ -88,9 +88,9 @@ public class ComponentAction implements CeWsAction { | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
ComponentDto component = loadComponent(dbSession, wsRequest); | |||
userSession.checkComponentPermission(UserRole.USER, component); | |||
List<CeQueueDto> queueDtos = dbClient.ceQueueDao().selectByComponentUuid(dbSession, component.uuid()); | |||
List<CeQueueDto> queueDtos = dbClient.ceQueueDao().selectByMainComponentUuid(dbSession, component.uuid()); | |||
CeTaskQuery activityQuery = new CeTaskQuery() | |||
.setComponentUuid(component.uuid()) | |||
.setMainComponentUuid(component.uuid()) | |||
.setOnlyCurrents(true); | |||
List<CeActivityDto> activityDtos = dbClient.ceActivityDao().selectByQuery(dbSession, activityQuery, forPage(1).andSize(1)); | |||
@@ -121,7 +121,7 @@ public class SubmitAction implements CeWsAction { | |||
CeTask task = reportSubmitter.submit(organizationKey, projectKey, deprecatedBranch, projectName, characteristics, report); | |||
Ce.SubmitResponse submitResponse = Ce.SubmitResponse.newBuilder() | |||
.setTaskId(task.getUuid()) | |||
.setProjectId(task.getComponentUuid()) | |||
.setProjectId(task.getComponent().get().getUuid()) | |||
.build(); | |||
WsUtils.writeProtobuf(submitResponse, wsRequest, wsResponse); | |||
} |
@@ -128,6 +128,7 @@ import org.sonar.server.platform.ws.DbMigrationStatusAction; | |||
import org.sonar.server.platform.ws.HealthActionModule; | |||
import org.sonar.server.platform.ws.L10nWs; | |||
import org.sonar.server.platform.ws.LogsAction; | |||
import org.sonar.server.platform.ws.MigrateDataAction; | |||
import org.sonar.server.platform.ws.MigrateDbAction; | |||
import org.sonar.server.platform.ws.PingAction; | |||
import org.sonar.server.platform.ws.RestartAction; | |||
@@ -512,6 +513,7 @@ public class PlatformLevel4 extends PlatformLevel { | |||
UpgradesAction.class, | |||
StatusAction.class, | |||
MigrateDbAction.class, | |||
MigrateDataAction.class, | |||
LogsAction.class, | |||
ChangeLogLevelAction.class, | |||
DbMigrationStatusAction.class, |
@@ -0,0 +1,65 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 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.server.platform.ws; | |||
import org.sonar.api.config.Configuration; | |||
import org.sonar.api.config.internal.MapSettings; | |||
import org.sonar.api.server.ws.Request; | |||
import org.sonar.api.server.ws.Response; | |||
import org.sonar.api.server.ws.WebService; | |||
import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.db.DbClient; | |||
import org.sonar.server.platform.db.migration.version.v74.PopulateTmpColumnsToCeActivity; | |||
import org.sonar.server.platform.db.migration.version.v74.PopulateTmpColumnsToCeQueue; | |||
import org.sonar.server.platform.db.migration.version.v74.PopulateTmpLastKeyColumnsToCeActivity; | |||
import org.sonar.server.user.UserSession; | |||
public class MigrateDataAction implements SystemWsAction { | |||
private static final Logger LOG = Loggers.get(MigrateDataAction.class); | |||
private final UserSession userSession; | |||
private final DbClient dbClient; | |||
public MigrateDataAction(UserSession userSession, DbClient dbClient) { | |||
this.userSession = userSession; | |||
this.dbClient = dbClient; | |||
} | |||
@Override | |||
public void define(WebService.NewController controller) { | |||
controller.createAction("migrate_data") | |||
.setPost(true) | |||
.setHandler(this); | |||
} | |||
@Override | |||
public void handle(Request request, Response response) throws Exception { | |||
userSession.isSystemAdministrator(); | |||
Configuration emptyConfiguration = new MapSettings().asConfig(); | |||
new PopulateTmpColumnsToCeQueue(dbClient.getDatabase()).execute(); | |||
new PopulateTmpColumnsToCeActivity(dbClient.getDatabase(), emptyConfiguration).execute(); | |||
new PopulateTmpLastKeyColumnsToCeActivity(dbClient.getDatabase(), emptyConfiguration).execute(); | |||
LOG.info("done"); | |||
response.noContent(); | |||
} | |||
} |
@@ -126,7 +126,8 @@ public class UpdateVisibilityAction implements ProjectsWsAction { | |||
} | |||
private boolean noPendingTask(DbSession dbSession, ComponentDto rootComponent) { | |||
return dbClient.ceQueueDao().selectByComponentUuid(dbSession, rootComponent.uuid()).isEmpty(); | |||
// FIXME this is probably broken in case a branch is passed to the WS | |||
return dbClient.ceQueueDao().selectByMainComponentUuid(dbSession, rootComponent.uuid()).isEmpty(); | |||
} | |||
private void updatePermissionsToPrivate(DbSession dbSession, ComponentDto component) { |
@@ -39,7 +39,6 @@ import static org.apache.commons.lang.StringUtils.defaultString; | |||
public abstract class AbstractUserSession implements UserSession { | |||
private static final String INSUFFICIENT_PRIVILEGES_MESSAGE = "Insufficient privileges"; | |||
private static final ForbiddenException INSUFFICIENT_PRIVILEGES_EXCEPTION = new ForbiddenException(INSUFFICIENT_PRIVILEGES_MESSAGE); | |||
private static final String AUTHENTICATION_IS_REQUIRED_MESSAGE = "Authentication is required"; | |||
protected static Identity computeIdentity(UserDto userDto) { | |||
@@ -191,7 +190,7 @@ public abstract class AbstractUserSession implements UserSession { | |||
} | |||
public static ForbiddenException insufficientPrivilegesException() { | |||
return INSUFFICIENT_PRIVILEGES_EXCEPTION; | |||
return new ForbiddenException(INSUFFICIENT_PRIVILEGES_MESSAGE); | |||
} | |||
@Override |
@@ -0,0 +1,301 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 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.server.ce.queue; | |||
import com.google.common.collect.ImmutableMap; | |||
import com.tngtech.java.junit.dataprovider.DataProvider; | |||
import com.tngtech.java.junit.dataprovider.DataProviderRunner; | |||
import java.io.InputStream; | |||
import java.nio.charset.StandardCharsets; | |||
import java.util.Map; | |||
import java.util.Random; | |||
import java.util.function.BiConsumer; | |||
import java.util.stream.IntStream; | |||
import org.apache.commons.io.IOUtils; | |||
import org.apache.commons.lang.RandomStringUtils; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.junit.runner.RunWith; | |||
import org.sonar.api.resources.Qualifiers; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.ce.queue.CeQueue; | |||
import org.sonar.ce.queue.CeQueueImpl; | |||
import org.sonar.ce.queue.CeTaskSubmit; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.ce.CeTaskTypes; | |||
import org.sonar.db.component.BranchDto; | |||
import org.sonar.db.component.BranchType; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.component.ComponentTesting; | |||
import org.sonar.db.organization.OrganizationDto; | |||
import org.sonar.db.user.UserDto; | |||
import org.sonar.server.component.ComponentUpdater; | |||
import org.sonar.server.exceptions.ForbiddenException; | |||
import org.sonar.server.favorite.FavoriteUpdater; | |||
import org.sonar.server.permission.PermissionTemplateService; | |||
import org.sonar.server.tester.UserSessionRule; | |||
import static java.util.Collections.emptyMap; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.junit.Assert.fail; | |||
import static org.mockito.ArgumentMatchers.any; | |||
import static org.mockito.ArgumentMatchers.argThat; | |||
import static org.mockito.ArgumentMatchers.eq; | |||
import static org.mockito.ArgumentMatchers.same; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.spy; | |||
import static org.mockito.Mockito.times; | |||
import static org.mockito.Mockito.verify; | |||
import static org.mockito.Mockito.verifyNoMoreInteractions; | |||
import static org.mockito.Mockito.verifyZeroInteractions; | |||
import static org.mockito.Mockito.when; | |||
import static org.sonar.core.permission.GlobalPermissions.PROVISIONING; | |||
import static org.sonar.core.permission.GlobalPermissions.SCAN_EXECUTION; | |||
import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex; | |||
import static org.sonar.db.component.ComponentTesting.newBranchDto; | |||
import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto; | |||
import static org.sonar.db.permission.OrganizationPermission.PROVISION_PROJECTS; | |||
import static org.sonar.db.permission.OrganizationPermission.SCAN; | |||
/** | |||
* Tests of {@link ReportSubmitter} when branch support is installed. | |||
*/ | |||
@RunWith(DataProviderRunner.class) | |||
public class BranchReportSubmitterTest { | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
@Rule | |||
public UserSessionRule userSession = UserSessionRule.standalone(); | |||
@Rule | |||
public DbTester db = DbTester.create(System2.INSTANCE); | |||
private CeQueue queue = mock(CeQueueImpl.class); | |||
private ComponentUpdater componentUpdater = mock(ComponentUpdater.class); | |||
private PermissionTemplateService permissionTemplateService = mock(PermissionTemplateService.class); | |||
private FavoriteUpdater favoriteUpdater = mock(FavoriteUpdater.class); | |||
private BranchSupportDelegate branchSupportDelegate = mock(BranchSupportDelegate.class); | |||
private BranchSupport branchSupport = spy(new BranchSupport(branchSupportDelegate)); | |||
private ReportSubmitter underTest = new ReportSubmitter(queue, userSession, componentUpdater, permissionTemplateService, db.getDbClient(), branchSupport); | |||
@Test | |||
public void submit_does_not_use_delegate_if_characteristics_are_empty() { | |||
OrganizationDto organization = db.organizations().insert(); | |||
ComponentDto project = db.components().insertPrivateProject(organization); | |||
UserDto user = db.users().insertUser(); | |||
userSession.logIn(user).addProjectPermission(SCAN_EXECUTION, project); | |||
mockSuccessfulPrepareSubmitCall(); | |||
InputStream reportInput = IOUtils.toInputStream("{binary}", StandardCharsets.UTF_8); | |||
underTest.submit(organization.getKey(), project.getDbKey(), null, project.name(), emptyMap(), reportInput); | |||
verifyZeroInteractions(branchSupportDelegate); | |||
} | |||
@Test | |||
public void submit_a_report_on_existing_branch() { | |||
OrganizationDto organization = db.organizations().insert(); | |||
ComponentDto project = db.components().insertPrivateProject(organization); | |||
ComponentDto branch = db.components().insertProjectBranch(project); | |||
UserDto user = db.users().insertUser(); | |||
userSession.logIn(user).addProjectPermission(SCAN_EXECUTION, project); | |||
Map<String, String> randomCharacteristics = randomNonEmptyMap(); | |||
BranchSupport.ComponentKey componentKey = createComponentKeyOfBranch(branch); | |||
when(branchSupportDelegate.createComponentKey(project.getDbKey(), randomCharacteristics)) | |||
.thenReturn(componentKey); | |||
InputStream reportInput = IOUtils.toInputStream("{binary}", StandardCharsets.UTF_8); | |||
String taskUuid = mockSuccessfulPrepareSubmitCall(); | |||
underTest.submit(organization.getKey(), project.getDbKey(), null, project.name(), randomCharacteristics, reportInput); | |||
verifyZeroInteractions(permissionTemplateService); | |||
verifyZeroInteractions(favoriteUpdater); | |||
verify(branchSupport, times(0)).createBranchComponent(any(), any(), any(), any()); | |||
verify(branchSupportDelegate).createComponentKey(project.getDbKey(), randomCharacteristics); | |||
verify(branchSupportDelegate, times(0)).createBranchComponent(any(), any(), any(), any()); | |||
verifyNoMoreInteractions(branchSupportDelegate); | |||
verifyQueueSubmit(project, branch, user, randomCharacteristics, taskUuid); | |||
} | |||
@Test | |||
public void submit_a_report_on_missing_branch_but_existing_project() { | |||
OrganizationDto organization = db.organizations().insert(); | |||
ComponentDto nonExistingProject = db.components().insertPrivateProject(organization); | |||
UserDto user = db.users().insertUser(); | |||
userSession.logIn(user).addProjectPermission(SCAN_EXECUTION, nonExistingProject); | |||
Map<String, String> randomCharacteristics = randomNonEmptyMap(); | |||
ComponentDto createdBranch = createButDoNotInsertBranch(nonExistingProject); | |||
BranchSupport.ComponentKey componentKey = createComponentKeyOfBranch(createdBranch); | |||
when(branchSupportDelegate.createComponentKey(nonExistingProject.getDbKey(), randomCharacteristics)) | |||
.thenReturn(componentKey); | |||
when(branchSupportDelegate.createBranchComponent(any(DbSession.class), same(componentKey), eq(organization), eq(nonExistingProject))) | |||
.thenReturn(createdBranch); | |||
InputStream reportInput = IOUtils.toInputStream("{binary}", StandardCharsets.UTF_8); | |||
String taskUuid = mockSuccessfulPrepareSubmitCall(); | |||
underTest.submit(organization.getKey(), nonExistingProject.getDbKey(), null, nonExistingProject.name(), randomCharacteristics, reportInput); | |||
verifyZeroInteractions(permissionTemplateService); | |||
verifyZeroInteractions(favoriteUpdater); | |||
verify(branchSupport).createBranchComponent(any(DbSession.class), same(componentKey), eq(organization), eq(nonExistingProject)); | |||
verify(branchSupportDelegate).createComponentKey(nonExistingProject.getDbKey(), randomCharacteristics); | |||
verify(branchSupportDelegate).createBranchComponent(any(DbSession.class), same(componentKey), eq(organization), eq(nonExistingProject)); | |||
verifyNoMoreInteractions(branchSupportDelegate); | |||
verify(componentUpdater, times(0)).commitAndIndex(any(), any()); | |||
verifyQueueSubmit(nonExistingProject, createdBranch, user, randomCharacteristics, taskUuid); | |||
} | |||
@Test | |||
public void submit_report_on_missing_branch_of_missing_project_provisions_project_when_org_PROVISION_PROJECT_perm() { | |||
OrganizationDto organization = db.organizations().insert(); | |||
ComponentDto nonExistingProject = newPrivateProjectDto(organization); | |||
UserDto user = db.users().insertUser(); | |||
userSession.logIn(user) | |||
.addPermission(PROVISION_PROJECTS, organization) | |||
.addPermission(SCAN, organization); | |||
Map<String, String> randomCharacteristics = randomNonEmptyMap(); | |||
ComponentDto createdBranch = createButDoNotInsertBranch(nonExistingProject); | |||
BranchSupport.ComponentKey componentKey = createComponentKeyOfBranch(createdBranch); | |||
when(branchSupportDelegate.createComponentKey(nonExistingProject.getDbKey(), randomCharacteristics)) | |||
.thenReturn(componentKey); | |||
when(componentUpdater.createWithoutCommit(any(), any(), eq(user.getId()))).thenReturn(nonExistingProject); | |||
when(branchSupportDelegate.createBranchComponent(any(DbSession.class), same(componentKey), eq(organization), eq(nonExistingProject))) | |||
.thenReturn(createdBranch); | |||
when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(), eq(organization.getUuid()), any(), | |||
eq(nonExistingProject.getKey()), eq(Qualifiers.PROJECT))) | |||
.thenReturn(true); | |||
String taskUuid = mockSuccessfulPrepareSubmitCall(); | |||
InputStream reportInput = IOUtils.toInputStream("{binary}", StandardCharsets.UTF_8); | |||
underTest.submit(organization.getKey(), nonExistingProject.getDbKey(), null, nonExistingProject.name(), randomCharacteristics, reportInput); | |||
verify(branchSupport).createBranchComponent(any(DbSession.class), same(componentKey), eq(organization), eq(nonExistingProject)); | |||
verify(branchSupportDelegate).createComponentKey(nonExistingProject.getDbKey(), randomCharacteristics); | |||
verify(branchSupportDelegate).createBranchComponent(any(DbSession.class), same(componentKey), eq(organization), eq(nonExistingProject)); | |||
verifyNoMoreInteractions(branchSupportDelegate); | |||
verifyQueueSubmit(nonExistingProject, createdBranch, user, randomCharacteristics, taskUuid); | |||
verify(componentUpdater).commitAndIndex(any(DbSession.class), eq(nonExistingProject)); | |||
} | |||
@Test | |||
public void submit_fails_if_branch_support_delegate_createComponentKey_throws_an_exception() { | |||
OrganizationDto organization = db.organizations().insert(); | |||
ComponentDto project = db.components().insertPrivateProject(organization); | |||
UserDto user = db.users().insertUser(); | |||
userSession.logIn(user).addProjectPermission(SCAN_EXECUTION, project); | |||
Map<String, String> randomCharacteristics = randomNonEmptyMap(); | |||
InputStream reportInput = IOUtils.toInputStream("{binary}", StandardCharsets.UTF_8); | |||
RuntimeException expected = new RuntimeException("Faking an exception thrown by branchSupportDelegate"); | |||
when(branchSupportDelegate.createComponentKey(any(), any())).thenThrow(expected); | |||
try { | |||
underTest.submit(organization.getKey(), project.getDbKey(), null, project.name(), randomCharacteristics, reportInput); | |||
fail("exception should have been thrown"); | |||
} catch (Exception e) { | |||
assertThat(e).isSameAs(expected); | |||
} | |||
} | |||
@DataProvider | |||
public static Object[][] permissionsAllowingProjectProvisioning() { | |||
BiConsumer<ComponentDto, UserSessionRule> noProjectPerm = (cpt, userSession) -> { | |||
}; | |||
BiConsumer<OrganizationDto, UserSessionRule> noOrgPerm = (cpt, userSession) -> { | |||
}; | |||
BiConsumer<ComponentDto, UserSessionRule> provisionOnProject = (cpt, userSession) -> userSession.addProjectPermission(PROVISIONING, cpt); | |||
BiConsumer<OrganizationDto, UserSessionRule> provisionOnOrganization = (cpt, userSession) -> userSession.addPermission(PROVISION_PROJECTS, cpt); | |||
return new Object[][] { | |||
{provisionOnProject, noOrgPerm}, | |||
{noProjectPerm, provisionOnOrganization}, | |||
{provisionOnProject, provisionOnOrganization} | |||
}; | |||
} | |||
@Test | |||
public void submit_report_on_missing_branch_of_missing_project_fails_with_ForbiddenException_if_only_scan_permission() { | |||
OrganizationDto organization = db.organizations().insert(); | |||
ComponentDto nonExistingProject = newPrivateProjectDto(organization); | |||
UserDto user = db.users().insertUser(); | |||
userSession.logIn(user).addProjectPermission(SCAN_EXECUTION, nonExistingProject); | |||
Map<String, String> randomCharacteristics = randomNonEmptyMap(); | |||
ComponentDto createdBranch = createButDoNotInsertBranch(nonExistingProject); | |||
BranchSupport.ComponentKey componentKey = createComponentKeyOfBranch(createdBranch); | |||
when(branchSupportDelegate.createComponentKey(nonExistingProject.getDbKey(), randomCharacteristics)) | |||
.thenReturn(componentKey); | |||
when(branchSupportDelegate.createBranchComponent(any(DbSession.class), same(componentKey), eq(organization), eq(nonExistingProject))) | |||
.thenReturn(createdBranch); | |||
InputStream reportInput = IOUtils.toInputStream("{binary}", StandardCharsets.UTF_8); | |||
expectedException.expect(ForbiddenException.class); | |||
expectedException.expectMessage("Insufficient privileges"); | |||
underTest.submit(organization.getKey(), nonExistingProject.getDbKey(), null, nonExistingProject.name(), randomCharacteristics, reportInput); | |||
} | |||
private static ComponentDto createButDoNotInsertBranch(ComponentDto project) { | |||
BranchType randomBranchType = BranchType.values()[new Random().nextInt(BranchType.values().length)]; | |||
BranchDto branchDto = newBranchDto(project.projectUuid(), randomBranchType); | |||
return ComponentTesting.newProjectBranch(project, branchDto); | |||
} | |||
private String mockSuccessfulPrepareSubmitCall() { | |||
String taskUuid = RandomStringUtils.randomAlphabetic(12); | |||
when(queue.prepareSubmit()).thenReturn(new CeTaskSubmit.Builder(taskUuid)); | |||
return taskUuid; | |||
} | |||
private void verifyQueueSubmit(ComponentDto project, ComponentDto branch, UserDto user, Map<String, String> characteristics, String taskUuid) { | |||
verify(queue).submit(argThat(submit -> submit.getType().equals(CeTaskTypes.REPORT) | |||
&& submit.getComponent().filter(cpt -> cpt.getUuid().equals(branch.uuid()) && cpt.getMainComponentUuid().equals(project.uuid())).isPresent() | |||
&& submit.getSubmitterUuid().equals(user.getUuid()) | |||
&& submit.getCharacteristics().equals(characteristics) | |||
&& submit.getUuid().equals(taskUuid))); | |||
} | |||
private static BranchSupport.ComponentKey createComponentKeyOfBranch(ComponentDto branch) { | |||
BranchSupport.ComponentKey mainComponentKey = mockComponentKey(branch.getKey(), branch.getKey()); | |||
when(mainComponentKey.getMainBranchComponentKey()).thenReturn(mainComponentKey); | |||
BranchSupport.ComponentKey componentKey = mockComponentKey(branch.getKey(), branch.getDbKey()); | |||
when(componentKey.getMainBranchComponentKey()).thenReturn(mainComponentKey); | |||
return componentKey; | |||
} | |||
private static BranchSupport.ComponentKey mockComponentKey(String key, String dbKey) { | |||
BranchSupport.ComponentKey componentKey = mock(BranchSupport.ComponentKey.class); | |||
when(componentKey.isDeprecatedBranch()).thenReturn(false); | |||
when(componentKey.isMainBranch()).thenReturn(key.equals(dbKey)); | |||
when(componentKey.getKey()).thenReturn(key); | |||
when(componentKey.getDbKey()).thenReturn(dbKey); | |||
return componentKey; | |||
} | |||
private static ImmutableMap<String, String> randomNonEmptyMap() { | |||
return IntStream.range(0, 1 + new Random().nextInt(5)) | |||
.boxed() | |||
.collect(uniqueIndex(i -> "key_" + i, i -> "val_" + i)); | |||
} | |||
} |
@@ -0,0 +1,166 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2018 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.server.ce.queue; | |||
import com.tngtech.java.junit.dataprovider.DataProvider; | |||
import com.tngtech.java.junit.dataprovider.DataProviderRunner; | |||
import com.tngtech.java.junit.dataprovider.UseDataProvider; | |||
import java.util.Collections; | |||
import java.util.Map; | |||
import java.util.Random; | |||
import java.util.stream.IntStream; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.junit.runner.RunWith; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.organization.OrganizationDto; | |||
import org.sonar.server.ce.queue.BranchSupport.ComponentKey; | |||
import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic; | |||
import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.when; | |||
import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex; | |||
@RunWith(DataProviderRunner.class) | |||
public class BranchSupportTest { | |||
private static final Map<String, String> NO_CHARACTERISTICS = Collections.emptyMap(); | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
private BranchSupportDelegate branchSupportDelegate = mock(BranchSupportDelegate.class); | |||
private BranchSupport underTestNoBranch = new BranchSupport(); | |||
private BranchSupport underTestWithBranch = new BranchSupport(branchSupportDelegate); | |||
@Test | |||
public void createComponentKey_of_main_branch() { | |||
String projectKey = randomAlphanumeric(12); | |||
ComponentKey componentKey = underTestNoBranch.createComponentKey(projectKey, null, NO_CHARACTERISTICS); | |||
assertThat(componentKey) | |||
.isEqualTo(underTestWithBranch.createComponentKey(projectKey, null, NO_CHARACTERISTICS)); | |||
assertThat(componentKey.getKey()).isEqualTo(projectKey); | |||
assertThat(componentKey.getDbKey()).isEqualTo(projectKey); | |||
assertThat(componentKey.isMainBranch()).isTrue(); | |||
assertThat(componentKey.isDeprecatedBranch()).isFalse(); | |||
assertThat(componentKey.getMainBranchComponentKey()).isSameAs(componentKey); | |||
assertThat(componentKey.getBranchName()).isEmpty(); | |||
assertThat(componentKey.getPullRequestKey()).isEmpty(); | |||
} | |||
@Test | |||
public void createComponentKey_of_deprecated_branch() { | |||
String projectKey = randomAlphanumeric(12); | |||
String deprecatedBranchName = randomAlphanumeric(12); | |||
ComponentKey componentKey = underTestNoBranch.createComponentKey(projectKey, deprecatedBranchName, NO_CHARACTERISTICS); | |||
assertThat(componentKey) | |||
.isEqualTo(underTestWithBranch.createComponentKey(projectKey, deprecatedBranchName, NO_CHARACTERISTICS)); | |||
assertThat(componentKey.getKey()).isEqualTo(projectKey); | |||
assertThat(componentKey.getDbKey()).isEqualTo(projectKey + ":" + deprecatedBranchName); | |||
assertThat(componentKey.isMainBranch()).isFalse(); | |||
assertThat(componentKey.isDeprecatedBranch()).isTrue(); | |||
assertThat(componentKey.getMainBranchComponentKey()).isSameAs(componentKey); | |||
assertThat(componentKey.getBranchName()).isEmpty(); | |||
assertThat(componentKey.getPullRequestKey()).isEmpty(); | |||
} | |||
@Test | |||
@UseDataProvider("nullOrNonEmpty") | |||
public void createComponentKey_with_ISE_if_characteristics_is_not_empty_and_delegate_is_null(String deprecatedBranchName) { | |||
String projectKey = randomAlphanumeric(12); | |||
Map<String, String> nonEmptyMap = newRandomNonEmptyMap(); | |||
expectedException.expect(IllegalStateException.class); | |||
expectedException.expectMessage("Current edition does not support branch feature"); | |||
underTestNoBranch.createComponentKey(projectKey, deprecatedBranchName, nonEmptyMap); | |||
} | |||
@Test | |||
public void createComponentKey_fails_with_IAE_if_characteristics_is_not_empty_and_deprecatedBranchName_is_non_null() { | |||
String projectKey = randomAlphanumeric(12); | |||
String deprecatedBranchName = randomAlphanumeric(13); | |||
Map<String, String> nonEmptyMap = newRandomNonEmptyMap(); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("Deprecated branch feature can't be used at the same time as new branch support"); | |||
underTestWithBranch.createComponentKey(projectKey, deprecatedBranchName, nonEmptyMap); | |||
} | |||
@Test | |||
public void createComponentKey_delegates_to_delegate_if_characteristics_is_not_empty() { | |||
String projectKey = randomAlphanumeric(12); | |||
Map<String, String> nonEmptyMap = newRandomNonEmptyMap(); | |||
ComponentKey expected = mock(ComponentKey.class); | |||
when(branchSupportDelegate.createComponentKey(projectKey, nonEmptyMap)).thenReturn(expected); | |||
ComponentKey componentKey = underTestWithBranch.createComponentKey(projectKey, null, nonEmptyMap); | |||
assertThat(componentKey).isSameAs(expected); | |||
} | |||
@Test | |||
public void createBranchComponent_fails_with_ISE_if_delegate_is_null() { | |||
DbSession dbSession = mock(DbSession.class); | |||
ComponentKey componentKey = mock(ComponentKey.class); | |||
OrganizationDto organization = new OrganizationDto(); | |||
ComponentDto mainComponentDto = new ComponentDto(); | |||
expectedException.expect(IllegalStateException.class); | |||
expectedException.expectMessage("Current edition does not support branch feature"); | |||
underTestNoBranch.createBranchComponent(dbSession, componentKey, organization, mainComponentDto); | |||
} | |||
@Test | |||
public void createBranchComponent_delegates_to_delegate() { | |||
DbSession dbSession = mock(DbSession.class); | |||
ComponentKey componentKey = mock(ComponentKey.class); | |||
OrganizationDto organization = new OrganizationDto(); | |||
ComponentDto mainComponentDto = new ComponentDto(); | |||
ComponentDto expected = new ComponentDto(); | |||
when(branchSupportDelegate.createBranchComponent(dbSession, componentKey, organization, mainComponentDto)) | |||
.thenReturn(expected); | |||
ComponentDto dto = underTestWithBranch.createBranchComponent(dbSession, componentKey, organization, mainComponentDto); | |||
assertThat(dto).isSameAs(expected); | |||
} | |||
@DataProvider | |||
public static Object[][] nullOrNonEmpty() { | |||
return new Object[][] { | |||
{null}, | |||
{randomAlphabetic(5)}, | |||
}; | |||
} | |||
private static Map<String, String> newRandomNonEmptyMap() { | |||
return IntStream.range(0, 1 + new Random().nextInt(10)).boxed().collect(uniqueIndex(i -> "key_" + i, i -> "val_" + i)); | |||
} | |||
} |
@@ -19,15 +19,16 @@ | |||
*/ | |||
package org.sonar.server.ce.queue; | |||
import com.google.common.collect.ImmutableMap; | |||
import java.io.InputStream; | |||
import java.nio.charset.StandardCharsets; | |||
import java.util.Map; | |||
import java.util.Random; | |||
import java.util.stream.IntStream; | |||
import org.apache.commons.io.IOUtils; | |||
import org.junit.Before; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.mockito.ArgumentCaptor; | |||
import org.sonar.api.resources.Qualifiers; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.ce.queue.CeQueue; | |||
@@ -36,7 +37,6 @@ import org.sonar.ce.queue.CeTaskSubmit; | |||
import org.sonar.core.permission.GlobalPermissions; | |||
import org.sonar.db.DbSession; | |||
import org.sonar.db.DbTester; | |||
import org.sonar.db.ce.CeTaskCharacteristicDto; | |||
import org.sonar.db.ce.CeTaskTypes; | |||
import org.sonar.db.component.ComponentDto; | |||
import org.sonar.db.component.ComponentTesting; | |||
@@ -55,8 +55,8 @@ import org.sonar.server.tester.UserSessionRule; | |||
import static java.lang.String.format; | |||
import static java.nio.charset.StandardCharsets.UTF_8; | |||
import static java.util.Collections.emptyMap; | |||
import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.assertj.core.api.Assertions.entry; | |||
import static org.junit.Assert.fail; | |||
import static org.mockito.ArgumentMatchers.any; | |||
import static org.mockito.ArgumentMatchers.argThat; | |||
@@ -67,6 +67,7 @@ import static org.mockito.Mockito.verify; | |||
import static org.mockito.Mockito.verifyZeroInteractions; | |||
import static org.mockito.Mockito.when; | |||
import static org.sonar.core.permission.GlobalPermissions.SCAN_EXECUTION; | |||
import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex; | |||
import static org.sonar.db.component.ComponentTesting.newModuleDto; | |||
import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto; | |||
import static org.sonar.db.permission.OrganizationPermission.PROVISION_PROJECTS; | |||
@@ -92,8 +93,9 @@ public class ReportSubmitterTest { | |||
private ComponentUpdater componentUpdater = mock(ComponentUpdater.class); | |||
private PermissionTemplateService permissionTemplateService = mock(PermissionTemplateService.class); | |||
private FavoriteUpdater favoriteUpdater = mock(FavoriteUpdater.class); | |||
private BranchSupport ossEditionBranchSupport = new BranchSupport(); | |||
private ReportSubmitter underTest = new ReportSubmitter(queue, userSession, componentUpdater, permissionTemplateService, db.getDbClient()); | |||
private ReportSubmitter underTest = new ReportSubmitter(queue, userSession, componentUpdater, permissionTemplateService, db.getDbClient(), ossEditionBranchSupport); | |||
@Before | |||
public void setUp() throws Exception { | |||
@@ -102,25 +104,45 @@ public class ReportSubmitterTest { | |||
} | |||
@Test | |||
public void submit_stores_report() { | |||
public void submit_with_characteristics_fails_with_ISE_when_no_branch_support_delegate() { | |||
userSession | |||
.addPermission(OrganizationPermission.SCAN, db.getDefaultOrganization().getUuid()) | |||
.addPermission(PROVISION_PROJECTS, db.getDefaultOrganization()); | |||
mockSuccessfulPrepareSubmitCall(); | |||
ComponentDto project = newPrivateProjectDto(db.getDefaultOrganization(), PROJECT_UUID).setDbKey(PROJECT_KEY); | |||
mockSuccessfulPrepareSubmitCall(); | |||
when(componentUpdater.create(any(), any(), any())).thenReturn(project); | |||
when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(), eq(defaultOrganizationUuid), any(), eq(PROJECT_KEY), | |||
eq(Qualifiers.PROJECT))) | |||
.thenReturn(true); | |||
Map<String, String> nonEmptyCharacteristics = IntStream.range(0, 1 + new Random().nextInt(5)) | |||
.boxed() | |||
.collect(uniqueIndex(i -> randomAlphabetic(i + 10), i -> randomAlphabetic(i + 20))); | |||
InputStream reportInput = IOUtils.toInputStream("{binary}", UTF_8); | |||
expectedException.expect(IllegalStateException.class); | |||
expectedException.expectMessage("Current edition does not support branch feature"); | |||
underTest.submit(defaultOrganizationKey, PROJECT_KEY, null, PROJECT_NAME, nonEmptyCharacteristics, reportInput); | |||
} | |||
@Test | |||
public void submit_stores_report() { | |||
userSession | |||
.addPermission(OrganizationPermission.SCAN, db.getDefaultOrganization().getUuid()) | |||
.addPermission(PROVISION_PROJECTS, db.getDefaultOrganization()); | |||
ComponentDto project = newPrivateProjectDto(db.getDefaultOrganization(), PROJECT_UUID).setDbKey(PROJECT_KEY); | |||
mockSuccessfulPrepareSubmitCall(); | |||
when(componentUpdater.createWithoutCommit(any(), any(), any())).thenReturn(project); | |||
when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(), eq(defaultOrganizationUuid), any(), eq(PROJECT_KEY), | |||
eq(Qualifiers.PROJECT))) | |||
.thenReturn(true); | |||
Map<String, String> taskCharacteristics = ImmutableMap.of(CeTaskCharacteristicDto.PULL_REQUEST, "123"); | |||
underTest.submit(defaultOrganizationKey, PROJECT_KEY, null, PROJECT_NAME, taskCharacteristics, IOUtils.toInputStream("{binary}", UTF_8)); | |||
underTest.submit(defaultOrganizationKey, PROJECT_KEY, null, PROJECT_NAME, emptyMap(), IOUtils.toInputStream("{binary}", UTF_8)); | |||
ArgumentCaptor<CeTaskSubmit> submittedTask = ArgumentCaptor.forClass(CeTaskSubmit.class); | |||
verify(queue).submit(submittedTask.capture()); | |||
assertThat(submittedTask.getValue().getCharacteristics()) | |||
.containsExactly(entry("pullRequest", "123")); | |||
verifyReportIsPersisted(TASK_UUID); | |||
verify(componentUpdater).commitAndIndex(any(DbSession.class), eq(project)); | |||
} | |||
@Test | |||
@@ -128,7 +150,6 @@ public class ReportSubmitterTest { | |||
ComponentDto project = db.components().insertPrivateProject(db.getDefaultOrganization()); | |||
UserDto user = db.users().insertUser(); | |||
userSession.logIn(user).addProjectPermission(SCAN_EXECUTION, project); | |||
mockSuccessfulPrepareSubmitCall(); | |||
underTest.submit(defaultOrganizationKey, project.getDbKey(), null, project.name(), emptyMap(), IOUtils.toInputStream("{binary}", StandardCharsets.UTF_8)); | |||
@@ -137,7 +158,7 @@ public class ReportSubmitterTest { | |||
verifyZeroInteractions(permissionTemplateService); | |||
verifyZeroInteractions(favoriteUpdater); | |||
verify(queue).submit(argThat(submit -> submit.getType().equals(CeTaskTypes.REPORT) | |||
&& submit.getComponentUuid().equals(project.uuid()) | |||
&& submit.getComponent().filter(cpt -> cpt.getUuid().equals(project.uuid()) && cpt.getMainComponentUuid().equals(project.uuid())).isPresent() | |||
&& submit.getSubmitterUuid().equals(user.getUuid()) | |||
&& submit.getUuid().equals(TASK_UUID))); | |||
} | |||
@@ -151,7 +172,7 @@ public class ReportSubmitterTest { | |||
mockSuccessfulPrepareSubmitCall(); | |||
ComponentDto createdProject = newPrivateProjectDto(organization, PROJECT_UUID).setDbKey(PROJECT_KEY); | |||
when(componentUpdater.create(any(), any(), isNull())).thenReturn(createdProject); | |||
when(componentUpdater.createWithoutCommit(any(), any(), isNull())).thenReturn(createdProject); | |||
when( | |||
permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(), eq(organization.getUuid()), any(), eq(PROJECT_KEY), eq(Qualifiers.PROJECT))) | |||
.thenReturn(true); | |||
@@ -160,7 +181,10 @@ public class ReportSubmitterTest { | |||
underTest.submit(organization.getKey(), PROJECT_KEY, null, PROJECT_NAME, emptyMap(), IOUtils.toInputStream("{binary}")); | |||
verifyReportIsPersisted(TASK_UUID); | |||
verify(queue).submit(argThat(submit -> submit.getType().equals(CeTaskTypes.REPORT) && submit.getComponentUuid().equals(PROJECT_UUID) && submit.getUuid().equals(TASK_UUID))); | |||
verify(queue).submit(argThat(submit -> submit.getType().equals(CeTaskTypes.REPORT) | |||
&& submit.getComponent().filter(cpt -> cpt.getUuid().equals(PROJECT_UUID) && cpt.getMainComponentUuid().equals(PROJECT_UUID)).isPresent() | |||
&& submit.getUuid().equals(TASK_UUID))); | |||
verify(componentUpdater).commitAndIndex(any(DbSession.class), eq(createdProject)); | |||
} | |||
@Test | |||
@@ -169,17 +193,18 @@ public class ReportSubmitterTest { | |||
.addPermission(OrganizationPermission.SCAN, db.getDefaultOrganization().getUuid()) | |||
.addPermission(PROVISION_PROJECTS, db.getDefaultOrganization()); | |||
mockSuccessfulPrepareSubmitCall(); | |||
ComponentDto createdProject = newPrivateProjectDto(db.getDefaultOrganization(), PROJECT_UUID).setDbKey(PROJECT_KEY); | |||
when(componentUpdater.create(any(), any(), isNull())).thenReturn(createdProject); | |||
when(componentUpdater.createWithoutCommit(any(), any(), isNull())).thenReturn(createdProject); | |||
when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(), eq(defaultOrganizationUuid), any(), | |||
eq(PROJECT_KEY), eq(Qualifiers.PROJECT))) | |||
.thenReturn(true); | |||
when(permissionTemplateService.hasDefaultTemplateWithPermissionOnProjectCreator(any(), eq(defaultOrganizationUuid), any())).thenReturn(false); | |||
mockSuccessfulPrepareSubmitCall(); | |||
underTest.submit(defaultOrganizationKey, PROJECT_KEY, null, PROJECT_NAME, emptyMap(), IOUtils.toInputStream("{binary}")); | |||
verifyZeroInteractions(favoriteUpdater); | |||
verify(componentUpdater).commitAndIndex(any(DbSession.class), eq(createdProject)); | |||
} | |||
@Test | |||
@@ -188,9 +213,9 @@ public class ReportSubmitterTest { | |||
.addPermission(OrganizationPermission.SCAN, db.getDefaultOrganization().getUuid()) | |||
.addPermission(PROVISION_PROJECTS, db.getDefaultOrganization()); | |||
mockSuccessfulPrepareSubmitCall(); | |||
ComponentDto project = newPrivateProjectDto(db.getDefaultOrganization(), PROJECT_UUID).setDbKey(PROJECT_KEY); | |||
when(componentUpdater.create(any(), any(), any())).thenReturn(project); | |||
mockSuccessfulPrepareSubmitCall(); | |||
when(componentUpdater.createWithoutCommit(any(), any(), any())).thenReturn(project); | |||
when(permissionTemplateService.wouldUserHaveScanPermissionWithDefaultTemplate(any(), eq(defaultOrganizationUuid), any(), | |||
eq(PROJECT_KEY), eq(Qualifiers.PROJECT))) | |||
.thenReturn(true); | |||
@@ -198,6 +223,7 @@ public class ReportSubmitterTest { | |||
underTest.submit(defaultOrganizationKey, PROJECT_KEY, null, PROJECT_NAME, emptyMap(), IOUtils.toInputStream("{binary}")); | |||
verify(queue).submit(any(CeTaskSubmit.class)); | |||
verify(componentUpdater).commitAndIndex(any(DbSession.class), eq(project)); | |||
} | |||
@Test | |||
@@ -205,7 +231,6 @@ public class ReportSubmitterTest { | |||
OrganizationDto org = db.organizations().insert(); | |||
ComponentDto project = db.components().insertPrivateProject(org); | |||
userSession.addPermission(SCAN, org); | |||
mockSuccessfulPrepareSubmitCall(); | |||
underTest.submit(org.getKey(), project.getDbKey(), null, project.name(), emptyMap(), IOUtils.toInputStream("{binary}")); | |||
@@ -217,7 +242,6 @@ public class ReportSubmitterTest { | |||
public void submit_a_report_on_existing_project_with_project_scan_permission() { | |||
ComponentDto project = db.components().insertPrivateProject(db.getDefaultOrganization()); | |||
userSession.addProjectPermission(SCAN_EXECUTION, project); | |||
mockSuccessfulPrepareSubmitCall(); | |||
underTest.submit(defaultOrganizationKey, project.getDbKey(), null, project.name(), emptyMap(), IOUtils.toInputStream("{binary}")); | |||
@@ -230,15 +254,16 @@ public class ReportSubmitterTest { | |||
*/ | |||
@Test | |||
public void project_branch_must_not_benefit_from_the_scan_permission_on_main_project() { | |||
String branchName = "branchFoo"; | |||
ComponentDto mainProject = db.components().insertPrivateProject(); | |||
userSession.addProjectPermission(GlobalPermissions.SCAN_EXECUTION, mainProject); | |||
// user does not have the "scan" permission on the branch, so it can't scan it | |||
String branchName = "branchFoo"; | |||
ComponentDto branchProject = db.components().insertPrivateProject(p -> p.setDbKey(mainProject.getDbKey() + ":" + branchName)); | |||
expectedException.expect(ForbiddenException.class); | |||
underTest.submit(defaultOrganizationKey, mainProject.getDbKey(), branchName, PROJECT_NAME,emptyMap(), IOUtils.toInputStream("{binary}")); | |||
underTest.submit(defaultOrganizationKey, mainProject.getDbKey(), branchName, PROJECT_NAME, emptyMap(), IOUtils.toInputStream("{binary}")); | |||
} | |||
@Test | |||
@@ -298,8 +323,8 @@ public class ReportSubmitterTest { | |||
@Test | |||
public void fail_with_forbidden_exception_on_new_project_when_only_project_scan_permission() { | |||
userSession.addProjectPermission(SCAN_EXECUTION, ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization(), PROJECT_UUID)); | |||
ComponentDto component = ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization(), PROJECT_UUID); | |||
userSession.addProjectPermission(SCAN_EXECUTION, component); | |||
mockSuccessfulPrepareSubmitCall(); | |||
when(componentUpdater.create(any(DbSession.class), any(NewComponent.class), eq(null))).thenReturn(new ComponentDto().setUuid(PROJECT_UUID).setDbKey(PROJECT_KEY)); | |||
@@ -507,7 +507,7 @@ public class ActivityActionTest { | |||
private CeQueueDto insertQueue(String taskUuid, @Nullable ComponentDto project, CeQueueDto.Status status) { | |||
CeQueueDto queueDto = new CeQueueDto(); | |||
queueDto.setTaskType(CeTaskTypes.REPORT); | |||
queueDto.setComponentUuid(project == null ? null : project.uuid()); | |||
queueDto.setComponent(project); | |||
queueDto.setUuid(taskUuid); | |||
queueDto.setStatus(status); | |||
db.getDbClient().ceQueueDao().insert(db.getSession(), queueDto); | |||
@@ -522,7 +522,7 @@ public class ActivityActionTest { | |||
private CeActivityDto insertActivity(String taskUuid, ComponentDto project, Status status, @Nullable SnapshotDto analysis) { | |||
CeQueueDto queueDto = new CeQueueDto(); | |||
queueDto.setTaskType(CeTaskTypes.REPORT); | |||
queueDto.setComponentUuid(project.uuid()); | |||
queueDto.setComponent(project); | |||
queueDto.setUuid(taskUuid); | |||
queueDto.setCreatedAt(EXECUTED_AT); | |||
CeActivityDto activityDto = new CeActivityDto(queueDto); |
@@ -45,9 +45,9 @@ import org.sonarqube.ws.Ce; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.sonar.db.ce.CeQueueTesting.newCeQueueDto; | |||
import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto; | |||
import static org.sonar.test.JsonAssert.assertJson; | |||
import static org.sonar.server.ce.ws.CeWsParameters.DEPRECATED_PARAM_COMPONENT_KEY; | |||
import static org.sonar.server.ce.ws.CeWsParameters.PARAM_COMPONENT_ID; | |||
import static org.sonar.test.JsonAssert.assertJson; | |||
public class ActivityStatusActionTest { | |||
@@ -84,22 +84,23 @@ public class ActivityStatusActionTest { | |||
String anotherProjectUuid = "another-project-uuid"; | |||
OrganizationDto organizationDto = db.organizations().insert(); | |||
ComponentDto project = newPrivateProjectDto(organizationDto, projectUuid); | |||
ComponentDto anotherProject = newPrivateProjectDto(organizationDto, anotherProjectUuid); | |||
db.components().insertComponent(project); | |||
db.components().insertComponent(newPrivateProjectDto(organizationDto, anotherProjectUuid)); | |||
userSession.logIn().addProjectPermission(UserRole.ADMIN, project); | |||
// pending tasks returned | |||
insertInQueue(CeQueueDto.Status.PENDING, projectUuid); | |||
insertInQueue(CeQueueDto.Status.PENDING, projectUuid); | |||
insertInQueue(CeQueueDto.Status.PENDING, project); | |||
insertInQueue(CeQueueDto.Status.PENDING, project); | |||
// other tasks not returned | |||
insertInQueue(CeQueueDto.Status.IN_PROGRESS, projectUuid); | |||
insertInQueue(CeQueueDto.Status.PENDING, anotherProjectUuid); | |||
insertInQueue(CeQueueDto.Status.IN_PROGRESS, project); | |||
insertInQueue(CeQueueDto.Status.PENDING, anotherProject); | |||
insertInQueue(CeQueueDto.Status.PENDING, null); | |||
// only one last activity for a given project | |||
insertActivity(CeActivityDto.Status.SUCCESS, projectUuid); | |||
insertActivity(CeActivityDto.Status.CANCELED, projectUuid); | |||
insertActivity(CeActivityDto.Status.FAILED, projectUuid); | |||
insertActivity(CeActivityDto.Status.FAILED, projectUuid); | |||
insertActivity(CeActivityDto.Status.FAILED, anotherProjectUuid); | |||
insertActivity(CeActivityDto.Status.SUCCESS, project); | |||
insertActivity(CeActivityDto.Status.CANCELED, project); | |||
insertActivity(CeActivityDto.Status.FAILED, project); | |||
insertActivity(CeActivityDto.Status.FAILED, project); | |||
insertActivity(CeActivityDto.Status.FAILED, anotherProject); | |||
Ce.ActivityStatusWsResponse result = call(projectUuid); | |||
@@ -159,18 +160,18 @@ public class ActivityStatusActionTest { | |||
callByComponentKey(project.getDbKey()); | |||
} | |||
private void insertInQueue(CeQueueDto.Status status, @Nullable String componentUuid) { | |||
private void insertInQueue(CeQueueDto.Status status, @Nullable ComponentDto componentDto) { | |||
dbClient.ceQueueDao().insert(dbSession, newCeQueueDto(Uuids.createFast()) | |||
.setStatus(status) | |||
.setComponentUuid(componentUuid)); | |||
.setComponent(componentDto)); | |||
db.commit(); | |||
} | |||
private void insertActivity(CeActivityDto.Status status, @Nullable String componentUuid) { | |||
dbClient.ceActivityDao().insert(dbSession, new CeActivityDto( | |||
newCeQueueDto(Uuids.createFast()) | |||
.setComponentUuid(componentUuid)) | |||
.setStatus(status)); | |||
private void insertActivity(CeActivityDto.Status status, @Nullable ComponentDto dto) { | |||
CeQueueDto ceQueueDto = newCeQueueDto(Uuids.createFast()); | |||
ceQueueDto.setComponent(dto); | |||
dbClient.ceActivityDao().insert(dbSession, new CeActivityDto(ceQueueDto) | |||
.setStatus(status)); | |||
db.commit(); | |||
} | |||
@@ -62,7 +62,7 @@ public class CancelActionTest { | |||
public void cancel_pending_task_on_project() { | |||
logInAsSystemAdministrator(); | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
CeQueueDto queue = createTaskSubmit(project.uuid()); | |||
CeQueueDto queue = createTaskSubmit(project); | |||
tester.newRequest() | |||
.setParam("id", queue.getUuid()) | |||
@@ -87,7 +87,7 @@ public class CancelActionTest { | |||
public void cancel_pending_task_when_system_administer() { | |||
logInAsSystemAdministrator(); | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
CeQueueDto queue = createTaskSubmit(project.uuid()); | |||
CeQueueDto queue = createTaskSubmit(project); | |||
tester.newRequest() | |||
.setParam("id", queue.getUuid()) | |||
@@ -100,7 +100,7 @@ public class CancelActionTest { | |||
public void cancel_pending_task_when_project_administer() { | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
userSession.addProjectPermission(UserRole.ADMIN, project); | |||
CeQueueDto queue = createTaskSubmit(project.uuid()); | |||
CeQueueDto queue = createTaskSubmit(project); | |||
tester.newRequest() | |||
.setParam("id", queue.getUuid()) | |||
@@ -132,7 +132,7 @@ public class CancelActionTest { | |||
public void throw_ForbiddenException_if_not_enough_permission_when_canceling_task_on_project() { | |||
userSession.logIn().setNonSystemAdministrator(); | |||
ComponentDto project = db.components().insertPrivateProject(); | |||
CeQueueDto queue = createTaskSubmit(project.uuid()); | |||
CeQueueDto queue = createTaskSubmit(project); | |||
expectedException.expect(ForbiddenException.class); | |||
expectedException.expectMessage("Insufficient privileges"); | |||
@@ -158,7 +158,7 @@ public class CancelActionTest { | |||
@Test | |||
public void throw_ForbiddenException_if_not_enough_permission_when_canceling_task_when_project_does_not_exist() { | |||
userSession.logIn().setNonSystemAdministrator(); | |||
CeQueueDto queue = createTaskSubmit("UNKNOWN"); | |||
CeQueueDto queue = createTaskSubmit(nonExistentComponentDot()); | |||
expectedException.expect(ForbiddenException.class); | |||
expectedException.expectMessage("Insufficient privileges"); | |||
@@ -168,16 +168,22 @@ public class CancelActionTest { | |||
.execute(); | |||
} | |||
private static ComponentDto nonExistentComponentDot() { | |||
return new ComponentDto().setUuid("does_not_exist").setProjectUuid("unknown"); | |||
} | |||
private void logInAsSystemAdministrator() { | |||
userSession.logIn().setSystemAdministrator(); | |||
} | |||
private CeQueueDto createTaskSubmit(@Nullable String componentUuid) { | |||
private CeQueueDto createTaskSubmit(@Nullable ComponentDto componentDto) { | |||
CeTaskSubmit.Builder submission = queue.prepareSubmit() | |||
.setType(CeTaskTypes.REPORT) | |||
.setComponentUuid(componentUuid) | |||
.setSubmitterUuid(null) | |||
.setCharacteristics(emptyMap()); | |||
if (componentDto != null) { | |||
submission.setComponent(CeTaskSubmit.Component.fromDto(componentDto)); | |||
} | |||
CeTask task = queue.submit(submission.build()); | |||
return db.getDbClient().ceQueueDao().selectByUuid(db.getSession(), task.getUuid()).get(); | |||
} |
@@ -281,7 +281,7 @@ public class ComponentActionTest { | |||
private CeQueueDto insertQueue(String taskUuid, ComponentDto component, CeQueueDto.Status status) { | |||
CeQueueDto queueDto = new CeQueueDto(); | |||
queueDto.setTaskType(CeTaskTypes.REPORT); | |||
queueDto.setComponentUuid(component.uuid()); | |||
queueDto.setComponent(component); | |||
queueDto.setUuid(taskUuid); | |||
queueDto.setStatus(status); | |||
db.getDbClient().ceQueueDao().insert(db.getSession(), queueDto); | |||
@@ -296,7 +296,7 @@ public class ComponentActionTest { | |||
private CeActivityDto insertActivity(String taskUuid, ComponentDto component, CeActivityDto.Status status, @Nullable SnapshotDto analysis) { | |||
CeQueueDto queueDto = new CeQueueDto(); | |||
queueDto.setTaskType(CeTaskTypes.REPORT); | |||
queueDto.setComponentUuid(component.uuid()); | |||
queueDto.setComponent(component); | |||
queueDto.setUuid(taskUuid); | |||
CeActivityDto activityDto = new CeActivityDto(queueDto); | |||
activityDto.setStatus(status); |
@@ -51,11 +51,14 @@ import static org.mockito.Mockito.when; | |||
public class SubmitActionTest { | |||
private static final String PROJECT_UUID = "PROJECT_1"; | |||
private static final CeTask.Component COMPONENT = new CeTask.Component(PROJECT_UUID, "KEY_1", "NAME_1"); | |||
private static final CeTask A_CE_TASK = new CeTask.Builder() | |||
.setOrganizationUuid("org1") | |||
.setUuid("TASK_1") | |||
.setType(CeTaskTypes.REPORT) | |||
.setComponentUuid("PROJECT_1") | |||
.setComponent(COMPONENT) | |||
.setMainComponent(COMPONENT) | |||
.setSubmitterUuid("robert") | |||
.build(); | |||
@@ -89,7 +92,7 @@ public class SubmitActionTest { | |||
anyMap(), any()); | |||
assertThat(submitResponse.getTaskId()).isEqualTo("TASK_1"); | |||
assertThat(submitResponse.getProjectId()).isEqualTo("PROJECT_1"); | |||
assertThat(submitResponse.getProjectId()).isEqualTo(PROJECT_UUID); | |||
} | |||
@Test | |||
@@ -132,7 +135,7 @@ public class SubmitActionTest { | |||
anyMap(), any()); | |||
assertThat(submitResponse.getTaskId()).isEqualTo("TASK_1"); | |||
assertThat(submitResponse.getProjectId()).isEqualTo("PROJECT_1"); | |||
assertThat(submitResponse.getProjectId()).isEqualTo(PROJECT_UUID); | |||
} | |||
@Test |
@@ -266,7 +266,7 @@ public class UpdateVisibilityActionTest { | |||
} | |||
@Test | |||
public void execute_throws_BadRequestException_if_specified_component_has_in_progress_tasks() { | |||
public void execute_throws_BadRequestException_if_main_component_of_specified_component_has_in_progress_tasks() { | |||
ComponentDto project = randomPublicOrPrivateProject(); | |||
IntStream.range(0, 1 + Math.abs(random.nextInt(5))) | |||
.forEach(i -> insertInProgressTask(project)); | |||
@@ -734,7 +734,7 @@ public class UpdateVisibilityActionTest { | |||
private void insertCeQueueDto(ComponentDto project, CeQueueDto.Status status) { | |||
dbClient.ceQueueDao().insert(dbTester.getSession(), new CeQueueDto() | |||
.setUuid("pending" + counter++) | |||
.setComponentUuid(project.uuid()) | |||
.setComponent(project) | |||
.setTaskType("foo") | |||
.setStatus(status)); | |||
dbTester.commit(); |