]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-7969 Create client for values WS
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Tue, 23 Aug 2016 15:50:44 +0000 (17:50 +0200)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Thu, 25 Aug 2016 09:29:41 +0000 (11:29 +0200)
server/sonar-server/src/main/java/org/sonar/server/settings/ws/ValuesAction.java
server/sonar-server/src/test/java/org/sonar/server/settings/ws/ValuesActionTest.java
sonar-ws/src/main/java/org/sonarqube/ws/client/setting/SettingsService.java
sonar-ws/src/main/java/org/sonarqube/ws/client/setting/SettingsWsParameters.java
sonar-ws/src/main/java/org/sonarqube/ws/client/setting/ValuesRequest.java [new file with mode: 0644]
sonar-ws/src/test/java/org/sonarqube/ws/client/setting/SettingsServiceTest.java
sonar-ws/src/test/java/org/sonarqube/ws/client/setting/ValuesRequestTest.java [new file with mode: 0644]

index 79f65c935ab5fc4ca9bbe6b53c3d2cf2c72af0a8..4528b6227c68fdb0ba698f393799503d4f46edcf 100644 (file)
@@ -34,41 +34,49 @@ import org.sonar.api.config.PropertyDefinitions;
 import org.sonar.api.server.ws.Request;
 import org.sonar.api.server.ws.Response;
 import org.sonar.api.server.ws.WebService;
+import org.sonar.api.web.UserRole;
+import org.sonar.core.permission.GlobalPermissions;
 import org.sonar.core.util.stream.Collectors;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.component.ComponentDto;
+import org.sonar.server.component.ComponentFinder;
+import org.sonar.server.user.UserSession;
 import org.sonarqube.ws.Settings;
 import org.sonarqube.ws.Settings.ValuesWsResponse;
+import org.sonarqube.ws.client.setting.ValuesRequest;
 
 import static org.elasticsearch.common.Strings.isNullOrEmpty;
 import static org.sonar.api.PropertyType.PROPERTY_SET;
+import static org.sonar.server.component.ComponentFinder.ParamNames.ID_AND_KEY;
 import static org.sonar.server.settings.ws.SettingsWsComponentParameters.addComponentParameters;
 import static org.sonar.server.ws.WsUtils.writeProtobuf;
+import static org.sonarqube.ws.client.setting.SettingsWsParameters.ACTION_VALUES;
 import static org.sonarqube.ws.client.setting.SettingsWsParameters.PARAM_COMPONENT_ID;
 import static org.sonarqube.ws.client.setting.SettingsWsParameters.PARAM_COMPONENT_KEY;
