]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-9939 add WS api/editions/preview (mock implementation)
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Fri, 13 Oct 2017 12:26:52 +0000 (14:26 +0200)
committerGrégoire Aubert <gregoire.aubert@sonarsource.com>
Mon, 23 Oct 2017 15:01:13 +0000 (08:01 -0700)
same mock implementation as for api/editions/apply_license

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
server/sonar-server/src/main/java/org/sonar/server/edition/ws/PreviewAction.java [new file with mode: 0644]
server/sonar-server/src/main/resources/org/sonar/server/edition/ws/example-edition-preview.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/PreviewActionTest.java [new file with mode: 0644]
sonar-ws/src/main/protobuf/ws-editions.proto

index 1f22a1c3182df40254f54843800a8b65dc001e35..e62724d7d5151f7bd69995e21e5575ccc6ff0387 100644 (file)
@@ -22,6 +22,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.PreviewAction;
 import org.sonar.server.edition.ws.StatusAction;
 
 public class EditionsWsModule extends Module {
@@ -30,6 +31,7 @@ public class EditionsWsModule extends Module {
     add(
       StatusAction.class,
       ApplyLicenseAction.class,
+      PreviewAction.class,
       EditionsWs.class);
   }
 }
index 75dc8356053b6422bf41453f4a069393960aab5f..da7bb813090fc2c4fdec0a9319d2f5de8e4a5236 100644 (file)
@@ -34,8 +34,8 @@ import org.sonarqube.ws.WsEditions;
 public class ApplyLicenseAction implements EditionsWsAction {
   private static final String PARAM_LICENSE = "license";
 
-  private UserSession userSession;
-  private MutableEditionManagementState editionManagementState;
+  private final UserSession userSession;
+  private final MutableEditionManagementState editionManagementState;
 
   public ApplyLicenseAction(UserSession userSession, MutableEditionManagementState editionManagementState) {
     this.userSession = userSession;
diff --git a/server/sonar-server/src/main/java/org/sonar/server/edition/ws/PreviewAction.java b/server/sonar-server/src/main/java/org/sonar/server/edition/ws/PreviewAction.java
new file mode 100644 (file)
index 0000000..1503163
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * 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 java.util.Optional;
+import javax.annotation.Nullable;
+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.exceptions.BadRequestException;
+import org.sonar.server.user.UserSession;
+import org.sonar.server.ws.WsUtils;
+import org.sonarqube.ws.WsEditions;
+
+import static java.util.Optional.ofNullable;
+import static org.sonarqube.ws.WsEditions.PreviewStatus.AUTOMATIC_INSTALL;
+import static org.sonarqube.ws.WsEditions.PreviewStatus.MANUAL_INSTALL;
+import static org.sonarqube.ws.WsEditions.PreviewStatus.NO_INSTALL;
+
+public class PreviewAction implements EditionsWsAction {
+  private static final String PARAM_LICENSE = "license";
+
+  private final UserSession userSession;
+  private final EditionManagementState editionManagementState;
+
+  public PreviewAction(UserSession userSession, EditionManagementState editionManagementState) {
+    this.userSession = userSession;
+    this.editionManagementState = editionManagementState;
+  }
+
+  @Override
+  public void define(WebService.NewController controller) {
+    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.")
+      .setResponseExample(getClass().getResource("example-edition-preview.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);
+    NextState nextState = computeNextState(newLicense);
+
+    WsUtils.writeProtobuf(buildResponse(nextState), request, response);
+  }
+
+  private static WsEditions.PreviewResponse buildResponse(NextState nextState) {
+    return WsEditions.PreviewResponse.newBuilder()
+      .setNextEditionKey(nextState.getPendingEditionKey().orElse(""))
+      .setPreviewStatus(nextState.getPreviewStatus())
+      .build();
+  }
+
+  private static NextState computeNextState(License newLicense) {
+    String licenseContent = newLicense.getContent();
+    if (licenseContent.contains("manual")) {
+      return new NextState(newLicense.getEditionKey(), MANUAL_INSTALL);
+    } else if (licenseContent.contains("done")) {
+      return new NextState(newLicense.getEditionKey(), NO_INSTALL);
+    }
+    return new NextState(newLicense.getEditionKey(), AUTOMATIC_INSTALL);
+  }
+
+  private static final class NextState {
+    private final String pendingEditionKey;
+    private final WsEditions.PreviewStatus previewStatus;
+
+    private NextState(@Nullable String pendingEditionKey, WsEditions.PreviewStatus previewStatus) {
+      this.pendingEditionKey = pendingEditionKey;
+      this.previewStatus = previewStatus;
+    }
+
+    Optional<String> getPendingEditionKey() {
+      return ofNullable(pendingEditionKey);
+    }
+
+    WsEditions.PreviewStatus getPreviewStatus() {
+      return previewStatus;
+    }
+  }
+
+}
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/edition/ws/example-edition-preview.json b/server/sonar-server/src/main/resources/org/sonar/server/edition/ws/example-edition-preview.json
new file mode 100644 (file)
index 0000000..2427d69
--- /dev/null
@@ -0,0 +1,4 @@
+{
+  "nextEditionKey": "developer-edition",
+  "previewStatus": "AUTOMATIC_INSTALL"
+}
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/PreviewActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/edition/ws/PreviewActionTest.java
new file mode 100644 (file)
index 0000000..46efe09
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * 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.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.NONE;
+
+@RunWith(DataProviderRunner.class)
+public class PreviewActionTest {
+  private static final String PARAM_LICENSE = "license";
+
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+  @Rule
+  public UserSessionRule userSessionRule = UserSessionRule.standalone();
+
+  private EditionManagementState editionManagementState = mock(EditionManagementState.class);
+  private PreviewAction underTest = new PreviewAction(userSessionRule, editionManagementState);
+  private WsActionTester actionTester = new WsActionTester(underTest);
+
+  @Test
+  public void verify_definition() {
+    WebService.Action def = actionTester.getDef();
+
+    assertThat(def.key()).isEqualTo("preview");
+    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(editionManagementState.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(editionManagementState.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(editionManagementState.getPendingInstallationStatus()).thenReturn(NONE);
+
+    TestRequest request = actionTester.newRequest()
+      .setParam(PARAM_LICENSE, "developer-edition");
+
+    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 8f173acc923b4e59f1dcf677a6cf9363ad9b3265..791ad47215f3dc6772a9720a66e3980f26764158 100644 (file)
@@ -39,3 +39,15 @@ enum InstallationStatus {
   AUTOMATIC_FAILED = 3;
   MANUAL_IN_PROGRESS = 4;
 }
+
+// POST api/editions/preview
+message PreviewResponse {
+  optional string nextEditionKey = 1;
+  optional PreviewStatus previewStatus = 2;
+}
+
+enum PreviewStatus {
+  NO_INSTALL = 0;
+  AUTOMATIC_INSTALL = 1;
+  MANUAL_INSTALL = 2;
+}