]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-9996 Add WS api/editions/uninstall
authorDuarte Meneses <duarte.meneses@sonarsource.com>
Wed, 18 Oct 2017 12:15:18 +0000 (14:15 +0200)
committerGrégoire Aubert <gregoire.aubert@sonarsource.com>
Mon, 23 Oct 2017 15:01:13 +0000 (08:01 -0700)
server/sonar-server/src/main/java/org/sonar/server/edition/EditionsWsModule.java
server/sonar-server/src/main/java/org/sonar/server/edition/ws/PreviewAction.java
server/sonar-server/src/main/java/org/sonar/server/edition/ws/StatusAction.java
server/sonar-server/src/main/java/org/sonar/server/edition/ws/UninstallAction.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/edition/EditionsWsModuleTest.java
server/sonar-server/src/test/java/org/sonar/server/edition/ws/UninstallActionTest.java [new file with mode: 0644]
sonar-ws/src/main/protobuf/ws-editions.proto

index 958250388d5b37e26847784966a24178f41fd15c..7470ffc2a370014270e9891dee0ad5e6f1d93b49 100644 (file)
@@ -25,6 +25,7 @@ import org.sonar.server.edition.ws.EditionsWs;
 import org.sonar.server.edition.ws.FormDataAction;
 import org.sonar.server.edition.ws.PreviewAction;
 import org.sonar.server.edition.ws.StatusAction;
+import org.sonar.server.edition.ws.UninstallAction;
 
 public class EditionsWsModule extends Module {
   @Override
@@ -34,6 +35,7 @@ public class EditionsWsModule extends Module {
       ApplyLicenseAction.class,
       PreviewAction.class,
       FormDataAction.class,
+      UninstallAction.class,
       EditionsWs.class);
   }
 }
index b159e48d9c30567fa60f3246dfeb84ea018faa57..e5de17fa81a5a25de430a0e8f939258eee97bc47 100644 (file)
@@ -55,7 +55,7 @@ public class PreviewAction implements EditionsWsAction {
     WebService.NewAction action = controller.createAction("preview")
       .setSince("6.7")
       .setPost(true)
-      .setDescription("Preview the changes to SonarQube to match the specified license. Require 'Administer System' permission.")
+      .setDescription("Preview the changes to SonarQube to match the specified license. Requires 'Administer System' permission.")
       .setResponseExample(getClass().getResource("example-edition-preview.json"))
       .setHandler(this);
 
index 4c44999b959338b681651d32a06fcd505cd21115..4c93a2e2caca7f5fefacdf32a2b562a03fe21697 100644 (file)
@@ -41,7 +41,7 @@ public class StatusAction implements EditionsWsAction {
     controller.createAction("status")
       .setSince("6.7")
       .setPost(false)
-      .setDescription("Provide status of SonarSource commercial edition of the current SonarQube. Require 'Administer System' permission.")
+      .setDescription("Provide status of SonarSource commercial edition of the current SonarQube. Requires 'Administer System' permission.")
       .setResponseExample(getClass().getResource("example-edition-status.json"))
       .setHandler(this);
   }
diff --git a/server/sonar-server/src/main/java/org/sonar/server/edition/ws/UninstallAction.java b/server/sonar-server/src/main/java/org/sonar/server/edition/ws/UninstallAction.java
new file mode 100644 (file)
index 0000000..67c1d26
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * 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.edition.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.server.edition.EditionManagementState;
+import org.sonar.server.edition.MutableEditionManagementState;
+import org.sonar.server.exceptions.BadRequestException;
+import org.sonar.server.plugins.edition.EditionInstaller;
+import org.sonar.server.user.UserSession;
+
+public class UninstallAction implements EditionsWsAction {
+  private final UserSession userSession;
+  private final MutableEditionManagementState mutableEditionManagementState;
+  private final EditionInstaller editionInstaller;
+
+  public UninstallAction(UserSession userSession, MutableEditionManagementState mutableEditionManagementState, EditionInstaller editionInstaller) {
+    this.userSession = userSession;
+    this.mutableEditionManagementState = mutableEditionManagementState;
+    this.editionInstaller = editionInstaller;
+  }
+
+  @Override
+  public void define(WebService.NewController controller) {
+    controller.createAction("uninstall")
+      .setSince("6.7")
+      .setPost(true)
+      .setDescription("Uninstall the currently installed edition. Requires 'Administer System' permission.")
+      .setHandler(this);
+  }
+
+  @Override
+  public void handle(Request request, Response response) throws Exception {
+    userSession.checkLoggedIn().checkIsSystemAdministrator();
+
+    if (mutableEditionManagementState.getPendingInstallationStatus() != EditionManagementState.PendingStatus.NONE
+      && mutableEditionManagementState.getPendingInstallationStatus() != EditionManagementState.PendingStatus.UNINSTALL_IN_PROGRESS) {
+      throw BadRequestException.create("Uninstall of the current edition is not allowed when install of an edition is in progress");
+    }
+
+    editionInstaller.uninstall();
+    mutableEditionManagementState.uninstall();
+    response.noContent();
+  }
+}
index a499e10eeef839fbc53165720a6cc42e52a136a9..34ab5aa5fa3ab20680d263ac16811f2c2d7f0e06 100644 (file)
@@ -34,6 +34,6 @@ public class EditionsWsModuleTest {
     underTest.configure(container);
 
     assertThat(container.getPicoContainer().getComponentAdapters())
-      .hasSize(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 5);
+      .hasSize(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 6);
   }
 }
