]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-9940 add WS api/editions/apply_license (mocked implementation)
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Thu, 12 Oct 2017 14:50:31 +0000 (16:50 +0200)
committerGrégoire Aubert <gregoire.aubert@sonarsource.com>
Mon, 23 Oct 2017 15:01:13 +0000 (08:01 -0700)
edition key is the whole license
if license contains string "manual", the state will be changed to MANUAL_IN_PROGRESS
if license contains string "done", the license will be applies without requiring a restart
otherwise state will go to AUTOMATIC_IN_PROGRESS

server/sonar-server/src/main/java/org/sonar/server/edition/EditionsWsModule.java
server/sonar-server/src/main/java/org/sonar/server/edition/ws/ApplyLicenseAction.java [new file with mode: 0644]
server/sonar-server/src/main/resources/org/sonar/server/edition/ws/example-edition-apply_license.json [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/ApplyLicenseActionTest.java [new file with mode: 0644]
sonar-ws/src/main/protobuf/ws-editions.proto

index fb05d1834c1e5c8824c5495eca247de0450a2cc8..0a1ca5d30f767b55bbd8ccacfaef6eabe7d76215 100644 (file)
@@ -20,6 +20,7 @@
 package org.sonar.server.edition;
 
 import org.sonar.core.platform.Module;
+import org.sonar.server.edition.ws.ApplyLicenseAction;
 import org.sonar.server.edition.ws.EditionsWs;
 import org.sonar.server.edition.ws.StatusAction;
 
@@ -29,6 +30,7 @@ public class EditionsWsModule extends Module {
     add(
       StandaloneEditionManagementStateImpl.class,
       StatusAction.class,
+      ApplyLicenseAction.class,
       EditionsWs.class);
   }
 }
diff --git a/server/sonar-server/src/main/java/org/sonar/server/edition/ws/ApplyLicenseAction.java b/server/sonar-server/src/main/java/org/sonar/server/edition/ws/ApplyLicenseAction.java
new file mode 100644 (file)
index 0000000..75dc835
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * 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 java.util.Collections;
+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.License;
+import org.sonar.server.edition.MutableEditionManagementState;
+import org.sonar.server.exceptions.BadRequestException;
+import org.sonar.server.user.UserSession;
+import org.sonar.server.ws.WsUtils;
+import org.sonarqube.ws.WsEditions;
+
+public class ApplyLicenseAction implements EditionsWsAction {
+  private static final String PARAM_LICENSE = "license";
+
+  private UserSession userSession;
+  private MutableEditionManagementState editionManagementState;
+
+  public ApplyLicenseAction(UserSession userSession, MutableEditionManagementState editionManagementState) {
+    this.userSession = userSession;
+    this.editionManagementState = editionManagementState;
+  }
+
+  @Override
+  public void define(WebService.NewController controller) {
+    WebService.NewAction action = controller.createAction("apply_license")
+      .setSince("6.7")
+      .setPost(true)
+      .setDescription("Apply changes to SonarQube to match the specified license. Require 'Administer System' permission.")
+      .setResponseExample(getClass().getResource("example-edition-apply_license.json"))
+      .setHandler(this);
+
+    action.createParam(PARAM_LICENSE)
+      .setRequired(true)
+      .setSince("6.7")
+      .setDescription("the license");
+  }
+
+  @Override
+  public void handle(Request request, Response response) throws Exception {
+    userSession.checkLoggedIn().checkIsSystemAdministrator();
+
+    if (editionManagementState.getPendingInstallationStatus() != EditionManagementState.PendingStatus.NONE) {
+      throw BadRequestException.create("Can't apply a license when applying one is already in progress");
+    }
+
+    String license = request.mandatoryParam(PARAM_LICENSE);
+    License newLicense = new License(license, Collections.emptyList(), license);
+    if (license.contains("manual")) {
+      editionManagementState.startManualInstall(newLicense);
+    } else if (license.contains("done")) {
+      editionManagementState.newEditionWithoutInstall(newLicense.getEditionKey());
+    } else {
+      editionManagementState.startAutomaticInstall(newLicense);
+    }
+
+    WsUtils.writeProtobuf(buildResponse(), request, response);
+  }
+
+  private WsEditions.StatusResponse buildResponse() {
+    return WsEditions.StatusResponse.newBuilder()
+      .setNextEditionKey(editionManagementState.getPendingEditionKey().orElse(""))
+      .setCurrentEditionKey(editionManagementState.getCurrentEditionKey().orElse(""))
+      .setInstallationStatus(WsEditions.InstallationStatus.valueOf(editionManagementState.getPendingInstallationStatus().name()))
+      .build();
+  }
+}
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/edition/ws/example-edition-apply_license.json b/server/sonar-server/src/main/resources/org/sonar/server/edition/ws/example-edition-apply_license.json
new file mode 100644 (file)
index 0000000..507a64d
--- /dev/null
@@ -0,0 +1,5 @@
+{
+  "currentEditionKey": "",
+  "installationStatus": "AUTOMATIC_IN_PROGRESS",
+  "nextEditionKey": "developer-edition"
+}
index c4fae543a7700e029bcbf32b20e87eb88b8e962f..116a4f4f2cdec3ba8707a05edeb1f77563721aba 100644 (file)
@@ -34,6 +34,6 @@ public class EditionsWsModuleTest {
     underTest.configure(container);
 
     assertThat(container.getPicoContainer().getComponentAdapters())
-      .hasSize(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 3);
+      .hasSize(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 4);
   }
 }