+import static org.sonarqube.ws.client.setting.SettingsWsParameters.PARAM_KEYS;
 
 public class ValuesAction implements SettingsWsAction {
 
   private static final Splitter COMMA_SPLITTER = Splitter.on(",");
 
-  private static final String PARAM_KEYS = "keys";
-
   private final DbClient dbClient;
-  private final SettingsWsComponentParameters settingsWsComponentParameters;
+  private final ComponentFinder componentFinder;
+  private final UserSession userSession;
   private final PropertyDefinitions propertyDefinitions;
   private final SettingsFinder settingsFinder;
 
-  public ValuesAction(DbClient dbClient, SettingsWsComponentParameters settingsWsComponentParameters, PropertyDefinitions propertyDefinitions, SettingsFinder settingsFinder) {
+  public ValuesAction(DbClient dbClient, ComponentFinder componentFinder, UserSession userSession, PropertyDefinitions propertyDefinitions, SettingsFinder settingsFinder) {
     this.dbClient = dbClient;
-    this.settingsWsComponentParameters = settingsWsComponentParameters;
+    this.componentFinder = componentFinder;
+    this.userSession = userSession;
     this.propertyDefinitions = propertyDefinitions;
     this.settingsFinder = settingsFinder;
   }
 
   @Override
   public void define(WebService.NewController context) {
-    WebService.NewAction action = context.createAction("values")
+    WebService.NewAction action = context.createAction(ACTION_VALUES)
       .setDescription("List settings values.<br>" +
         "If no value has been set for a setting, then the default value is returned.<br>" +
         "Either '%s' or '%s' can be provided, not both.<br> " +
@@ -82,7 +90,7 @@ public class ValuesAction implements SettingsWsAction {
       .setHandler(this);
     addComponentParameters(action);
     action.createParam(PARAM_KEYS)
-      .setDescription("List of property keys")
+      .setDescription("List of setting keys")
       .setRequired(true)
       .setExampleValue("sonar.technicalDebt.hoursInDay,sonar.dbcleaner.cleanDirectory");
   }
@@ -95,16 +103,41 @@ public class ValuesAction implements SettingsWsAction {
   private ValuesWsResponse doHandle(Request request) {
     DbSession dbSession = dbClient.openSession(true);
     try {
-      ComponentDto componentDto = settingsWsComponentParameters.getComponent(dbSession, request);
-      settingsWsComponentParameters.checkAdminPermission(componentDto);
-      Set<String> keys = new HashSet<>(request.mandatoryParamAsStrings(PARAM_KEYS));
-      Optional<ComponentDto> component = Optional.ofNullable(componentDto);
+      ValuesRequest valuesRequest = toWsRequest(request);
+      Optional<ComponentDto> component = getComponent(dbSession, valuesRequest);
+      checkAdminPermission(component);
+      Set<String> keys = new HashSet<>(valuesRequest.getKeys());
       return new ValuesResponseBuilder(loadSettings(dbSession, component, keys), component).build();
     } finally {
       dbClient.closeSession(dbSession);
     }
   }
 
+  private static ValuesRequest toWsRequest(Request request) {
+    return ValuesRequest.builder()
+      .setKeys(request.mandatoryParamAsStrings(PARAM_KEYS))
+      .setComponentId(request.param(PARAM_COMPONENT_ID))
+      .setComponentKey(request.param(PARAM_COMPONENT_KEY))
+      .build();
+  }
+
+  private Optional<ComponentDto> getComponent(DbSession dbSession, ValuesRequest valuesRequest) {
+    String componentId = valuesRequest.getComponentId();
+    String componentKey = valuesRequest.getComponentKey();
+    if (componentId != null || componentKey != null) {
+      return Optional.of(componentFinder.getByUuidOrKey(dbSession, componentId, componentKey, ID_AND_KEY));
+    }
+    return Optional.empty();
+  }
+
+  private void checkAdminPermission(Optional<ComponentDto> component) {
+    if (component.isPresent()) {
+      userSession.checkComponentUuidPermission(UserRole.ADMIN, component.get().uuid());
+    } else {
+      userSession.checkPermission(GlobalPermissions.SYSTEM_ADMIN);
+    }
+  }
+
   private List<Setting> loadSettings(DbSession dbSession, Optional<ComponentDto> component, Set<String> keys) {
     if (keys.isEmpty()) {
       return Collections.emptyList();
index ee060b1d13870c142b9abcd4b7e69ccde86c866a..2b17aa2c6649e1770dade66c213527ccadb87caa 100644 (file)
@@ -78,13 +78,12 @@ public class ValuesActionTest {
   DbClient dbClient = db.getDbClient();
   DbSession dbSession = db.getSession();
   ComponentDbTester componentDb = new ComponentDbTester(db);
-  SettingsWsComponentParameters settingsWsComponentParameters = new SettingsWsComponentParameters(new ComponentFinder(dbClient), userSession);
   PropertyDefinitions propertyDefinitions = new PropertyDefinitions();
   SettingsFinder settingsFinder = new SettingsFinder(dbClient, propertyDefinitions);
 
   ComponentDto project;
 
-  WsActionTester ws = new WsActionTester(new ValuesAction(dbClient, settingsWsComponentParameters, propertyDefinitions, settingsFinder));
+  WsActionTester ws = new WsActionTester(new ValuesAction(dbClient, new ComponentFinder(dbClient), userSession, propertyDefinitions, settingsFinder));
 
   @Before
   public void setUp() throws Exception {
@@ -376,7 +375,7 @@ public class ValuesActionTest {
     propertyDefinitions.addComponent(PropertyDefinition.builder("foo").build());
 
     expectedException.expect(ForbiddenException.class);
-    newRequestForGlobalProperties();
+    newRequestForGlobalProperties("foo");
   }
 
   @Test
@@ -385,7 +384,7 @@ public class ValuesActionTest {
     propertyDefinitions.addComponent(PropertyDefinition.builder("foo").build());
 
     expectedException.expect(ForbiddenException.class);
-    newRequest(project.uuid(), null);
+    newRequest(project.uuid(), null, "foo");
   }
 
   @Test
index ff5e53d669e8a6f3c4e8c6ea43fcb726d9243d8b..1b9f14007ca8a0fea249bb2d8658649524fa8bfb 100644 (file)
@@ -20,6 +20,7 @@
 package org.sonarqube.ws.client.setting;
 
 import org.sonarqube.ws.Settings.ListDefinitionsWsResponse;
+import org.sonarqube.ws.Settings.ValuesWsResponse;
 import org.sonarqube.ws.client.BaseService;
 import org.sonarqube.ws.client.GetRequest;
 import org.sonarqube.ws.client.WsConnector;
@@ -27,7 +28,9 @@ import org.sonarqube.ws.client.WsConnector;
 import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_COMPONENT_ID;
 import static org.sonarqube.ws.client.measure.MeasuresWsParameters.PARAM_COMPONENT_KEY;
 import static org.sonarqube.ws.client.setting.SettingsWsParameters.ACTION_LIST_DEFINITIONS;
+import static org.sonarqube.ws.client.setting.SettingsWsParameters.ACTION_VALUES;
 import static org.sonarqube.ws.client.setting.SettingsWsParameters.CONTROLLER_SETTINGS;
+import static org.sonarqube.ws.client.setting.SettingsWsParameters.PARAM_KEYS;
 
 public class SettingsService extends BaseService {
   public SettingsService(WsConnector wsConnector) {
@@ -41,4 +44,12 @@ public class SettingsService extends BaseService {
     return call(getRequest, ListDefinitionsWsResponse.parser());
   }
 
+  public ValuesWsResponse values(ValuesRequest request) {
+    GetRequest getRequest = new GetRequest(path(ACTION_VALUES))
+      .setParam(PARAM_KEYS, inlineMultipleParamValue(request.getKeys()))
+      .setParam(PARAM_COMPONENT_ID, request.getComponentId())
+      .setParam(PARAM_COMPONENT_KEY, request.getComponentKey());
+    return call(getRequest, ValuesWsResponse.parser());
+  }
+
 }
index e8b9f515cbce1c42c9a5732e44406e1eca5367e7..9c21076f684dcad2abe0367eb2e52285458d2927 100644 (file)
@@ -24,8 +24,14 @@ public class SettingsWsParameters {
   public static final String CONTROLLER_SETTINGS = "api/settings";
 
   public static final String ACTION_LIST_DEFINITIONS = "list_definitions";
+  public static final String ACTION_VALUES = "values";
 
   public static final String PARAM_COMPONENT_ID = "componentId";
   public static final String PARAM_COMPONENT_KEY = "componentKey";
+  public static final String PARAM_KEYS = "keys";
+
+  private SettingsWsParameters() {
+    // Only static stuff
+  }
 
 }
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/setting/ValuesRequest.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/setting/ValuesRequest.java
new file mode 100644 (file)
index 0000000..3c1d8d2
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.sonarqube.ws.client.setting;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Arrays.asList;
+import static java.util.Objects.requireNonNull;
+import static org.sonarqube.ws.client.setting.SettingsWsParameters.PARAM_KEYS;
+
+public class ValuesRequest {
+
+  private final String componentId;
+  private final String componentKey;
+  private final List<String> keys;
+
+  public ValuesRequest(Builder builder) {
+    this.componentId = builder.componentId;
+    this.componentKey = builder.componentKey;
+    this.keys = builder.keys;
+  }
+
+  @CheckForNull
+  public String getComponentId() {
+    return componentId;
+  }
+
+  @CheckForNull
+  public String getComponentKey() {
+    return componentKey;
+  }
+
+  public List<String> getKeys() {
+    return keys;
+  }
+
+  public static Builder builder() {
+    return new Builder();
+  }
+
+  public static class Builder {
+    private String componentId;
+    private String componentKey;
+    private List<String> keys = new ArrayList<>();
+
+    private Builder() {
+      // enforce factory method use
+    }
+
+    public Builder setComponentId(@Nullable String componentId) {
+      this.componentId = componentId;
+      return this;
+    }
+
+    public Builder setComponentKey(@Nullable String componentKey) {
+      this.componentKey = componentKey;
+      return this;
+    }
+
+    public Builder setKeys(List<String> keys) {
+      this.keys = requireNonNull(keys);
+      return this;
+    }
+
+    public Builder setKeys(String... keys) {
+      return setKeys(asList(keys));
+    }
+
+    public ValuesRequest build() {
+      checkArgument(!keys.isEmpty(), "'%s' cannot be empty", PARAM_KEYS);
+      return new ValuesRequest(this);
+    }
+  }
+
+}
index e8578b5699079717d112505195f74f50aa72a708..57607b16704c204e35af13b6c3800e86981cba99 100644 (file)
@@ -22,7 +22,8 @@ package org.sonarqube.ws.client.setting;
 
 import org.junit.Rule;
 import org.junit.Test;
-import org.sonarqube.ws.Settings;
+import org.sonarqube.ws.Settings.ListDefinitionsWsResponse;
+import org.sonarqube.ws.Settings.ValuesWsResponse;
 import org.sonarqube.ws.client.GetRequest;
 import org.sonarqube.ws.client.ServiceTester;
 import org.sonarqube.ws.client.WsConnector;
@@ -30,6 +31,7 @@ import org.sonarqube.ws.client.WsConnector;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
 import static org.sonarqube.ws.client.setting.SettingsWsParameters.PARAM_COMPONENT_KEY;
+import static org.sonarqube.ws.client.setting.SettingsWsParameters.PARAM_KEYS;
 
 public class SettingsServiceTest {
 
@@ -40,15 +42,28 @@ public class SettingsServiceTest {
 
   @Test
   public void list_definitions() {
-    ListDefinitionsRequest request = ListDefinitionsRequest.builder()
+    underTest.listDefinitions(ListDefinitionsRequest.builder()
       .setComponentKey("KEY")
-      .build();
+      .build());
+    GetRequest getRequest = serviceTester.getGetRequest();
+
+    assertThat(serviceTester.getGetParser()).isSameAs(ListDefinitionsWsResponse.parser());
+    serviceTester.assertThat(getRequest)
+      .hasParam(PARAM_COMPONENT_KEY, "KEY")
+      .andNoOtherParam();
+  }
 
-    underTest.listDefinitions(request);
+  @Test
+  public void values() {
+    underTest.values(ValuesRequest.builder()
+      .setKeys("sonar.debt,sonar.issue")
+      .setComponentKey("KEY")
+      .build());
     GetRequest getRequest = serviceTester.getGetRequest();
 
-    assertThat(serviceTester.getGetParser()).isSameAs(Settings.ListDefinitionsWsResponse.parser());
+    assertThat(serviceTester.getGetParser()).isSameAs(ValuesWsResponse.parser());
     serviceTester.assertThat(getRequest)
+      .hasParam(PARAM_KEYS, "sonar.debt,sonar.issue")
       .hasParam(PARAM_COMPONENT_KEY, "KEY")
       .andNoOtherParam();
   }
diff --git a/sonar-ws/src/test/java/org/sonarqube/ws/client/setting/ValuesRequestTest.java b/sonar-ws/src/test/java/org/sonarqube/ws/client/setting/ValuesRequestTest.java
new file mode 100644 (file)
index 0000000..1ee0d17
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.sonarqube.ws.client.setting;
+
+import java.util.List;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ValuesRequestTest {
+
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+
+  ValuesRequest.Builder underTest = ValuesRequest.builder();
+
+  @Test
+  public void create_request_with_no_component() {
+    ValuesRequest result = underTest.setKeys("sonar.debt").build();
+
+    assertThat(result.getComponentId()).isNull();
+    assertThat(result.getComponentKey()).isNull();
+    assertThat(result.getKeys()).containsOnly("sonar.debt");
+  }
+
+  @Test
+  public void create_request_with_component_id() {
+    ValuesRequest result = underTest.setKeys("sonar.debt").setComponentId("projectId").build();
+
+    assertThat(result.getComponentId()).isEqualTo("projectId");
+    assertThat(result.getComponentKey()).isNull();
+    assertThat(result.getKeys()).containsOnly("sonar.debt");
+  }
+
+  @Test
+  public void create_request_with_component_key() {
+    ValuesRequest result = underTest.setKeys("sonar.debt").setComponentKey("projectKey").build();
+
+    assertThat(result.getComponentId()).isNull();
+    assertThat(result.getComponentKey()).isEqualTo("projectKey");
+    assertThat(result.getKeys()).containsOnly("sonar.debt");
+  }
+
+  @Test
+  public void fail_when_keys_is_null() throws Exception {
+    expectedException.expect(NullPointerException.class);
+    underTest
+      .setKeys((List<String>) null)
+      .setComponentId("projectId")
+      .build();
+  }
+
+  @Test
+  public void fail_when_keys_is_empty() throws Exception {
+    expectedException.expect(IllegalArgumentException.class);
+    expectedException.expectMessage("'keys' cannot be empty");
+
+    underTest.setComponentId("projectId").build();
+  }
+
+}