From 13b8590acb21f58d0485729425cff724dee3d999 Mon Sep 17 00:00:00 2001 From: Duarte Meneses Date: Thu, 19 Oct 2017 18:03:14 +0200 Subject: [PATCH] SONAR-9961 Support cluster in marketplace --- .../server/edition/ws/ApplyLicenseAction.java | 25 +++++-- .../server/edition/ws/PreviewAction.java | 8 ++- .../edition/ws/ApplyLicenseActionTest.java | 67 +++++++++++++++++-- .../server/edition/ws/PreviewActionTest.java | 24 ++++++- 4 files changed, 109 insertions(+), 15 deletions(-) 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 index a4e6239b5aeb..de7f62f6d4a1 100644 --- 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 @@ -29,6 +29,7 @@ import org.sonar.server.edition.MutableEditionManagementState; import org.sonar.server.exceptions.BadRequestException; import org.sonar.server.license.LicenseCommit; +import org.sonar.server.platform.WebServer; import org.sonar.server.plugins.edition.EditionInstaller; import org.sonar.server.user.UserSession; import org.sonar.server.ws.WsUtils; @@ -42,18 +43,21 @@ public class ApplyLicenseAction implements EditionsWsAction { private final UserSession userSession; private final MutableEditionManagementState editionManagementState; private final EditionInstaller editionInstaller; + private final WebServer webServer; @CheckForNull private final LicenseCommit licenseCommit; - public ApplyLicenseAction(UserSession userSession, MutableEditionManagementState editionManagementState, EditionInstaller editionInstaller) { - this(userSession, editionManagementState, editionInstaller, null); + public ApplyLicenseAction(UserSession userSession, MutableEditionManagementState editionManagementState, + EditionInstaller editionInstaller, WebServer webServer) { + this(userSession, editionManagementState, editionInstaller, webServer, null); } - public ApplyLicenseAction(UserSession userSession, MutableEditionManagementState editionManagementState, EditionInstaller editionInstaller, - @Nullable LicenseCommit licenseCommit) { + public ApplyLicenseAction(UserSession userSession, MutableEditionManagementState editionManagementState, + EditionInstaller editionInstaller, WebServer webServer, @Nullable LicenseCommit licenseCommit) { this.userSession = userSession; this.editionManagementState = editionManagementState; this.editionInstaller = editionInstaller; + this.webServer = webServer; this.licenseCommit = licenseCommit; } @@ -85,19 +89,26 @@ public void handle(Request request, Response response) throws Exception { String licenseParam = request.mandatoryParam(PARAM_LICENSE); License newLicense = License.parse(licenseParam).orElseThrow(() -> BadRequestException.create("The license provided is invalid")); - if (editionInstaller.requiresInstallationChange(newLicense.getPluginKeys())) { + if (!webServer.isStandalone()) { + checkState(licenseCommit != null, "LicenseCommit instance not found. License-manager plugin should be installed."); + setLicenseWithoutInstall(newLicense); + } else if (editionInstaller.requiresInstallationChange(newLicense.getPluginKeys())) { editionInstaller.install(newLicense); } else { checkState(licenseCommit != null, "Can't decide edition does not require install if LicenseCommit instance is null. " + "License-manager plugin should be installed."); - editionManagementState.newEditionWithoutInstall(newLicense.getEditionKey()); - licenseCommit.update(newLicense.getContent()); + setLicenseWithoutInstall(newLicense); } WsUtils.writeProtobuf(buildResponse(), request, response); } + private void setLicenseWithoutInstall(License newLicense) { + editionManagementState.newEditionWithoutInstall(newLicense.getEditionKey()); + licenseCommit.update(newLicense.getContent()); + } + private WsEditions.StatusResponse buildResponse() { WsEditions.StatusResponse.Builder builder = WsEditions.StatusResponse.newBuilder() .setNextEditionKey(editionManagementState.getPendingEditionKey().orElse("")) 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 index 399d0fc311d7..a0853f91f856 100644 --- 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 @@ -27,6 +27,7 @@ import org.sonar.server.edition.EditionManagementState; import org.sonar.server.edition.License; import org.sonar.server.exceptions.BadRequestException; +import org.sonar.server.platform.WebServer; import org.sonar.server.plugins.edition.EditionInstaller; import org.sonar.server.user.UserSession; import org.sonar.server.ws.WsUtils; @@ -43,11 +44,14 @@ public class PreviewAction implements EditionsWsAction { private final UserSession userSession; private final EditionManagementState editionManagementState; private final EditionInstaller editionInstaller; + private final WebServer webServer; - public PreviewAction(UserSession userSession, EditionManagementState editionManagementState, EditionInstaller editionInstaller) { + public PreviewAction(UserSession userSession, EditionManagementState editionManagementState, EditionInstaller editionInstaller, + WebServer webServer) { this.userSession = userSession; this.editionManagementState = editionManagementState; this.editionInstaller = editionInstaller; + this.webServer = webServer; } @Override @@ -91,7 +95,7 @@ private static WsEditions.PreviewResponse buildResponse(NextState nextState) { } private NextState computeNextState(License newLicense) { - if (!editionInstaller.requiresInstallationChange(newLicense.getPluginKeys())) { + if (!webServer.isStandalone() || !editionInstaller.requiresInstallationChange(newLicense.getPluginKeys())) { return new NextState(newLicense.getEditionKey(), NO_INSTALL); // this won't refresh the update center (uses cached state). Preview is called while typing (must be fast) // and anyway the status is refreshed when arriving at the marketplace page. 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 index 9c4801036135..c05b5e75ec28 100644 --- 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 @@ -43,6 +43,7 @@ import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.exceptions.UnauthorizedException; import org.sonar.server.license.LicenseCommit; +import org.sonar.server.platform.WebServer; import org.sonar.server.plugins.edition.EditionInstaller; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.ws.TestRequest; @@ -59,6 +60,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; 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; @@ -76,7 +78,9 @@ public class ApplyLicenseActionTest { private EditionInstaller editionInstaller = mock(EditionInstaller.class); private MutableEditionManagementState mutableEditionManagementState = mock(MutableEditionManagementState.class); private LicenseCommit licenseCommit = mock(LicenseCommit.class); - private ApplyLicenseAction underTest = new ApplyLicenseAction(userSessionRule, mutableEditionManagementState, editionInstaller, licenseCommit); + private WebServer webServer = mock(WebServer.class); + private ApplyLicenseAction underTest = new ApplyLicenseAction(userSessionRule, mutableEditionManagementState, editionInstaller, + webServer, licenseCommit); private WsActionTester actionTester = new WsActionTester(underTest); @Test @@ -157,6 +161,54 @@ public void request_fails_with_BadRequestException_if_license_is_invalid() { request.execute(); } + @Test + public void request_fails_with_ISE_if_is_cluster_and_license_plugin_is_not_installed() throws IOException { + underTest = new ApplyLicenseAction(userSessionRule, mutableEditionManagementState, editionInstaller, webServer, null); + actionTester = new WsActionTester(underTest); + userSessionRule.logIn().setSystemAdministrator(); + + when(mutableEditionManagementState.getPendingInstallationStatus()).thenReturn(NONE); + when(webServer.isStandalone()).thenReturn(false); + + TestRequest request = actionTester.newRequest().setParam(PARAM_LICENSE, createLicenseParam("dev", "plugin1")); + + expectedException.expect(IllegalStateException.class); + expectedException.expectMessage("License-manager plugin should be installed"); + request.execute(); + } + + @Test + public void request_fails_with_ISE_if_no_change_needed_but_license_plugin_is_not_installed() throws IOException { + underTest = new ApplyLicenseAction(userSessionRule, mutableEditionManagementState, editionInstaller, webServer, null); + actionTester = new WsActionTester(underTest); + userSessionRule.logIn().setSystemAdministrator(); + + setPendingLicense(NONE); + when(webServer.isStandalone()).thenReturn(true); + + TestRequest request = actionTester.newRequest().setParam(PARAM_LICENSE, createLicenseParam("dev", "plugin1")); + + expectedException.expect(IllegalStateException.class); + expectedException.expectMessage("Can't decide edition does not require install if LicenseCommit instance is null"); + request.execute(); + } + + @Test + public void always_apply_license_when_is_cluster() throws IOException { + userSessionRule.logIn().setSystemAdministrator(); + when(webServer.isStandalone()).thenReturn(false); + setPendingLicense(NONE); + + TestRequest request = actionTester.newRequest() + .setMediaType(MediaTypes.PROTOBUF) + .setParam(PARAM_LICENSE, createLicenseParam(PENDING_EDITION_NAME, "plugin1")); + + TestResponse response = request.execute(); + assertResponse(response, PENDING_EDITION_NAME, "", NONE); + verify(mutableEditionManagementState).newEditionWithoutInstall(PENDING_EDITION_NAME); + verifyZeroInteractions(editionInstaller); + } + @Test public void verify_example() throws IOException { userSessionRule.logIn().setSystemAdministrator(); @@ -171,8 +223,9 @@ public void verify_example() throws IOException { @Test public void apply_without_need_to_install() throws IOException { userSessionRule.logIn().setSystemAdministrator(); - setPendingLicense(NONE, null); + setPendingLicense(NONE); when(editionInstaller.requiresInstallationChange(singleton("plugin1"))).thenReturn(false); + when(webServer.isStandalone()).thenReturn(true); TestRequest request = actionTester.newRequest() .setMediaType(MediaTypes.PROTOBUF) @@ -186,8 +239,9 @@ public void apply_without_need_to_install() throws IOException { @Test public void apply_offline() throws IOException { userSessionRule.logIn().setSystemAdministrator(); - setPendingLicense(PendingStatus.MANUAL_IN_PROGRESS, null); + setPendingLicense(PendingStatus.MANUAL_IN_PROGRESS); when(editionInstaller.requiresInstallationChange(singleton("plugin1"))).thenReturn(true); + when(webServer.isStandalone()).thenReturn(true); TestRequest request = actionTester.newRequest() .setMediaType(MediaTypes.PROTOBUF) @@ -203,8 +257,9 @@ public void apply_offline() throws IOException { @Test public void apply_successfully_auto_installation() throws IOException { userSessionRule.logIn().setSystemAdministrator(); - setPendingLicense(PendingStatus.AUTOMATIC_IN_PROGRESS, null); + setPendingLicense(PendingStatus.AUTOMATIC_IN_PROGRESS); when(editionInstaller.requiresInstallationChange(singleton("plugin1"))).thenReturn(true); + when(webServer.isStandalone()).thenReturn(true); TestRequest request = actionTester.newRequest() .setMediaType(MediaTypes.PROTOBUF) @@ -243,6 +298,10 @@ private void assertResponse(TestResponse response, String expectedNextEditionKey assertThat(parsedResponse.getInstallationStatus()).isEqualTo(WsEditions.InstallationStatus.valueOf(expectedPendingStatus.toString())); } + private void setPendingLicense(PendingStatus pendingStatus) { + setPendingLicense(pendingStatus, null); + } + private void setPendingLicense(PendingStatus pendingStatus, @Nullable String errorMessage) { when(mutableEditionManagementState.getCurrentEditionKey()).thenReturn(Optional.empty()); when(mutableEditionManagementState.getPendingEditionKey()).thenReturn(Optional.of(PENDING_EDITION_NAME)); 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 index 718b5207b238..8e8d0170da56 100644 --- 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 @@ -38,6 +38,7 @@ import org.sonar.server.exceptions.BadRequestException; import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.exceptions.UnauthorizedException; +import org.sonar.server.platform.WebServer; import org.sonar.server.plugins.edition.EditionInstaller; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.ws.TestRequest; @@ -65,7 +66,8 @@ public class PreviewActionTest { private EditionManagementState editionManagementState = mock(EditionManagementState.class); private EditionInstaller editionInstaller = mock(EditionInstaller.class); - private PreviewAction underTest = new PreviewAction(userSessionRule, editionManagementState, editionInstaller); + private WebServer webServer = mock(WebServer.class); + private PreviewAction underTest = new PreviewAction(userSessionRule, editionManagementState, editionInstaller, webServer); private WsActionTester actionTester = new WsActionTester(underTest); @Test @@ -117,7 +119,7 @@ public void request_fails_if_license_param_is_not_provided() { request.execute(); } - + @Test public void request_fails_if_license_param_is_empty() { userSessionRule.logIn().setSystemAdministrator(); @@ -161,6 +163,7 @@ public void request_fails_with_BadRequestException_is_pendingStatus_is_not_NONE( @Test public void verify_example() throws IOException { userSessionRule.logIn().setSystemAdministrator(); + when(webServer.isStandalone()).thenReturn(true); when(editionManagementState.getPendingInstallationStatus()).thenReturn(NONE); when(editionInstaller.requiresInstallationChange(Collections.singleton("plugin1"))).thenReturn(true); when(editionInstaller.isOffline()).thenReturn(false); @@ -173,6 +176,21 @@ public void verify_example() throws IOException { @Test public void license_requires_no_installation() throws IOException { + when(webServer.isStandalone()).thenReturn(true); + userSessionRule.logIn().setSystemAdministrator(); + when(editionManagementState.getPendingInstallationStatus()).thenReturn(NONE); + when(editionInstaller.requiresInstallationChange(Collections.singleton("plugin1"))).thenReturn(false); + + TestRequest request = actionTester.newRequest() + .setMediaType(MediaTypes.PROTOBUF) + .setParam(PARAM_LICENSE, createLicenseParam("developer-edition", "plugin1")); + + assertResponse(request.execute(), "developer-edition", PreviewStatus.NO_INSTALL); + } + + @Test + public void cluster_require_no_installation() throws IOException { + when(webServer.isStandalone()).thenReturn(false); userSessionRule.logIn().setSystemAdministrator(); when(editionManagementState.getPendingInstallationStatus()).thenReturn(NONE); when(editionInstaller.requiresInstallationChange(Collections.singleton("plugin1"))).thenReturn(false); @@ -187,6 +205,7 @@ public void license_requires_no_installation() throws IOException { @Test public void license_will_result_in_auto_install() throws IOException { userSessionRule.logIn().setSystemAdministrator(); + when(webServer.isStandalone()).thenReturn(true); when(editionManagementState.getPendingInstallationStatus()).thenReturn(NONE); when(editionInstaller.requiresInstallationChange(Collections.singleton("plugin1"))).thenReturn(true); when(editionInstaller.isOffline()).thenReturn(false); @@ -201,6 +220,7 @@ public void license_will_result_in_auto_install() throws IOException { @Test public void license_will_result_in_manual_install() throws IOException { userSessionRule.logIn().setSystemAdministrator(); + when(webServer.isStandalone()).thenReturn(true); when(editionManagementState.getPendingInstallationStatus()).thenReturn(NONE); when(editionInstaller.requiresInstallationChange(Collections.singleton("plugin1"))).thenReturn(true); when(editionInstaller.isOffline()).thenReturn(true);