diff --git a/server/sonar-server/src/test/java/org/sonar/server/edition/ws/ApplyLicenseActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/edition/ws/ApplyLicenseActionTest.java
new file mode 100644 (file)
index 0000000..4cd01c6
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * 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 java.util.Optional;
+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.tester.UserSessionRule;
+import org.sonar.server.ws.TestRequest;
+import org.sonar.server.ws.WsActionTester;
+import org.sonar.test.JsonAssert;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.sonar.server.edition.EditionManagementState.PendingStatus.AUTOMATIC_IN_PROGRESS;
+import static org.sonar.server.edition.EditionManagementState.PendingStatus.NONE;
+
+@RunWith(DataProviderRunner.class)
+public class ApplyLicenseActionTest {
+  private static final String PARAM_LICENSE = "license";
+
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+  @Rule
+  public UserSessionRule userSessionRule = UserSessionRule.standalone();
+
+  private MutableEditionManagementState mutableEditionManagementState = mock(MutableEditionManagementState.class);
+  private ApplyLicenseAction underTest = new ApplyLicenseAction(userSessionRule, mutableEditionManagementState);
+  private WsActionTester actionTester = new WsActionTester(underTest);
+
+  @Test
+  public void verify_definition() {
+    WebService.Action def = actionTester.getDef();
+
+    assertThat(def.key()).isEqualTo("apply_license");
+    assertThat(def.since()).isEqualTo("6.7");
+    assertThat(def.isPost()).isTrue();
+    assertThat(def.isInternal()).isFalse();
+    assertThat(def.description()).isNotEmpty();
+    assertThat(def.params()).hasSize(1);
+
+    WebService.Param licenseParam = def.param("license");
+    assertThat(licenseParam.isRequired()).isTrue();
+    assertThat(licenseParam.description()).isNotEmpty();
+  }
+
+  @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
+  public void request_fails_if_license_param_is_not_provided() {
+    userSessionRule.logIn().setSystemAdministrator();
+    when(mutableEditionManagementState.getPendingInstallationStatus()).thenReturn(NONE);
+    TestRequest request = actionTester.newRequest();
+
+    expectedException.expect(IllegalArgumentException.class);
+    expectedException.expectMessage("The 'license' parameter is missing");
+
+    request.execute();
+  }
+
+  @Test
+  @UseDataProvider("notNonePendingInstallationStatuses")
+  public void request_fails_with_BadRequestException_is_pendingStatus_is_not_NONE(EditionManagementState.PendingStatus notNone) {
+    userSessionRule.logIn().setSystemAdministrator();
+    when(mutableEditionManagementState.getCurrentEditionKey()).thenReturn(Optional.empty());
+    when(mutableEditionManagementState.getPendingEditionKey()).thenReturn(Optional.empty());
+    when(mutableEditionManagementState.getPendingInstallationStatus()).thenReturn(notNone);
+    TestRequest request = actionTester.newRequest()
+      .setParam(PARAM_LICENSE, "foo");
+
+    expectedException.expect(BadRequestException.class);
+    expectedException.expectMessage("Can't apply a license when applying one is already in progress");
+
+    request.execute();
+  }
+
+  @Test
+  public void verify_example() {
+    userSessionRule.logIn().setSystemAdministrator();
+    when(mutableEditionManagementState.getCurrentEditionKey()).thenReturn(Optional.empty());
+    when(mutableEditionManagementState.getPendingEditionKey()).thenReturn(Optional.of("developer-edition"));
+    when(mutableEditionManagementState.getPendingInstallationStatus())
+        .thenReturn(NONE)
+        .thenReturn(AUTOMATIC_IN_PROGRESS);
+
+    TestRequest request = actionTester.newRequest()
+      .setParam(PARAM_LICENSE, "foo");
+
+    JsonAssert.assertJson(request.execute().getInput()).isSimilarTo(actionTester.getDef().responseExampleAsString());
+  }
+
+  @DataProvider
+  public static Object[][] notNonePendingInstallationStatuses() {
+    return Arrays.stream(EditionManagementState.PendingStatus.values())
+        .filter(s -> s != NONE)
+        .map(s -> new Object[] {s})
+        .toArray(Object[][]::new);
+  }
+}
index 9e486715aae28f9988825f68517006e5838360f4..8f173acc923b4e59f1dcf677a6cf9363ad9b3265 100644 (file)
@@ -25,6 +25,7 @@ option java_outer_classname = "WsEditions";
 option optimize_for = SPEED;
 
 // GET api/editions/status
+// POST api/editions/apply_license
 message StatusResponse {
   optional string currentEditionKey = 1;
   optional InstallationStatus installationStatus = 2;