diff --git a/server/sonar-server/src/test/java/org/sonar/server/edition/ws/UninstallActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/edition/ws/UninstallActionTest.java
new file mode 100644 (file)
index 0000000..aecb773
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * 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.edition.ws;
+
+import com.tngtech.java.junit.dataprovider.DataProvider;
+import com.tngtech.java.junit.dataprovider.DataProviderRunner;
+import com.tngtech.java.junit.dataprovider.UseDataProvider;
+import java.util.Arrays;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.server.edition.EditionManagementState;
+import org.sonar.server.edition.MutableEditionManagementState;
+import org.sonar.server.exceptions.BadRequestException;
+import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.exceptions.UnauthorizedException;
+import org.sonar.server.plugins.edition.EditionInstaller;
+import org.sonar.server.tester.UserSessionRule;
+import org.sonar.server.ws.TestRequest;
+import org.sonar.server.ws.TestResponse;
+import org.sonar.server.ws.WsActionTester;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.sonar.server.edition.EditionManagementState.PendingStatus.NONE;
+import static org.sonar.server.edition.EditionManagementState.PendingStatus.UNINSTALL_IN_PROGRESS;
+
+@RunWith(DataProviderRunner.class)
+public class UninstallActionTest {
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+  @Rule
+  public UserSessionRule userSessionRule = UserSessionRule.standalone();
+
+  private EditionInstaller editionInstaller = mock(EditionInstaller.class);
+  private MutableEditionManagementState mutableEditionManagementState = mock(MutableEditionManagementState.class);
+  private UninstallAction action = new UninstallAction(userSessionRule, mutableEditionManagementState, editionInstaller);
+  private WsActionTester actionTester = new WsActionTester(action);
+
+  @Test
+  public void check_definition() {
+    WebService.Action def = actionTester.getDef();
+
+    assertThat(def.key()).isEqualTo("uninstall");
+    assertThat(def.since()).isEqualTo("6.7");
+    assertThat(def.isPost()).isTrue();
+    assertThat(def.isInternal()).isFalse();
+    assertThat(def.responseExampleAsString()).isNull();
+    assertThat(def.description()).isNotEmpty();
+    assertThat(def.params()).isEmpty();
+  }
+
+  @Test
+  public void request_fails_if_user_not_logged_in() {
+    userSessionRule.anonymous();
+    TestRequest request = actionTester.newRequest();
+
+    expectedException.expect(UnauthorizedException.class);
+    expectedException.expectMessage("Authentication is required");
+
+    request.execute();
+  }
+
+  @Test
+  public void request_fails_if_user_is_not_system_administer() {
+    userSessionRule.logIn();
+    TestRequest request = actionTester.newRequest();
+
+    expectedException.expect(ForbiddenException.class);
+    expectedException.expectMessage("Insufficient privileges");
+
+    request.execute();
+  }
+
+  @Test
+  @UseDataProvider("notNoneOrUninstallStatuses")
+  public void request_fails_if_current_status_is_not_none(EditionManagementState.PendingStatus notNoneOrUninstall) {
+    userSessionRule.logIn().setSystemAdministrator();
+    when(mutableEditionManagementState.getPendingInstallationStatus()).thenReturn(notNoneOrUninstall);
+
+    expectedException.expect(BadRequestException.class);
+    expectedException.expectMessage("Uninstall of the current edition is not allowed when install of an edition");
+    actionTester.newRequest().execute();
+  }
+
+  @Test
+  public void successful_edition_uninstall() {
+    userSessionRule.logIn().setSystemAdministrator();
+    when(mutableEditionManagementState.getPendingInstallationStatus()).thenReturn(NONE);
+
+    TestResponse execute = actionTester.newRequest().execute();
+    assertThat(execute.getStatus()).isEqualTo(204);
+    verify(editionInstaller).uninstall();
+    verify(mutableEditionManagementState).uninstall();
+  }
+
+  @Test
+  public void successful_edition_uninstall_when_state_is_already_uninstall_in_progress() {
+    userSessionRule.logIn().setSystemAdministrator();
+    when(mutableEditionManagementState.getPendingInstallationStatus()).thenReturn(UNINSTALL_IN_PROGRESS);
+
+    TestResponse execute = actionTester.newRequest().execute();
+    assertThat(execute.getStatus()).isEqualTo(204);
+    verify(editionInstaller).uninstall();
+    verify(mutableEditionManagementState).uninstall();
+  }
+
+  @DataProvider
+  public static Object[][] notNoneOrUninstallStatuses() {
+    return Arrays.stream(EditionManagementState.PendingStatus.values())
+      .filter(s -> s != NONE)
+      .filter(s -> s != UNINSTALL_IN_PROGRESS)
+      .map(s -> new Object[] {s})
+      .toArray(Object[][]::new);
+  }
+}
index c8dc31ee29d302a391940319dae308bec2b150f3..2c72180bacdb2b4d8a3a0e9fc2d49143a5a8f151 100644 (file)
@@ -38,6 +38,7 @@ enum InstallationStatus {
   AUTOMATIC_READY = 2;
   AUTOMATIC_FAILED = 3;
   MANUAL_IN_PROGRESS = 4;
+  UNINSTALL_IN_PROGRESS = 5;
 }
 
 // POST api/editions/preview