From 2ebc792076910c168ded2464865098a629de6ab6 Mon Sep 17 00:00:00 2001 From: Duarte Meneses Date: Thu, 19 Oct 2017 08:45:26 +0200 Subject: [PATCH] SONAR-10010 Add WS api/edition/form_data --- .../server/edition/EditionsWsModule.java | 2 + .../server/edition/ws/FormDataAction.java | 68 +++++++++ .../edition/ws/example-edition-form_data.json | 4 + .../server/edition/EditionsWsModuleTest.java | 2 +- .../server/edition/ws/FormDataActionTest.java | 136 ++++++++++++++++++ sonar-ws/src/main/protobuf/ws-editions.proto | 6 + 6 files changed, 217 insertions(+), 1 deletion(-) create mode 100644 server/sonar-server/src/main/java/org/sonar/server/edition/ws/FormDataAction.java create mode 100644 server/sonar-server/src/main/resources/org/sonar/server/edition/ws/example-edition-form_data.json create mode 100644 server/sonar-server/src/test/java/org/sonar/server/edition/ws/FormDataActionTest.java diff --git a/server/sonar-server/src/main/java/org/sonar/server/edition/EditionsWsModule.java b/server/sonar-server/src/main/java/org/sonar/server/edition/EditionsWsModule.java index e62724d7d51..958250388d5 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/edition/EditionsWsModule.java +++ b/server/sonar-server/src/main/java/org/sonar/server/edition/EditionsWsModule.java @@ -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.FormDataAction; import org.sonar.server.edition.ws.PreviewAction; import org.sonar.server.edition.ws.StatusAction; @@ -32,6 +33,7 @@ public class EditionsWsModule extends Module { StatusAction.class, ApplyLicenseAction.class, PreviewAction.class, + FormDataAction.class, EditionsWs.class); } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/edition/ws/FormDataAction.java b/server/sonar-server/src/main/java/org/sonar/server/edition/ws/FormDataAction.java new file mode 100644 index 00000000000..1cfb9aa100f --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/edition/ws/FormDataAction.java @@ -0,0 +1,68 @@ +/* + * 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.platform.Server; +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.measure.index.ProjectMeasuresIndex; +import org.sonar.server.user.UserSession; +import org.sonar.server.ws.WsUtils; +import org.sonarqube.ws.WsEditions.FormDataResponse; + +public class FormDataAction implements EditionsWsAction { + private final UserSession userSession; + private final Server server; + private final ProjectMeasuresIndex measuresIndex; + + public FormDataAction(UserSession userSession, Server server, ProjectMeasuresIndex measuresIndex) { + this.userSession = userSession; + this.server = server; + this.measuresIndex = measuresIndex; + } + + @Override + public void define(WebService.NewController controller) { + controller.createAction("form_data") + .setSince("6.7") + .setPost(false) + .setDescription("Provide data to prefill license request forms: the server ID and the total number of lines of code.") + .setResponseExample(getClass().getResource("example-edition-form_data.json")) + .setInternal(true) + .setHandler(this); + } + + @Override + public void handle(Request request, Response response) throws Exception { + userSession + .checkLoggedIn() + .checkIsSystemAdministrator(); + + String serverId = server.getId(); + long nloc = measuresIndex.searchTelemetryStatistics().getNcloc(); + + FormDataResponse responsePayload = FormDataResponse.newBuilder() + .setNcloc(nloc) + .setServerId(serverId) + .build(); + WsUtils.writeProtobuf(responsePayload, request, response); + } +} diff --git a/server/sonar-server/src/main/resources/org/sonar/server/edition/ws/example-edition-form_data.json b/server/sonar-server/src/main/resources/org/sonar/server/edition/ws/example-edition-form_data.json new file mode 100644 index 00000000000..3a361124437 --- /dev/null +++ b/server/sonar-server/src/main/resources/org/sonar/server/edition/ws/example-edition-form_data.json @@ -0,0 +1,4 @@ +{ + "serverId": "uuid", + "ncloc": 12345 +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/edition/EditionsWsModuleTest.java b/server/sonar-server/src/test/java/org/sonar/server/edition/EditionsWsModuleTest.java index 116a4f4f2cd..a499e10eeef 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/edition/EditionsWsModuleTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/edition/EditionsWsModuleTest.java @@ -34,6 +34,6 @@ public class EditionsWsModuleTest { underTest.configure(container); assertThat(container.getPicoContainer().getComponentAdapters()) - .hasSize(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 4); + .hasSize(COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER + 5); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/edition/ws/FormDataActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/edition/ws/FormDataActionTest.java new file mode 100644 index 00000000000..e2ce1b60347 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/edition/ws/FormDataActionTest.java @@ -0,0 +1,136 @@ +/* + * 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 java.io.IOException; +import java.util.Arrays; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.sonar.api.platform.Server; +import org.sonar.api.server.ws.WebService; +import org.sonar.server.edition.EditionManagementState; +import org.sonar.server.exceptions.ForbiddenException; +import org.sonar.server.exceptions.UnauthorizedException; +import org.sonar.server.measure.index.ProjectMeasuresIndex; +import org.sonar.server.measure.index.ProjectMeasuresStatistics; +import org.sonar.server.tester.UserSessionRule; +import org.sonar.server.ws.TestRequest; +import org.sonar.server.ws.WsActionTester; +import org.sonar.test.JsonAssert; +import org.sonarqube.ws.MediaTypes; +import org.sonarqube.ws.WsEditions.FormDataResponse; + +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 FormDataActionTest { + @Rule + public ExpectedException expectedException = ExpectedException.none(); + @Rule + public UserSessionRule userSessionRule = UserSessionRule.standalone(); + + private Server server = mock(Server.class); + private ProjectMeasuresStatistics stats = mock(ProjectMeasuresStatistics.class); + private ProjectMeasuresIndex measuresIndex = mock(ProjectMeasuresIndex.class); + private FormDataAction underTest = new FormDataAction(userSessionRule, server, measuresIndex); + private WsActionTester actionTester = new WsActionTester(underTest); + + @Before + public void setUp() { + when(measuresIndex.searchTelemetryStatistics()).thenReturn(stats); + } + + @Test + public void verify_definition() { + WebService.Action def = actionTester.getDef(); + + assertThat(def.key()).isEqualTo("form_data"); + assertThat(def.since()).isEqualTo("6.7"); + assertThat(def.isPost()).isFalse(); + assertThat(def.isInternal()).isTrue(); + 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 + public void verify_example() throws IOException { + userSessionRule.logIn().setSystemAdministrator(); + when(server.getId()).thenReturn("uuid"); + when(stats.getNcloc()).thenReturn(12345L); + + TestRequest request = actionTester.newRequest(); + + JsonAssert.assertJson(request.execute().getInput()).isSimilarTo(actionTester.getDef().responseExampleAsString()); + } + + @Test + public void returns_server_id_and_nloc() throws IOException { + userSessionRule.logIn().setSystemAdministrator(); + when(server.getId()).thenReturn("myserver"); + when(stats.getNcloc()).thenReturn(1000L); + + FormDataResponse expectedResponse = FormDataResponse.newBuilder() + .setServerId("myserver") + .setNcloc(1000L) + .build(); + + TestRequest request = actionTester.newRequest().setMediaType(MediaTypes.PROTOBUF); + + assertThat(FormDataResponse.parseFrom(request.execute().getInputStream())).isEqualTo(expectedResponse); + } + + @DataProvider + public static Object[][] notNonePendingInstallationStatuses() { + return Arrays.stream(EditionManagementState.PendingStatus.values()) + .filter(s -> s != NONE) + .map(s -> new Object[] {s}) + .toArray(Object[][]::new); + } +} diff --git a/sonar-ws/src/main/protobuf/ws-editions.proto b/sonar-ws/src/main/protobuf/ws-editions.proto index 791ad47215f..c8dc31ee29d 100644 --- a/sonar-ws/src/main/protobuf/ws-editions.proto +++ b/sonar-ws/src/main/protobuf/ws-editions.proto @@ -51,3 +51,9 @@ enum PreviewStatus { AUTOMATIC_INSTALL = 1; MANUAL_INSTALL = 2; } + +// POST api/editions/form_data +message FormDataResponse { + optional string serverId = 1; + optional int64 ncloc = 2; +} -- 2.39.5