aboutsummaryrefslogtreecommitdiffstats
path: root/tests/src
diff options
context:
space:
mode:
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>2017-07-07 16:59:16 +0200
committerSébastien Lesaint <sebastien.lesaint@sonarsource.com>2017-07-18 08:51:46 +0200
commite6ee887b01b83bb12aec85ab1dfdaee639b1d241 (patch)
tree342214b006379a44a8b76fc892a40259f7d482c8 /tests/src
parent2349795115d14542a44dba354a5c36bed15742c5 (diff)
downloadsonarqube-e6ee887b01b83bb12aec85ab1dfdaee639b1d241.tar.gz
sonarqube-e6ee887b01b83bb12aec85ab1dfdaee639b1d241.zip
SONAR-9525 add IT on number of tasks processed in //
Diffstat (limited to 'tests/src')
-rw-r--r--tests/src/test/java/org/sonarqube/tests/Category5Suite.java4
-rw-r--r--tests/src/test/java/org/sonarqube/tests/ce/CeWorkersTest.java196
-rw-r--r--tests/src/test/java/org/sonarqube/tests/ce/WorkerCountTest.java69
3 files changed, 198 insertions, 71 deletions
diff --git a/tests/src/test/java/org/sonarqube/tests/Category5Suite.java b/tests/src/test/java/org/sonarqube/tests/Category5Suite.java
index 905897e6c07..98587c47027 100644
--- a/tests/src/test/java/org/sonarqube/tests/Category5Suite.java
+++ b/tests/src/test/java/org/sonarqube/tests/Category5Suite.java
@@ -21,7 +21,7 @@ package org.sonarqube.tests;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
-import org.sonarqube.tests.ce.WorkerCountTest;
+import org.sonarqube.tests.ce.CeWorkersTest;
import org.sonarqube.tests.qualityProfile.ActiveRuleEsResilienceTest;
import org.sonarqube.tests.qualityProfile.BuiltInQualityProfilesNotificationTest;
import org.sonarqube.tests.rule.RuleEsResilienceTest;
@@ -58,7 +58,7 @@ import org.sonarqube.tests.user.UserEsResilienceTest;
RuleEsResilienceTest.class,
UserEsResilienceTest.class,
// ce
- WorkerCountTest.class
+ CeWorkersTest.class
})
public class Category5Suite {
diff --git a/tests/src/test/java/org/sonarqube/tests/ce/CeWorkersTest.java b/tests/src/test/java/org/sonarqube/tests/ce/CeWorkersTest.java
new file mode 100644
index 00000000000..92a9482d852
--- /dev/null
+++ b/tests/src/test/java/org/sonarqube/tests/ce/CeWorkersTest.java
@@ -0,0 +1,196 @@
+/*
+ * 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.sonarqube.tests.ce;
+
+import com.google.common.collect.ImmutableList;
+import com.sonar.orchestrator.Orchestrator;
+import com.sonar.orchestrator.OrchestratorBuilder;
+import com.sonar.orchestrator.build.SonarScanner;
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.file.Files;
+import java.util.List;
+import java.util.Random;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonarqube.ws.WsCe;
+import org.sonarqube.ws.client.WsClient;
+import org.sonarqube.ws.client.ce.ActivityWsRequest;
+import util.ItUtils;
+
+import static com.google.common.collect.ImmutableSet.copyOf;
+import static java.lang.String.valueOf;
+import static java.util.stream.Collectors.toList;
+import static java.util.stream.Collectors.toSet;
+import static org.assertj.core.api.Assertions.assertThat;
+import static util.ItUtils.newAdminWsClient;
+import static util.ItUtils.pluginArtifact;
+import static util.ItUtils.xooPlugin;
+
+public class CeWorkersTest {
+ /** 2 <= workerCount <= 5 */
+ private static final int WORKER_COUNT = 2 + new Random().nextInt(4);
+
+ private static final int WAIT = 200; // ms
+ private static final int MAX_WAIT_LOOP = 5 * 10; // 10s
+
+ private static final byte BLOCKING = (byte) 0x00;
+ private static final byte UNLATCHED = (byte) 0x01;
+
+ private static final String STATUS_PENDING = "PENDING";
+ private static final String STATUS_IN_PROGRESS = "IN_PROGRESS";
+ private static final String STATUS_SUCCESS = "SUCCESS";
+ private static final String STATUS_FAILED = "FAILED";
+
+ private static final String STATUS_CANCELED = "CANCELED";
+
+ @ClassRule
+ public static TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+ private static File sharedMemory;
+ private static Orchestrator orchestrator;
+
+ @BeforeClass
+ public static void setUp() throws Exception {
+ sharedMemory = temporaryFolder.newFile();
+
+ OrchestratorBuilder builder = Orchestrator.builderEnv()
+ .addPlugin(pluginArtifact("fake-governance-plugin"))
+ .setServerProperty("fakeGovernance.workerCount", valueOf(WORKER_COUNT))
+ .setServerProperty("fakeGoverance.workerLatch.sharedMemoryFile", sharedMemory.getAbsolutePath())
+ .addPlugin(xooPlugin());
+ orchestrator = builder.build();
+ orchestrator.start();
+ }
+
+ @AfterClass
+ public static void stop() {
+ if (orchestrator != null) {
+ orchestrator.stop();
+ orchestrator = null;
+ }
+ }
+
+ @Test
+ public void workerCount_is_modified_by_plugin() throws IOException {
+ Set<String> line = Files.lines(orchestrator.getServer().getCeLogs().toPath())
+ .filter(s -> s.contains("Compute Engine will use "))
+ .collect(Collectors.toSet());
+ assertThat(line)
+ .hasSize(1);
+ assertThat(line.iterator().next()).contains(valueOf(WORKER_COUNT));
+
+ assertThat(newAdminWsClient(orchestrator).ce().workerCount())
+ .extracting(WsCe.WorkerCountResponse::getValue, WsCe.WorkerCountResponse::getCanSetWorkerCount)
+ .containsOnly(WORKER_COUNT, true);
+ }
+
+ @Test
+ public void number_of_analysis_processed_in_parallel_is_equal_to_number_of_workers() throws IOException {
+ RandomAccessFile randomAccessFile = null;
+ try {
+ randomAccessFile = new RandomAccessFile(sharedMemory, "rw");
+ MappedByteBuffer mappedByteBuffer = randomAccessFile.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, 1);
+ // block any analysis which will run with the fake-governance-plugin
+ mappedByteBuffer.put(0, BLOCKING);
+
+ // start analysis of WORKER_COUNT + 2 projects
+ List<String> projectKeys = IntStream.range(0, WORKER_COUNT + 2).mapToObj(i -> "prj" + i).collect(toList());
+ for (String projectKey : projectKeys) {
+ SonarScanner sonarRunner = SonarScanner.create(ItUtils.projectDir("shared/xoo-sample"))
+ .setProperties("sonar.projectKey", projectKey);
+ orchestrator.executeBuild(sonarRunner, false);
+ }
+
+ List<WsCe.Task> tasksList = waitForWsCallStatus(this::getTasksAllTasks, CeWorkersTest::threeTasksNotPending);
+ boolean expectedState = threeTasksNotPending(tasksList);
+ // let the blocked analyses finish running
+ mappedByteBuffer.put(0, UNLATCHED);
+
+ assertThat(expectedState).as("Couldn't get to the expected CE queue state in time").isTrue();
+ assertThat(tasksList.stream()
+ .filter(CeWorkersTest::pending)
+ .map(WsCe.Task::getComponentKey)
+ .collect(toSet()))
+ .isEqualTo(copyOf(projectKeys.subList(WORKER_COUNT, projectKeys.size())));
+ assertThat(tasksList.stream()
+ .filter(CeWorkersTest::inProgress)
+ .map(WsCe.Task::getComponentKey)
+ .collect(toSet()))
+ .isEqualTo(copyOf(projectKeys.subList(0, WORKER_COUNT)));
+
+ waitForWsCallStatus(this::getTasksAllTasks, tasks -> tasks.stream().noneMatch(CeWorkersTest::pending));
+ } finally {
+ if (randomAccessFile != null) {
+ randomAccessFile.close();
+ }
+ }
+ }
+
+ private static boolean threeTasksNotPending(List<WsCe.Task> tasksList) {
+ return tasksList.stream().filter(task -> !pending(task)).count() >= WORKER_COUNT;
+ }
+
+ private static boolean pending(WsCe.Task task) {
+ return WsCe.TaskStatus.PENDING == task.getStatus();
+ }
+
+ private static boolean inProgress(WsCe.Task task) {
+ return WsCe.TaskStatus.IN_PROGRESS == task.getStatus();
+ }
+
+ private List<WsCe.Task> getTasksAllTasks(WsClient wsClient) {
+ return wsClient.ce().activity(new ActivityWsRequest()
+ .setStatus(ImmutableList.of(STATUS_PENDING, STATUS_IN_PROGRESS, STATUS_SUCCESS, STATUS_FAILED, STATUS_CANCELED)))
+ .getTasksList();
+ }
+
+ private <T> T waitForWsCallStatus(Function<WsClient, T> call, Function<T, Boolean> test) {
+ WsClient wsClient = ItUtils.newAdminWsClient(orchestrator);
+ int i = 0;
+ T returnValue = call.apply(wsClient);
+ boolean expectedState = test.apply(returnValue);
+ while (i < MAX_WAIT_LOOP && !expectedState) {
+ waitInterruptedly();
+ i++;
+ returnValue = call.apply(wsClient);
+ expectedState = test.apply(returnValue);
+ }
+ return returnValue;
+ }
+
+ private static void waitInterruptedly() {
+ try {
+ Thread.sleep(WAIT);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/tests/src/test/java/org/sonarqube/tests/ce/WorkerCountTest.java b/tests/src/test/java/org/sonarqube/tests/ce/WorkerCountTest.java
deleted file mode 100644
index 3a8e766953d..00000000000
--- a/tests/src/test/java/org/sonarqube/tests/ce/WorkerCountTest.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * 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.sonarqube.tests.ce;
-
-import com.sonar.orchestrator.Orchestrator;
-import com.sonar.orchestrator.OrchestratorBuilder;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.util.Set;
-import java.util.stream.Collectors;
-import org.junit.After;
-import org.junit.Test;
-import org.sonarqube.ws.WsCe.WorkerCountResponse;
-
-import static java.lang.Integer.parseInt;
-import static org.assertj.core.api.Assertions.assertThat;
-import static util.ItUtils.newAdminWsClient;
-import static util.ItUtils.pluginArtifact;
-
-public class WorkerCountTest {
-
- private Orchestrator orchestrator;
-
- @After
- public void stop() {
- if (orchestrator != null) {
- orchestrator.stop();
- orchestrator = null;
- }
- }
-
- @Test
- public void workerCount_can_be_controlled_via_plugin() throws IOException {
- String workerCount = "5";
- OrchestratorBuilder builder = Orchestrator.builderEnv()
- .addPlugin(pluginArtifact("fake-governance-plugin"))
- .setServerProperty("fakeGovernance.workerCount", workerCount);
- orchestrator = builder.build();
- orchestrator.start();
-
- Set<String> line = Files.lines(orchestrator.getServer().getCeLogs().toPath())
- .filter(s -> s.contains("Compute Engine will use "))
- .collect(Collectors.toSet());
- assertThat(line)
- .hasSize(1);
- assertThat(line.iterator().next()).contains(workerCount);
-
- assertThat(newAdminWsClient(orchestrator).ce().workerCount())
- .extracting(WorkerCountResponse::getValue, WorkerCountResponse::getCanSetWorkerCount)
- .containsOnly(parseInt(workerCount), true);
- }
-}