@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";
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);
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";
.setHandler(this);
action.createParam(PARAM_BOMB_TYPE)
.setRequired(true)
- .setPossibleValues("OOM", "ISE", "NONE");
+ .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.setIseStopBomb(false);
- bombConfig.setOomStopBomb(false);
+ bombConfig.reset();
switch (bombType) {
- case ISE:
+ case ISE_START:
+ bombConfig.setIseStartBomb(true);
+ break;
+ case OOM_START:
+ bombConfig.setOomStartBomb(true);
+ break;
+ case ISE_STOP:
bombConfig.setIseStopBomb(true);
break;
- case OOM:
+ case OOM_STOP:
bombConfig.setOomStopBomb(true);
break;
case NONE:
}
enum BombType {
- NONE, OOM, ISE
+ NONE, OOM_START, ISE_START, OOM_STOP, ISE_STOP
}
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;
}
}
+ @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");
}
@Test
- public void ce_worker_is_resilient_to_OOM_and_RuntimeException_when_stopping_analysis_report_container() throws IOException {
+ 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();
- RandomAccessFile randomAccessFile = null;
- try {
- randomAccessFile = new RandomAccessFile(sharedMemory, "rw");
- MappedByteBuffer mappedByteBuffer = initMappedByteBuffer(randomAccessFile);
- releaseAnyAnalysisWithFakeGovernancePlugin(mappedByteBuffer);
+ SonarScanner sonarRunner = SonarScanner.create(ItUtils.projectDir("shared/xoo-sample"));
+ orchestrator.executeBuild(sonarRunner, true);
- SonarScanner sonarRunner = SonarScanner.create(ItUtils.projectDir("shared/xoo-sample"));
- orchestrator.executeBuild(sonarRunner, true);
+ enableComponentBomb("OOM_STOP");
- enableComponentBomb("OOM");
+ orchestrator.executeBuild(sonarRunner, true);
- orchestrator.executeBuild(sonarRunner, true);
+ enableComponentBomb("NONE");
- enableComponentBomb("NONE");
+ orchestrator.executeBuild(sonarRunner, true);
- orchestrator.executeBuild(sonarRunner, true);
+ enableComponentBomb("ISE_START");
- enableComponentBomb("ISE");
+ orchestrator.executeBuild(sonarRunner, true);
- orchestrator.executeBuild(sonarRunner, true);
+ enableComponentBomb("NONE");
- enableComponentBomb("NONE");
+ orchestrator.executeBuild(sonarRunner, true);
- 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);
- assertThat(adminWsClient.ce().activity(new ActivityWsRequest()
- .setType("REPORT")
- .setStatus(ImmutableList.of("SUCCESS")))
- .getTasksCount())
- .isEqualTo(5);
- } finally {
- close(randomAccessFile);
- }
}
private void enableComponentBomb(String type) {
}
private void waitForEmptyQueue() throws InterruptedException {
+ int delay = 200;
+ int timeout = 5 * 10; // 10 seconds
+ int i = 0;
int tasksCount;
do {
- Thread.sleep(100);
+ Thread.sleep(delay);
tasksCount = adminWsClient.ce().activity(new ActivityWsRequest()
.setStatus(ImmutableList.of("PENDING", "IN_PROGRESS")))
.getTasksCount();
- } while (tasksCount > 0);
+ i++;
+ } while (i <= timeout && tasksCount > 0);
+ assertThat(tasksCount).describedAs("Failed to get to an empty CE queue in a timely fashion").isZero();
}
}