"IS_LAST" BOOLEAN NOT NULL,
"IS_LAST_KEY" VARCHAR(55) NOT NULL,
"SUBMITTER_LOGIN" 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,
*/
package org.sonar.db.ce;
-import com.google.common.base.MoreObjects;
import com.google.common.base.Strings;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
private boolean isLast;
private String isLastKey;
private String submitterLogin;
+ private String workerUuid;
+ private int executionCount;
private long submittedAt;
private Long startedAt;
private Long executedAt;
this.componentUuid = queueDto.getComponentUuid();
this.isLastKey = format("%s%s", taskType, Strings.nullToEmpty(componentUuid));
this.submitterLogin = queueDto.getSubmitterLogin();
+ this.workerUuid = queueDto.getWorkerUuid();
+ this.executionCount = queueDto.getExecutionCount();
this.submittedAt = queueDto.getCreatedAt();
this.startedAt = queueDto.getStartedAt();
}
return this;
}
+ @CheckForNull
+ public String getWorkerUuid() {
+ return workerUuid;
+ }
+
+ public CeActivityDto setWorkerUuid(String workerUuid) {
+ this.workerUuid = workerUuid;
+ return this;
+ }
+
+ public int getExecutionCount() {
+ return executionCount;
+ }
+
+ public CeActivityDto setExecutionCount(int executionCount) {
+ this.executionCount = executionCount;
+ return this;
+ }
+
@CheckForNull
public String getErrorMessage() {
return errorMessage;
@Override
public String toString() {
- return MoreObjects.toStringHelper(this)
- .add("uuid", uuid)
- .add("taskType", taskType)
- .add("componentUuid", componentUuid)
- .add("analysisUuid", analysisUuid)
- .add("status", status)
- .add("isLast", isLast)
- .add("isLastKey", isLastKey)
- .add("submitterLogin", submitterLogin)
- .add("submittedAt", submittedAt)
- .add("startedAt", startedAt)
- .add("executedAt", executedAt)
- .add("createdAt", createdAt)
- .add("updatedAt", updatedAt)
- .add("executionTimeMs", executionTimeMs)
- .add("errorMessage", errorMessage)
- .add("errorStacktrace", errorStacktrace)
- .add("hasScannerContext", hasScannerContext)
- .toString();
+ return "CeActivityDto{" +
+ "uuid='" + uuid + '\'' +
+ ", componentUuid='" + componentUuid + '\'' +
+ ", analysisUuid='" + analysisUuid + '\'' +
+ ", status=" + status +
+ ", taskType='" + taskType + '\'' +
+ ", isLast=" + isLast +
+ ", isLastKey='" + isLastKey + '\'' +
+ ", submitterLogin='" + submitterLogin + '\'' +
+ ", workerUuid='" + workerUuid + '\'' +
+ ", executionCount=" + executionCount +
+ ", submittedAt=" + submittedAt +
+ ", startedAt=" + startedAt +
+ ", executedAt=" + executedAt +
+ ", createdAt=" + createdAt +
+ ", updatedAt=" + updatedAt +
+ ", executionTimeMs=" + executionTimeMs +
+ ", errorMessage='" + errorMessage + '\'' +
+ ", errorStacktrace='" + errorStacktrace + '\'' +
+ ", hasScannerContext=" + hasScannerContext +
+ '}';
}
}
ca.status as status,
ca.submitter_login as submitterLogin,
ca.submitted_at as submittedAt,
+ ca.worker_uuid as workerUuid,
+ ca.execution_count as executionCount,
ca.started_at as startedAt,
ca.executed_at as executedAt,
ca.created_at as createdAt,
is_last_key,
submitter_login,
submitted_at,
+ worker_uuid,
+ execution_count,
started_at,
executed_at,
created_at,
#{isLastKey,jdbcType=VARCHAR},
#{submitterLogin,jdbcType=VARCHAR},
#{submittedAt,jdbcType=BIGINT},
+ #{workerUuid,jdbcType=VARCHAR},
+ #{executionCount,jdbcType=INTEGER},
#{startedAt,jdbcType=BIGINT},
#{executedAt,jdbcType=BIGINT},
#{createdAt,jdbcType=BIGINT},
assertThat(dto.getComponentUuid()).isEqualTo("PROJECT_1");
assertThat(dto.getStatus()).isEqualTo(CeActivityDto.Status.SUCCESS);
assertThat(dto.getSubmitterLogin()).isEqualTo("henri");
+ assertThat(dto.getSubmittedAt()).isEqualTo(1_300_000_000_000L);
+ assertThat(dto.getWorkerUuid()).isEqualTo("worker uuid");
+ assertThat(dto.getExecutionCount()).isEqualTo(42);
assertThat(dto.getIsLast()).isTrue();
assertThat(dto.getIsLastKey()).isEqualTo("REPORTPROJECT_1");
- assertThat(dto.getSubmittedAt()).isEqualTo(1_300_000_000_000L);
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);
queueDto.setTaskType(type);
queueDto.setComponentUuid(componentUuid);
queueDto.setSubmitterLogin("henri");
+ queueDto.setWorkerUuid("worker uuid");
+ queueDto.setExecutionCount(42);
queueDto.setCreatedAt(1_300_000_000_000L);
CeActivityDto dto = new CeActivityDto(queueDto);
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.db.migration.version.v64;
+
+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.step.DdlChange;
+
+import static org.sonar.server.platform.db.migration.def.IntegerColumnDef.newIntegerColumnDefBuilder;
+
+public class AddCeActivityWorkerUuidAndExecutionCount extends DdlChange {
+
+ private static final String TABLE_CE_ACTIVITY = "ce_activity";
+
+ public AddCeActivityWorkerUuidAndExecutionCount(Database db) {
+ super(db);
+ }
+
+ @Override
+ public void execute(Context context) throws SQLException {
+ context.execute(new AddColumnsBuilder(getDialect(), TABLE_CE_ACTIVITY)
+ .addColumn(VarcharColumnDef.newVarcharColumnDefBuilder()
+ .setColumnName("worker_uuid")
+ .setLimit(VarcharColumnDef.UUID_SIZE)
+ .setIsNullable(true)
+ .build())
+ .addColumn(newIntegerColumnDefBuilder()
+ .setColumnName("execution_count")
+ .setIsNullable(true)
+ .build())
+ .build());
+ }
+}
;
.add(1628, "Add columns CE_QUEUE.WORKER_UUID and EXECUTION_COUNT", AddCeQueueWorkerUuidAndExecutionCount.class);
.add(1629, "Make CE_QUEUE.EXECUTION_COUNT not nullable", MakeCeQueueExecutionCountNotNullable.class);
+ .add(1630, "Add columns CE_ACTIVITY.WORKER_UUID and EXECUTION_COUNT", AddCeActivityWorkerUuidAndExecutionCount.class)
+ .add(1631, "Make columns CE_ACTIVITY.EXECUTION_COUNT not nullable", MakeCeActivityExecutionCountNotNullable.class);
}
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.db.migration.version.v64;
+
+import java.sql.SQLException;
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.sql.AlterColumnsBuilder;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+import static org.sonar.server.platform.db.migration.def.IntegerColumnDef.newIntegerColumnDefBuilder;
+
+public class MakeCeActivityExecutionCountNotNullable extends DdlChange {
+
+ private static final String TABLE_CE_ACTIVITY = "ce_activity";
+
+ public MakeCeActivityExecutionCountNotNullable(Database db) {
+ super(db);
+ }
+
+ @Override
+ public void execute(Context context) throws SQLException {
+ context.execute("update ce_activity set execution_count = 0 where execution_count is null and status = 'CANCELED'");
+ context.execute("update ce_activity set execution_count = 1 where execution_count is null and status in ('SUCCESS', 'FAILED')");
+
+ context.execute(new AlterColumnsBuilder(getDialect(), TABLE_CE_ACTIVITY)
+ .updateColumn(newIntegerColumnDefBuilder()
+ .setColumnName("execution_count")
+ .setIsNullable(false)
+ .build())
+ .build());
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.db.migration.version.v64;
+
+import java.sql.SQLException;
+import java.sql.Types;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.db.CoreDbTester;
+
+public class AddCeActivityWorkerUuidAndExecutionCountTest {
+ @Rule
+ public CoreDbTester db = CoreDbTester.createForSchema(AddCeActivityWorkerUuidAndExecutionCountTest.class, "ce_activity.sql");
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ private AddCeActivityWorkerUuidAndExecutionCount underTest = new AddCeActivityWorkerUuidAndExecutionCount(db.database());
+
+ @Test
+ public void execute_adds_columns_worker_uuid_and_processing_count() throws SQLException {
+ underTest.execute();
+
+ db.assertColumnDefinition("ce_activity", "worker_uuid", Types.VARCHAR, 40, true);
+ db.assertColumnDefinition("ce_activity", "execution_count", Types.INTEGER, null, true);
+ }
+
+ @Test
+ public void execute_is_not_reentreant() throws SQLException {
+ underTest.execute();
+
+ expectedException.expect(IllegalStateException.class);
+ expectedException.expectMessage("Fail to execute");
+
+ underTest.execute();
+ }
+}
@Test
public void verify_migration_count() {
- verifyMigrationCount(underTest, 29);
+ verifyMigrationCount(underTest, 31);
}
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.db.migration.version.v64;
+
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.List;
+import java.util.Random;
+import java.util.stream.Stream;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.core.util.stream.MoreCollectors;
+import org.sonar.db.CoreDbTester;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class MakeCeActivityExecutionCountNotNullableTest {
+
+ private static final String TABLE_CE_ACTIVITY = "ce_activity";
+
+ @Rule
+ public CoreDbTester db = CoreDbTester.createForSchema(MakeCeActivityExecutionCountNotNullableTest.class, "ce_activity.sql");
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ private MakeCeActivityExecutionCountNotNullable underTest = new MakeCeActivityExecutionCountNotNullable(db.database());
+
+ @Test
+ public void execute_makes_column_execution_count_not_nullable_when_table_is_empty() throws SQLException {
+ underTest.execute();
+
+ verifyColumnDefinition();
+ }
+
+ @Test
+ public void execute_set_column_execution_count_to_0_or_1_and_not_nullable_depending_on_status_of_the_task() throws SQLException {
+ insertCeActivity("u1", Status.SUCCESS);
+ insertCeActivity("u2", Status.FAILED);
+ insertCeActivity("u3", Status.CANCELED);
+
+ underTest.execute();
+
+ verifyColumnDefinition();
+ assertThat(getUuidsForExecutionCount(0)).containsOnly("u3");
+ assertThat(getUuidsForExecutionCount(1)).containsOnly("u1", "u2");
+ }
+
+ private List<Object> getUuidsForExecutionCount(int executionCount) {
+ return db.select("select uuid as \"UUID\" from ce_activity where execution_count=" + executionCount)
+ .stream()
+ .flatMap(row -> Stream.of(row.get("UUID")))
+ .collect(MoreCollectors.toList());
+ }
+
+ private void verifyColumnDefinition() {
+ db.assertColumnDefinition(TABLE_CE_ACTIVITY, "execution_count", Types.INTEGER, null, false);
+ }
+
+ private void insertCeActivity(String uuid, Status status) {
+ db.executeInsert(TABLE_CE_ACTIVITY,
+ "UUID", uuid,
+ "TASK_TYPE", uuid + "_type",
+ "STATUS", status.name(),
+ "IS_LAST", new Random().nextBoolean() + "",
+ "IS_LAST_KEY", "key",
+ "SUBMITTED_AT", new Random().nextLong() + "",
+ "CREATED_AT", new Random().nextLong() + "",
+ "UPDATED_AT", new Random().nextLong() + "");
+ }
+
+ public enum Status {
+ SUCCESS, FAILED, CANCELED
+ }
+
+}
--- /dev/null
+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_LOGIN" VARCHAR(255) 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(2147483647)
+);
+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");
--- /dev/null
+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_LOGIN" VARCHAR(255) NULL,
+ "WORKER_UUID" VARCHAR(40) NULL,
+ "EXECUTION_COUNT" INTEGER 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(2147483647)
+);
+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");
assertThat(activityDto.get().getErrorStacktrace()).isEqualToIgnoringWhitespace(stacktraceToString(error));
}
+ @Test
+ public void remove_copies_executionCount_and_workerUuid() {
+ dbTester.getDbClient().ceQueueDao().insert(session, new CeQueueDto()
+ .setUuid("uuid")
+ .setTaskType("foo")
+ .setStatus(CeQueueDto.Status.PENDING)
+ .setWorkerUuid("Dustin")
+ .setExecutionCount(2));
+ dbTester.commit();
+
+ underTest.remove(new CeTask.Builder()
+ .setOrganizationUuid("foo")
+ .setUuid("uuid")
+ .setType("bar")
+ .build(), CeActivityDto.Status.SUCCESS, null, null);
+
+ CeActivityDto dto = dbTester.getDbClient().ceActivityDao().selectByUuid(dbTester.getSession(), "uuid").get();
+ assertThat(dto.getExecutionCount()).isEqualTo(2);
+ assertThat(dto.getWorkerUuid()).isEqualTo("Dustin");
+ }
+
private static String stacktraceToString(Throwable error) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
error.printStackTrace(new PrintStream(out));
assertThat(peek.isPresent()).isFalse();
}
+ @Test
+ public void peek_increases_executionCount_and_override_workerUuid_to_argument() {
+ dbTester.getDbClient().ceQueueDao().insert(session, new CeQueueDto()
+ .setUuid("uuid")
+ .setTaskType("foo")
+ .setStatus(CeQueueDto.Status.PENDING)
+ .setWorkerUuid("must be overriden")
+ .setExecutionCount(2));
+ dbTester.commit();
+
+ underTest.peek(WORKER_UUID_1);
+
+ CeQueueDto ceQueueDto = dbTester.getDbClient().ceQueueDao().selectByUuid(session, "uuid").get();
+ assertThat(ceQueueDto.getWorkerUuid()).isEqualTo(WORKER_UUID_1);
+ assertThat(ceQueueDto.getExecutionCount()).isEqualTo(3);
+ }
+
@Test
public void peek_nothing_if_paused() throws Exception {
submit(CeTaskTypes.REPORT, "PROJECT_1");
assertThat(activity.get().getStatus()).isEqualTo(CeActivityDto.Status.CANCELED);
}
+ @Test
+ public void cancel_copies_executionCount_and_workerUuid() {
+ dbTester.getDbClient().ceQueueDao().insert(session, new CeQueueDto()
+ .setUuid("uuid")
+ .setTaskType("foo")
+ .setStatus(CeQueueDto.Status.PENDING)
+ .setWorkerUuid("Dustin")
+ .setExecutionCount(2));
+ dbTester.commit();
+
+ underTest.cancel("uuid");
+
+ CeActivityDto dto = dbTester.getDbClient().ceActivityDao().selectByUuid(dbTester.getSession(), "uuid").get();
+ assertThat(dto.getExecutionCount()).isEqualTo(2);
+ assertThat(dto.getWorkerUuid()).isEqualTo("Dustin");
+ }
+
@Test
public void fail_to_cancel_if_in_progress() throws Exception {
expectedException.expect(IllegalStateException.class);