diff options
author | ssjenka <ssjenka@ops-slave-fedora25-1.internal.sonarsource.com> | 2017-11-03 16:01:25 +0100 |
---|---|---|
committer | ssjenka <ssjenka@ops-slave-fedora25-1.internal.sonarsource.com> | 2017-11-03 16:01:25 +0100 |
commit | 5326c7cc97db482803c11f06a45a7e497824765d (patch) | |
tree | e7ae79ec6cf0082a1586272b7fab8d531ae9b943 /tests | |
parent | 46c24fe4dfa047d7b14c55fc376f502daa3d6050 (diff) | |
parent | 61d27599390f01279a25241daa5d361fcb362803 (diff) | |
download | sonarqube-5326c7cc97db482803c11f06a45a7e497824765d.tar.gz sonarqube-5326c7cc97db482803c11f06a45a7e497824765d.zip |
Automatic merge from branch-6.7
* origin/branch-6.7:
SONAR-9973 IT for report processing resilient to failure during start
SONAR-9973 TaskContainer now support errors during start of components
SONAR-9973 add IT ensuring resilience of Ce Workers to exceptions
SONAR-9973 ComponentContainer#stopComponent now never fail
Diffstat (limited to 'tests')
12 files changed, 750 insertions, 1 deletions
diff --git a/tests/plugins/fake-governance-plugin/src/main/java/FakeGovernancePlugin.java b/tests/plugins/fake-governance-plugin/src/main/java/FakeGovernancePlugin.java index 19f6fdf68c3..b37e201d61f 100644 --- a/tests/plugins/fake-governance-plugin/src/main/java/FakeGovernancePlugin.java +++ b/tests/plugins/fake-governance-plugin/src/main/java/FakeGovernancePlugin.java @@ -18,6 +18,14 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +import ce.BombConfig; +import ce.ComponentBombReportAnalysisComponentProvider; +import ce.IseTaskProcessor; +import ce.OkTaskProcessor; +import ce.OomTaskProcessor; +import ce.ws.BombActivatorAction; +import ce.ws.FakeGovWs; +import ce.ws.SubmitAction; import org.sonar.api.Plugin; import systemPasscode.SystemPasscodeWebService; import workerCount.FakeWorkerCountProviderImpl; @@ -36,6 +44,20 @@ public class FakeGovernancePlugin implements Plugin { context.addExtension(LatchControllerWorkerMeasureComputer.class); context.addExtension(RefreshWorkerCountAction.class); context.addExtension(SystemPasscodeWebService.class); + + // WS api/fake_gov + context.addExtension(FakeGovWs.class); + + // failing CE tasks + context.addExtension(SubmitAction.class); + context.addExtension(OomTaskProcessor.class); + context.addExtension(IseTaskProcessor.class); + context.addExtension(OkTaskProcessor.class); + + // component bombs injection into the Report Analysis processing container in the CE + context.addExtension(BombConfig.class); + context.addExtension(ComponentBombReportAnalysisComponentProvider.class); + context.addExtension(BombActivatorAction.class); } } diff --git a/tests/plugins/fake-governance-plugin/src/main/java/ce/BombConfig.java b/tests/plugins/fake-governance-plugin/src/main/java/ce/BombConfig.java new file mode 100644 index 00000000000..3e5af086b86 --- /dev/null +++ b/tests/plugins/fake-governance-plugin/src/main/java/ce/BombConfig.java @@ -0,0 +1,102 @@ +/* + * 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 ce; + +import org.sonar.api.ce.ComputeEngineSide; +import org.sonar.api.server.ServerSide; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; + +@ServerSide +@ComputeEngineSide +public class BombConfig { + private static final String OOM_START_BOMB_KEY = "oomStartBomb"; + private static final String ISE_START_BOMB_KEY = "iseStartBomb"; + private static final String OOM_STOP_BOMB_KEY = "oomStopBomb"; + private static final String ISE_STOP_BOMB_KEY = "iseStopBomb"; + + private final DbClient dbClient; + + public BombConfig(DbClient dbClient) { + this.dbClient = dbClient; + } + + public void reset() { + try (DbSession dbSession = dbClient.openSession(false)) { + dbClient.internalPropertiesDao().save(dbSession, OOM_START_BOMB_KEY, String.valueOf(false)); + dbClient.internalPropertiesDao().save(dbSession, ISE_START_BOMB_KEY, String.valueOf(false)); + dbClient.internalPropertiesDao().save(dbSession, OOM_STOP_BOMB_KEY, String.valueOf(false)); + dbClient.internalPropertiesDao().save(dbSession, ISE_STOP_BOMB_KEY, String.valueOf(false)); + dbSession.commit(); + } + } + + public boolean isOomStartBomb() { + try (DbSession dbSession = dbClient.openSession(false)) { + return dbClient.internalPropertiesDao().selectByKey(dbSession, OOM_START_BOMB_KEY).map(Boolean::valueOf).orElse(false); + } + } + + public void setOomStartBomb(boolean oomStartBomb) { + try (DbSession dbSession = dbClient.openSession(false)) { + dbClient.internalPropertiesDao().save(dbSession, OOM_START_BOMB_KEY, String.valueOf(oomStartBomb)); + dbSession.commit(); + } + } + + public boolean isIseStartBomb() { + try (DbSession dbSession = dbClient.openSession(false)) { + return dbClient.internalPropertiesDao().selectByKey(dbSession, ISE_START_BOMB_KEY).map(Boolean::valueOf).orElse(false); + } + } + + public void setIseStartBomb(boolean iseStartBomb) { + try (DbSession dbSession = dbClient.openSession(false)) { + dbClient.internalPropertiesDao().save(dbSession, ISE_START_BOMB_KEY, String.valueOf(iseStartBomb)); + dbSession.commit(); + } + } + + public boolean isOomStopBomb() { + try (DbSession dbSession = dbClient.openSession(false)) { + return dbClient.internalPropertiesDao().selectByKey(dbSession, OOM_STOP_BOMB_KEY).map(Boolean::valueOf).orElse(false); + } + } + + public void setOomStopBomb(boolean oomStopBomb) { + try (DbSession dbSession = dbClient.openSession(false)) { + dbClient.internalPropertiesDao().save(dbSession, OOM_STOP_BOMB_KEY, String.valueOf(oomStopBomb)); + dbSession.commit(); + } + } + + public boolean isIseStopBomb() { + try (DbSession dbSession = dbClient.openSession(false)) { + return dbClient.internalPropertiesDao().selectByKey(dbSession, ISE_STOP_BOMB_KEY).map(Boolean::valueOf).orElse(false); + } + } + + public void setIseStopBomb(boolean iseStopBomb) { + try (DbSession dbSession = dbClient.openSession(false)) { + dbClient.internalPropertiesDao().save(dbSession, ISE_STOP_BOMB_KEY, String.valueOf(iseStopBomb)); + dbSession.commit(); + } + } +} diff --git a/tests/plugins/fake-governance-plugin/src/main/java/ce/ComponentBombReportAnalysisComponentProvider.java b/tests/plugins/fake-governance-plugin/src/main/java/ce/ComponentBombReportAnalysisComponentProvider.java new file mode 100644 index 00000000000..166f526fca4 --- /dev/null +++ b/tests/plugins/fake-governance-plugin/src/main/java/ce/ComponentBombReportAnalysisComponentProvider.java @@ -0,0 +1,109 @@ +/* + * 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 ce; + +import java.util.List; +import org.picocontainer.Startable; +import org.sonar.plugin.ce.ReportAnalysisComponentProvider; +import org.sonar.server.computation.task.container.EagerStart; + +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; + +public class ComponentBombReportAnalysisComponentProvider implements ReportAnalysisComponentProvider { + private final BombConfig bombConfig; + + public ComponentBombReportAnalysisComponentProvider(BombConfig bombConfig) { + this.bombConfig = bombConfig; + } + + @Override + public List<Object> getComponents() { + if (bombConfig.isOomStartBomb()) { + return singletonList(OOMFailingStartComponent.class); + } + if (bombConfig.isIseStartBomb()) { + return singletonList(ISEFailingStartComponent.class); + } + if (bombConfig.isOomStopBomb()) { + return singletonList(OOMFailingStopComponent.class); + } + if (bombConfig.isIseStopBomb()) { + return singletonList(ISEFailingStopComponent.class); + } + return emptyList(); + } + + @EagerStart + public static final class OOMFailingStartComponent implements Startable { + + @Override + public void start() { + OOMGenerator.consumeAvailableMemory(); + } + + @Override + public void stop() { + // nothing to do + } + } + + @EagerStart + public static final class ISEFailingStartComponent implements Startable { + + @Override + public void start() { + throw new IllegalStateException("Faking an IllegalStateException thrown by a startable component in the Analysis Report processing container"); + } + + @Override + public void stop() { + // nothing to do + } + } + + @EagerStart + public static final class OOMFailingStopComponent implements Startable { + + @Override + public void start() { + // nothing to do + } + + @Override + public void stop() { + OOMGenerator.consumeAvailableMemory(); + } + } + + @EagerStart + public static final class ISEFailingStopComponent implements Startable { + + @Override + public void start() { + // nothing to do + } + + @Override + public void stop() { + throw new IllegalStateException("Faking an IllegalStateException thrown by a stoppable component in the Analysis Report processing container"); + } + } +} diff --git a/tests/plugins/fake-governance-plugin/src/main/java/ce/IseTaskProcessor.java b/tests/plugins/fake-governance-plugin/src/main/java/ce/IseTaskProcessor.java new file mode 100644 index 00000000000..a6960d1b049 --- /dev/null +++ b/tests/plugins/fake-governance-plugin/src/main/java/ce/IseTaskProcessor.java @@ -0,0 +1,38 @@ +/* + * 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 ce; + +import java.util.Collections; +import java.util.Set; +import org.sonar.ce.queue.CeTask; +import org.sonar.ce.queue.CeTaskResult; +import org.sonar.ce.taskprocessor.CeTaskProcessor; + +public class IseTaskProcessor implements CeTaskProcessor { + @Override + public Set<String> getHandledCeTaskTypes() { + return Collections.singleton("ISE"); + } + + @Override + public CeTaskResult process(CeTask task) { + throw new IllegalStateException("Faking an IllegalStateException thrown processing a task"); + } +} diff --git a/tests/plugins/fake-governance-plugin/src/main/java/ce/OOMGenerator.java b/tests/plugins/fake-governance-plugin/src/main/java/ce/OOMGenerator.java new file mode 100644 index 00000000000..4fcef07cb80 --- /dev/null +++ b/tests/plugins/fake-governance-plugin/src/main/java/ce/OOMGenerator.java @@ -0,0 +1,36 @@ +/* + * 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 ce; + +import java.util.ArrayList; +import java.util.List; + +public final class OOMGenerator { + private OOMGenerator() { + // prevents instantiation + } + + public static List<Object> consumeAvailableMemory() { + List<Object> holder = new ArrayList<>(); + while (true) { + holder.add(new byte[128 * 1024]); + } + } +} diff --git a/tests/plugins/fake-governance-plugin/src/main/java/ce/OkTaskProcessor.java b/tests/plugins/fake-governance-plugin/src/main/java/ce/OkTaskProcessor.java new file mode 100644 index 00000000000..92e05032fa0 --- /dev/null +++ b/tests/plugins/fake-governance-plugin/src/main/java/ce/OkTaskProcessor.java @@ -0,0 +1,41 @@ +/* + * 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 ce; + +import java.util.Collections; +import java.util.Optional; +import java.util.Set; +import org.sonar.ce.queue.CeTask; +import org.sonar.ce.queue.CeTaskResult; +import org.sonar.ce.taskprocessor.CeTaskProcessor; + +public class OkTaskProcessor implements CeTaskProcessor { + @Override + public Set<String> getHandledCeTaskTypes() { + return Collections.singleton("OK"); + } + + @Override + public CeTaskResult process(CeTask task) { + return Optional::empty; + } + + +} diff --git a/tests/plugins/fake-governance-plugin/src/main/java/ce/OomTaskProcessor.java b/tests/plugins/fake-governance-plugin/src/main/java/ce/OomTaskProcessor.java new file mode 100644 index 00000000000..384d3201daa --- /dev/null +++ b/tests/plugins/fake-governance-plugin/src/main/java/ce/OomTaskProcessor.java @@ -0,0 +1,39 @@ +/* + * 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 ce; + +import java.util.Collections; +import java.util.Set; +import org.sonar.ce.queue.CeTask; +import org.sonar.ce.queue.CeTaskResult; +import org.sonar.ce.taskprocessor.CeTaskProcessor; + +public class OomTaskProcessor implements CeTaskProcessor { + @Override + public Set<String> getHandledCeTaskTypes() { + return Collections.singleton("OOM"); + } + + @Override + public CeTaskResult process(CeTask task) { + OOMGenerator.consumeAvailableMemory(); + return null; + } +} diff --git a/tests/plugins/fake-governance-plugin/src/main/java/ce/ws/BombActivatorAction.java b/tests/plugins/fake-governance-plugin/src/main/java/ce/ws/BombActivatorAction.java new file mode 100644 index 00000000000..e2366b8e16a --- /dev/null +++ b/tests/plugins/fake-governance-plugin/src/main/java/ce/ws/BombActivatorAction.java @@ -0,0 +1,82 @@ +/* + * 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 ce.ws; + +import ce.BombConfig; +import java.util.Arrays; +import org.sonar.api.server.ws.Request; +import org.sonar.api.server.ws.Response; +import org.sonar.api.server.ws.WebService; + +import static java.util.stream.Collectors.toList; + +public class BombActivatorAction implements FakeGoVWsAction { + + private static final String PARAM_BOMB_TYPE = "type"; + + private final BombConfig bombConfig; + + public BombActivatorAction(BombConfig bombConfig) { + this.bombConfig = bombConfig; + } + + @Override + public void define(WebService.NewController controller) { + WebService.NewAction action = controller.createAction("activate_bomb") + .setPost(true) + .setHandler(this); + action.createParam(PARAM_BOMB_TYPE) + .setRequired(true) + .setPossibleValues(Arrays.stream(BombType.values()).map(Enum::toString).collect(toList())); + } + + @Override + public void handle(Request request, Response response) throws Exception { + BombType bombType = BombType.valueOf(request.mandatoryParam(PARAM_BOMB_TYPE)); + + bombConfig.reset(); + switch (bombType) { + case ISE_START: + bombConfig.setIseStartBomb(true); + break; + case OOM_START: + bombConfig.setOomStartBomb(true); + break; + case ISE_STOP: + bombConfig.setIseStopBomb(true); + break; + case OOM_STOP: + bombConfig.setOomStopBomb(true); + break; + case NONE: + break; + default: + throw new IllegalArgumentException("Unsupported bomb type " + bombType); + } + + response.noContent(); + } + + enum BombType { + NONE, OOM_START, ISE_START, OOM_STOP, ISE_STOP + + } + +} diff --git a/tests/plugins/fake-governance-plugin/src/main/java/ce/ws/FakeGoVWsAction.java b/tests/plugins/fake-governance-plugin/src/main/java/ce/ws/FakeGoVWsAction.java new file mode 100644 index 00000000000..bd361f92961 --- /dev/null +++ b/tests/plugins/fake-governance-plugin/src/main/java/ce/ws/FakeGoVWsAction.java @@ -0,0 +1,25 @@ +/* + * 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 ce.ws; + +import org.sonar.server.ws.WsAction; + +public interface FakeGoVWsAction extends WsAction { +} diff --git a/tests/plugins/fake-governance-plugin/src/main/java/ce/ws/FakeGovWs.java b/tests/plugins/fake-governance-plugin/src/main/java/ce/ws/FakeGovWs.java new file mode 100644 index 00000000000..9d89cfbb795 --- /dev/null +++ b/tests/plugins/fake-governance-plugin/src/main/java/ce/ws/FakeGovWs.java @@ -0,0 +1,38 @@ +/* + * 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 ce.ws; + +import java.util.Arrays; +import org.sonar.api.server.ws.WebService; + +public class FakeGovWs implements WebService { + private final FakeGoVWsAction[] actions; + + public FakeGovWs(FakeGoVWsAction[] actions) { + this.actions = actions; + } + + @Override + public void define(Context context) { + NewController controller = context.createController("api/fake_gov"); + Arrays.stream(actions).forEach(action -> action.define(controller)); + controller.done(); + } +} diff --git a/tests/plugins/fake-governance-plugin/src/main/java/ce/ws/SubmitAction.java b/tests/plugins/fake-governance-plugin/src/main/java/ce/ws/SubmitAction.java new file mode 100644 index 00000000000..42f037f819c --- /dev/null +++ b/tests/plugins/fake-governance-plugin/src/main/java/ce/ws/SubmitAction.java @@ -0,0 +1,58 @@ +/* + * 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 ce.ws; + +import org.sonar.api.server.ws.Request; +import org.sonar.api.server.ws.Response; +import org.sonar.api.server.ws.WebService; +import org.sonar.ce.queue.CeQueue; +import org.sonar.ce.queue.CeTaskSubmit; + +public class SubmitAction implements FakeGoVWsAction { + + private static final String PARAM_TYPE = "type"; + + private final CeQueue ceQueue; + + public SubmitAction(CeQueue ceQueue) { + this.ceQueue = ceQueue; + } + + @Override + public void define(WebService.NewController controller) { + WebService.NewAction action = controller.createAction("submit") + .setPost(true) + .setHandler(this); + action.createParam(PARAM_TYPE) + .setRequired(true) + .setPossibleValues("OOM", "OK", "ISE"); + } + + @Override + public void handle(Request request, Response response) throws Exception { + String type = request.mandatoryParam(PARAM_TYPE); + + CeTaskSubmit.Builder submit = ceQueue.prepareSubmit(); + submit.setType(type); + + ceQueue.submit(submit.build()); + response.noContent(); + } +} diff --git a/tests/src/test/java/org/sonarqube/tests/ce/CeWorkersTest.java b/tests/src/test/java/org/sonarqube/tests/ce/CeWorkersTest.java index 491c671a3ce..64d0625e192 100644 --- a/tests/src/test/java/org/sonarqube/tests/ce/CeWorkersTest.java +++ b/tests/src/test/java/org/sonarqube/tests/ce/CeWorkersTest.java @@ -38,12 +38,15 @@ import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.IntStream; import javax.annotation.Nullable; +import org.junit.After; import org.junit.AfterClass; +import org.junit.Before; 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.PostRequest; import org.sonarqube.ws.client.WsClient; import org.sonarqube.ws.client.ce.ActivityWsRequest; import util.ItUtils; @@ -81,6 +84,8 @@ public class CeWorkersTest { OrchestratorBuilder builder = Orchestrator.builderEnv() .addPlugin(pluginArtifact("fake-governance-plugin")) .setServerProperty("fakeGoverance.workerLatch.sharedMemoryFile", sharedMemory.getAbsolutePath()) + // overwrite default value to display heap dump on OOM and reduce max heap + .setServerProperty("sonar.ce.javaOpts", "-Xmx256m -Xms128m") .addPlugin(xooPlugin()); orchestrator = builder.build(); orchestrator.start(); @@ -96,6 +101,145 @@ public class CeWorkersTest { } } + @Before + public void setup() throws Exception { + unlockWorkersAndResetWorkerCount(); + } + + @After + public void tearDown() throws Exception { + unlockWorkersAndResetWorkerCount(); + } + + private void unlockWorkersAndResetWorkerCount() throws IOException { + RandomAccessFile randomAccessFile = null; + try { + randomAccessFile = new RandomAccessFile(sharedMemory, "rw"); + MappedByteBuffer mappedByteBuffer = initMappedByteBuffer(randomAccessFile); + releaseAnyAnalysisWithFakeGovernancePlugin(mappedByteBuffer); + updateWorkerCount(1); + } finally { + close(randomAccessFile); + } + } + + @Test + public void ce_worker_is_resilient_to_OOM_and_ISE_during_processing_of_a_task() throws InterruptedException { + submitFakeTask("OOM"); + + waitForEmptyQueue(); + + assertThat(adminWsClient.ce().activity(new ActivityWsRequest() + .setType("OOM") + .setStatus(ImmutableList.of("FAILED"))) + .getTasksCount()) + .isEqualTo(1); + + submitFakeTask("OK"); + + waitForEmptyQueue(); + + assertThat(adminWsClient.ce().activity(new ActivityWsRequest() + .setType("OK") + .setStatus(ImmutableList.of("SUCCESS"))) + .getTasksCount()) + .isEqualTo(1); + + submitFakeTask("ISE"); + + waitForEmptyQueue(); + + assertThat(adminWsClient.ce().activity(new ActivityWsRequest() + .setType("ISE") + .setStatus(ImmutableList.of("FAILED"))) + .getTasksCount()) + .isEqualTo(1); + + submitFakeTask("OK"); + + waitForEmptyQueue(); + + assertThat(adminWsClient.ce().activity(new ActivityWsRequest() + .setType("OK") + .setStatus(ImmutableList.of("SUCCESS"))) + .getTasksCount()) + .isEqualTo(2); + } + + private void submitFakeTask(String type) { + adminWsClient.wsConnector().call(new PostRequest("api/fake_gov/submit") + .setParam("type", type)) + .failIfNotSuccessful(); + } + + @Test + public void ce_worker_is_resilient_to_OOM_and_RuntimeException_when_starting_or_stopping_analysis_report_container() throws IOException { + int initSuccessReportTaskCount = adminWsClient.ce().activity(new ActivityWsRequest() + .setType("REPORT") + .setStatus(ImmutableList.of("SUCCESS"))) + .getTasksCount(); + int initFailedReportTaskCount = adminWsClient.ce().activity(new ActivityWsRequest() + .setType("REPORT") + .setStatus(ImmutableList.of("FAILED"))) + .getTasksCount(); + + SonarScanner sonarRunner = SonarScanner.create(ItUtils.projectDir("shared/xoo-sample")); + orchestrator.executeBuild(sonarRunner, true); + + enableComponentBomb("OOM_STOP"); + + orchestrator.executeBuild(sonarRunner, true); + + enableComponentBomb("NONE"); + + orchestrator.executeBuild(sonarRunner, true); + + enableComponentBomb("ISE_START"); + + orchestrator.executeBuild(sonarRunner, true); + + enableComponentBomb("NONE"); + + orchestrator.executeBuild(sonarRunner, true); + + enableComponentBomb("ISE_STOP"); + + orchestrator.executeBuild(sonarRunner, true); + + enableComponentBomb("NONE"); + + orchestrator.executeBuild(sonarRunner, true); + + enableComponentBomb("OOM_START"); + + orchestrator.executeBuild(sonarRunner, true); + + enableComponentBomb("NONE"); + + orchestrator.executeBuild(sonarRunner, true); + + // failure while starting components does fail the tasks + assertThat(adminWsClient.ce().activity(new ActivityWsRequest() + .setType("REPORT") + .setStatus(ImmutableList.of("FAILED"))) + .getTasksCount()) + .isEqualTo(initFailedReportTaskCount + 2); + + // failure while stopping components does not fail the tasks + assertThat(adminWsClient.ce().activity(new ActivityWsRequest() + .setType("REPORT") + .setStatus(ImmutableList.of("SUCCESS"))) + .getTasksCount()) + .isEqualTo(initSuccessReportTaskCount + 7); + + } + + private void enableComponentBomb(String type) { + adminWsClient.wsConnector().call(new PostRequest("api/fake_gov/activate_bomb") + .setParam("type", type)) + .failIfNotSuccessful(); + } + @Test public void enabled_worker_count_is_initially_1_and_can_be_changed_dynamically_by_plugin() throws IOException { assertThat(Files.lines(orchestrator.getServer().getCeLogs().toPath()) @@ -109,7 +253,7 @@ public class CeWorkersTest { verifyAnalysesRunInParallel(mappedByteBuffer, 1); - /* 2 <= newWorkerCount <= 7 */ + /* 4 <= newWorkerCount <= 7 */ int newWorkerCount = 4 + new Random().nextInt(4); updateWorkerCount(newWorkerCount); @@ -234,4 +378,19 @@ public class CeWorkersTest { e.printStackTrace(); } } + + private void waitForEmptyQueue() throws InterruptedException { + int delay = 200; + int timeout = 5 * 10; // 10 seconds + int i = 0; + int tasksCount; + do { + Thread.sleep(delay); + tasksCount = adminWsClient.ce().activity(new ActivityWsRequest() + .setStatus(ImmutableList.of("PENDING", "IN_PROGRESS"))) + .getTasksCount(); + i++; + } while (i <= timeout && tasksCount > 0); + assertThat(tasksCount).describedAs("Failed to get to an empty CE queue in a timely fashion").isZero(); + } } |