aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorJulien Lancelot <julien.lancelot@sonarsource.com>2017-01-04 16:18:14 +0100
committerJulien Lancelot <julien.lancelot@sonarsource.com>2017-01-10 09:56:54 +0100
commitc54d9160675527e5b95c6af914be0bbaeb657627 (patch)
tree9058362b8b446ebd5548b188a77b4ba76b18a3f0 /server
parent7ee49838b7b3d4e657b80669a3bbf58d5658a220 (diff)
downloadsonarqube-c54d9160675527e5b95c6af914be0bbaeb657627.tar.gz
sonarqube-c54d9160675527e5b95c6af914be0bbaeb657627.zip
SONAR-7300 Deprecate and rewrite api/properties/index in Java
Diffstat (limited to 'server')
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/config/ws/IndexAction.java257
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/config/ws/PropertiesWs.java28
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/setting/ws/SettingsPermissionPredicates.java9
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/ws/WebServiceFilter.java32
-rw-r--r--server/sonar-server/src/main/resources/org/sonar/server/config/ws/index-example.json39
-rw-r--r--server/sonar-server/src/main/resources/org/sonar/server/config/ws/index-example.xml47
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/config/ws/IndexActionTest.java483
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/config/ws/PropertiesWsTest.java40
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/does_not_fail_when_user_has_not_project_browse_permission.json6
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/does_not_returned_secured_and_license_settings_in_property_set_when_not_authenticated.json13
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/does_not_returned_secured_and_license_settings_when_not_authenticated.json6
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/empty.json2
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_all_project_settings_when_component_and_no_key.json22
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_all_settings_when_no_component_and_no_key.json18
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_default_values.json6
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_global_values.json6
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_inherited_values_on_global_setting.json10
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_inherited_values_on_module.json18
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_license_with_hash_settings_when_authenticated_but_not_admin.json18
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_module_values.json6
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_multi_value_with_coma.json10
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_multi_values.json18
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_only_one_setting_when_key_is_provided.json6
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_project_values.json6
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_property_set.json22
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_secured_and_license_settings_in_property_set_when_system_admin.json21
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_secured_and_license_settings_when_project_admin.json18
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_secured_and_license_settings_when_system_admin.json18
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_simple_value.json6
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_values_even_if_no_property_definition.json6
30 files changed, 1069 insertions, 128 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/config/ws/IndexAction.java b/server/sonar-server/src/main/java/org/sonar/server/config/ws/IndexAction.java
new file mode 100644
index 00000000000..fef3bad5035
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/config/ws/IndexAction.java
@@ -0,0 +1,257 @@
+/*
+ * 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.sonar.server.config.ws;
+
+import com.google.common.base.Splitter;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Ordering;
+import com.google.common.collect.TreeMultimap;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import org.sonar.api.config.PropertyDefinition;
+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.utils.text.JsonWriter;
+import org.sonar.core.permission.GlobalPermissions;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.property.PropertyDto;
+import org.sonar.server.component.ComponentFinder;
+import org.sonar.server.user.UserSession;
+import org.sonar.server.ws.WsAction;
+
+import static org.apache.commons.lang.StringUtils.isEmpty;
+import static org.sonar.api.PropertyType.PROPERTY_SET;
+import static org.sonar.api.server.ws.RailsHandler.PARAM_FORMAT;
+import static org.sonar.api.server.ws.RailsHandler.addJsonOnlyFormatParam;
+import static org.sonar.api.web.UserRole.ADMIN;
+import static org.sonar.server.setting.ws.SettingsPermissionPredicates.DOT_LICENSE;
+import static org.sonar.server.setting.ws.SettingsPermissionPredicates.DOT_SECURED;
+import static org.sonar.server.ws.KeyExamples.KEY_PROJECT_EXAMPLE_001;
+
+public class IndexAction implements WsAction {
+
+ private static final Splitter DOT_SPLITTER = Splitter.on(".").omitEmptyStrings();
+ private static final Splitter COMMA_SPLITTER = Splitter.on(",");
+ private static final String COMMA_ENCODED_VALUE = "%2C";
+
+ private static final String PARAM_KEY = "key";
+ private static final String PARAM_COMPONENT = "resource";
+
+ private final DbClient dbClient;
+ private final ComponentFinder componentFinder;
+ private final UserSession userSession;
+ private final PropertyDefinitions propertyDefinitions;
+
+ public IndexAction(DbClient dbClient, ComponentFinder componentFinder, UserSession userSession, PropertyDefinitions propertyDefinitions) {
+ this.dbClient = dbClient;
+ this.componentFinder = componentFinder;
+ this.userSession = userSession;
+ this.propertyDefinitions = propertyDefinitions;
+ }
+
+ @Override
+ public void define(WebService.NewController context) {
+ WebService.NewAction action = context.createAction("index")
+ .setDescription("This web service is deprecated, please use api/settings/values instead.")
+ .setDeprecatedSince("6.3")
+ .setResponseExample(getClass().getResource("index-example.json"))
+ .setSince("2.6")
+ .setHandler(this);
+ action.createParam(PARAM_KEY)
+ .setDescription("Setting key")
+ .setExampleValue("sonar.technicalDebt.hoursInDay");
+ action.createParam(PARAM_COMPONENT)
+ .setDescription("Component key or database id")
+ .setExampleValue(KEY_PROJECT_EXAMPLE_001);
+ addJsonOnlyFormatParam(action);
+ }
+
+ @Override
+ public void handle(Request request, Response response) throws Exception {
+ request.param(PARAM_FORMAT);
+ JsonWriter json = response.newJsonWriter();
+ json.beginArray();
+ doHandle(json, request);
+ json.endArray();
+ json.close();
+ }
+
+ private void doHandle(JsonWriter json, Request request) {
+ DbSession dbSession = dbClient.openSession(true);
+ try {
+ Optional<ComponentDto> component = loadComponent(dbSession, request);
+ String key = request.param(PARAM_KEY);
+ List<PropertyDto> propertyDtos = loadProperties(dbSession, component, Optional.ofNullable(key));
+ new ResponseBuilder(propertyDtos).build(json);
+ } finally {
+ dbClient.closeSession(dbSession);
+ }
+ }
+
+ private Optional<ComponentDto> loadComponent(DbSession dbSession, Request request) {
+ String component = request.param(PARAM_COMPONENT);
+ if (component == null) {
+ return Optional.empty();
+ }
+ return Optional.of(loadComponent(dbSession, component));
+ }
+
+ private ComponentDto loadComponent(DbSession dbSession, String component) {
+ try {
+ Long componentId = Long.parseLong(component);
+ return componentFinder.getById(dbSession, componentId);
+ } catch (NumberFormatException e) {
+ return componentFinder.getByKey(dbSession, component);
+ }
+ }
+
+ private List<PropertyDto> loadProperties(DbSession dbSession, Optional<ComponentDto> component, Optional<String> key) {
+ // List of settings must be kept in the following orders : default -> global -> component
+ List<PropertyDto> propertyDtos = new ArrayList<>();
+ propertyDtos.addAll(loadDefaultSettings(key));
+ propertyDtos.addAll(loadGlobalSettings(dbSession, key));
+ component.ifPresent(componentDto -> propertyDtos.addAll(loadComponentSettings(dbSession, key, componentDto).values()));
+ return propertyDtos.stream().filter(isVisible(component)).collect(Collectors.toList());
+ }
+
+ Predicate<PropertyDto> isVisible(Optional<ComponentDto> component) {
+ return propertyDto -> !propertyDto.getKey().endsWith(DOT_SECURED)
+ || hasAdminPermission(component)
+ || (propertyDto.getKey().contains(DOT_LICENSE) && userSession.isLoggedIn());
+ }
+
+ private boolean hasAdminPermission(Optional<ComponentDto> component) {
+ return component.isPresent() ? userSession.hasComponentUuidPermission(ADMIN, component.get().uuid()) : userSession.hasPermission(GlobalPermissions.SYSTEM_ADMIN);
+ }
+
+ private List<PropertyDto> loadGlobalSettings(DbSession dbSession, Optional<String> key) {
+ if (key.isPresent()) {
+ return dbClient.propertiesDao().selectGlobalPropertiesByKeys(dbSession, Collections.singleton(key.get()));
+ }
+ return dbClient.propertiesDao().selectGlobalProperties(dbSession);
+ }
+
+ /**
+ * Return list of propertyDto by component uuid, sorted from project to lowest module
+ */
+ private Multimap<String, PropertyDto> loadComponentSettings(DbSession dbSession, Optional<String> key, ComponentDto component) {
+ List<String> componentUuids = DOT_SPLITTER.splitToList(component.moduleUuidPath());
+ List<ComponentDto> componentDtos = dbClient.componentDao().selectByUuids(dbSession, componentUuids);
+ Set<Long> componentIds = componentDtos.stream().map(ComponentDto::getId).collect(Collectors.toSet());
+ Map<Long, String> uuidsById = componentDtos.stream().collect(Collectors.toMap(ComponentDto::getId, ComponentDto::uuid));
+ List<PropertyDto> properties = key.isPresent() ? dbClient.propertiesDao().selectPropertiesByKeysAndComponentIds(dbSession, Collections.singleton(key.get()), componentIds)
+ : dbClient.propertiesDao().selectPropertiesByComponentIds(dbSession, componentIds);
+
+ Multimap<String, PropertyDto> propertyDtosByUuid = TreeMultimap.create(Ordering.explicit(componentUuids), Ordering.arbitrary());
+ for (PropertyDto propertyDto : properties) {
+ Long componentId = propertyDto.getResourceId();
+ String componentUuid = uuidsById.get(componentId);
+ propertyDtosByUuid.put(componentUuid, propertyDto);
+ }
+ return propertyDtosByUuid;
+ }
+
+ private List<PropertyDto> loadDefaultSettings(Optional<String> key) {
+ return propertyDefinitions.getAll().stream()
+ .filter(definition -> !key.isPresent() || key.get().equals(definition.key()))
+ .filter(defaultProperty -> !isEmpty(defaultProperty.defaultValue()))
+ .map(definition -> new PropertyDto().setKey(definition.key()).setValue(definition.defaultValue()))
+ .collect(Collectors.toList());
+ }
+
+ private class ResponseBuilder {
+ private final List<PropertyDto> propertyDtos;
+ private final Map<String, Property> propertiesByKey = new HashMap<>();
+
+ ResponseBuilder(List<PropertyDto> propertyDtos) {
+ this.propertyDtos = propertyDtos;
+ }
+
+ void build(JsonWriter json) {
+ processSettings();
+ propertiesByKey.values().forEach(property -> {
+ json.beginObject()
+ .prop("key", property.key)
+ .prop("value", property.value);
+ if (!property.values.isEmpty()) {
+ json.name("values").beginArray().values(property.values).endArray();
+ }
+ json.endObject();
+ });
+ }
+
+ private void processSettings() {
+ propertyDtos.forEach(setting -> {
+ Property property = createProperty(setting.getKey());
+ setValue(setting, property);
+ });
+ }
+
+ private Property createProperty(String key) {
+ return propertiesByKey.computeIfAbsent(key, k -> new Property(key));
+ }
+
+ private void setValue(PropertyDto propertyDto, Property property) {
+ String value = propertyDto.getValue();
+ property.setValue(value);
+ PropertyDefinition definition = propertyDefinitions.get(propertyDto.getKey());
+ if (definition != null && (definition.multiValues() || definition.type().equals(PROPERTY_SET))) {
+ property.setValues(createValues(value));
+ }
+ }
+
+ private List<String> createValues(String value) {
+ return COMMA_SPLITTER.splitToList(value).stream().map(v -> v.replace(COMMA_ENCODED_VALUE, ",")).collect(Collectors.toList());
+ }
+ }
+
+ private static class Property {
+ private final String key;
+ private String value;
+ private List<String> values = new ArrayList<>();
+
+ public Property(String key) {
+ this.key = key;
+ }
+
+ public Property setValue(String value) {
+ this.value = value;
+ return this;
+ }
+
+ public Property setValues(List<String> values) {
+ this.values = values;
+ return this;
+ }
+ }
+
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/config/ws/PropertiesWs.java b/server/sonar-server/src/main/java/org/sonar/server/config/ws/PropertiesWs.java
index 3aa3f58d8a0..3870bff9e62 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/config/ws/PropertiesWs.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/config/ws/PropertiesWs.java
@@ -19,30 +19,24 @@
*/
package org.sonar.server.config.ws;
-import org.sonar.api.server.ws.RailsHandler;
import org.sonar.api.server.ws.WebService;
-import static org.sonar.api.server.ws.RailsHandler.addFormatParam;
-
public class PropertiesWs implements WebService {
- @Override
- public void define(Context context) {
- NewController controller = context.createController("api/properties");
- controller.setDescription("Manage global and project properties.");
- controller.setSince("2.6");
+ public static final String CONTROLLER_PROPERTIES = "api/properties";
- defineIndexAction(controller);
+ private final IndexAction indexAction;
- controller.done();
+ public PropertiesWs(IndexAction indexAction) {
+ this.indexAction = indexAction;
}
- private void defineIndexAction(NewController controller) {
- NewAction action = controller.createAction("index")
- .setDescription("Documentation of this web service is available <a href=\"http://redirect.sonarsource.com/doc/old-web-service-api.html\">here</a>")
- .setResponseExample(getClass().getResource("index-example.xml"))
- .setSince("2.6")
- .setHandler(RailsHandler.INSTANCE);
- addFormatParam(action);
+ @Override
+ public void define(Context context) {
+ NewController controller = context.createController(CONTROLLER_PROPERTIES)
+ .setDescription("This web service is deprecated, please use api/settings instead.")
+ .setSince("2.6");
+ indexAction.define(controller);
+ controller.done();
}
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/setting/ws/SettingsPermissionPredicates.java b/server/sonar-server/src/main/java/org/sonar/server/setting/ws/SettingsPermissionPredicates.java
index 53eb10147b7..ef4482efb6b 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/setting/ws/SettingsPermissionPredicates.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/setting/ws/SettingsPermissionPredicates.java
@@ -32,9 +32,10 @@ import static org.sonar.api.web.UserRole.ADMIN;
public class SettingsPermissionPredicates {
- private static final String SECURED_SUFFIX = ".secured";
- static final String LICENSE_SUFFIX = ".license.secured";
- static final String LICENSE_HASH_SUFFIX = ".licenseHash.secured";
+ public static final String DOT_SECURED = ".secured";
+ public static final String DOT_LICENSE = ".license";
+ static final String LICENSE_SUFFIX = DOT_LICENSE + DOT_SECURED;
+ static final String LICENSE_HASH_SUFFIX = ".licenseHash" + DOT_SECURED;
private final UserSession userSession;
@@ -55,7 +56,7 @@ public class SettingsPermissionPredicates {
}
private boolean verifySecuredSetting(String key, @Nullable PropertyDefinition definition, Optional<ComponentDto> component) {
- return isLicense(key, definition) || (!key.endsWith(SECURED_SUFFIX) || hasAdminPermission(component));
+ return isLicense(key, definition) || (!key.endsWith(DOT_SECURED) || hasAdminPermission(component));
}
private boolean hasAdminPermission(Optional<ComponentDto> component) {
diff --git a/server/sonar-server/src/main/java/org/sonar/server/ws/WebServiceFilter.java b/server/sonar-server/src/main/java/org/sonar/server/ws/WebServiceFilter.java
index 1c5e10b44d2..028c5c1760f 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/ws/WebServiceFilter.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/ws/WebServiceFilter.java
@@ -29,8 +29,11 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.sonar.api.server.ws.RailsHandler;
+import org.sonar.api.server.ws.WebService;
import org.sonar.api.web.ServletFilter;
+import static org.sonar.server.config.ws.PropertiesWs.CONTROLLER_PROPERTIES;
+
/**
* This filter is used to execute Java WS.
*
@@ -45,11 +48,11 @@ public class WebServiceFilter extends ServletFilter {
public WebServiceFilter(WebServiceEngine webServiceEngine) {
this.webServiceEngine = webServiceEngine;
- webServiceEngine.controllers().stream()
- .forEach(controller -> controller.actions().stream()
+ webServiceEngine.controllers()
+ .forEach(controller -> controller.actions()
.forEach(action -> {
- // Rails and servlet filter WS should not be executed by the web service engine
- if (!(action.handler() instanceof RailsHandler) && !(action.handler() instanceof ServletFilterHandler)) {
+ // Rails, Rest and servlet filter WS should not be executed by the web service engine
+ if (isJavaWs(controller, action)) {
includeUrls.add("/" + controller.path() + "/*");
} else {
excludeUrls.add("/" + action.path() + "*");
@@ -84,21 +87,10 @@ public class WebServiceFilter extends ServletFilter {
// Nothing to do
}
- private static class WsUrl {
- private final String controller;
- private final String action;
-
- WsUrl(String controller, String action) {
- this.controller = controller;
- this.action = action;
- }
-
- String getController() {
- return controller;
- }
-
- String getAction() {
- return action;
- }
+ private static boolean isJavaWs(WebService.Controller controller, WebService.Action action) {
+ return !(action.handler() instanceof RailsHandler)
+ && !(action.handler() instanceof ServletFilterHandler)
+ && !controller.path().equals(CONTROLLER_PROPERTIES);
}
+
}
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/config/ws/index-example.json b/server/sonar-server/src/main/resources/org/sonar/server/config/ws/index-example.json
new file mode 100644
index 00000000000..9574238f574
--- /dev/null
+++ b/server/sonar-server/src/main/resources/org/sonar/server/config/ws/index-example.json
@@ -0,0 +1,39 @@
+[
+ {
+ "key": "sonar.test.jira",
+ "value": "abc"
+ },
+ {
+ "key": "sonar.autogenerated",
+ "value": "val1,val2,val3",
+ "values": [
+ "val1",
+ "val2",
+ "val3"
+ ]
+ },
+ {
+ "key": "sonar.demo",
+ "value": "1,2",
+ "values": [
+ "1",
+ "2"
+ ]
+ },
+ {
+ "key": "sonar.demo.1.text",
+ "value": "foo"
+ },
+ {
+ "key": "sonar.demo.1.boolean",
+ "value": "true"
+ },
+ {
+ "key": "sonar.demo.2.text",
+ "value": "bar"
+ },
+ {
+ "key": "sonar.demo.2.boolean",
+ "value": "false"
+ }
+]
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/config/ws/index-example.xml b/server/sonar-server/src/main/resources/org/sonar/server/config/ws/index-example.xml
deleted file mode 100644
index 33186f28bd9..00000000000
--- a/server/sonar-server/src/main/resources/org/sonar/server/config/ws/index-example.xml
+++ /dev/null
@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<properties>
- <property>
- <key>sonar.core.treemap.colormetric</key>
- <value><![CDATA[violations_density]]></value>
- </property>
- <property>
- <key>sonar.core.treemap.sizemetric</key>
- <value><![CDATA[ncloc]]></value>
- </property>
- <property>
- <key>sonar.plsql.suffixes</key>
- <value><![CDATA[sql,tab,pkb]]></value>
- </property>
- <property>
- <key>sonar.build-stability.days</key>
- <value><![CDATA[30]]></value>
- </property>
- <property>
- <key>sonar.dbcleaner.monthsBeforeDeletingAllSnapshots</key>
- <value><![CDATA[120]]></value>
- </property>
- <property>
- <key>sonar.c.predefinedMacros</key>
- <value><![CDATA[#define MY_MACRO(a) struct a {}]]></value>
- </property>
- <property>
- <key>sonar.scm.enabled</key>
- <value><![CDATA[true]]></value>
- </property>
- <property>
- <key>sonar.cpd.cross_project</key>
- <value><![CDATA[true]]></value>
- </property>
- <property>
- <key>sonar.forceAuthentication</key>
- <value><![CDATA[true]]></value>
- </property>
- <property>
- <key>sonar.dbcleaner.weeksBeforeDeletingAllSnapshots</key>
- <value><![CDATA[480]]></value>
- </property>
- <property>
- <key>sonar.java.coveragePlugin</key>
- <value><![CDATA[jacoco]]></value>
- </property>
-</properties>
diff --git a/server/sonar-server/src/test/java/org/sonar/server/config/ws/IndexActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/config/ws/IndexActionTest.java
new file mode 100644
index 00000000000..1aba7354382
--- /dev/null
+++ b/server/sonar-server/src/test/java/org/sonar/server/config/ws/IndexActionTest.java
@@ -0,0 +1,483 @@
+/*
+ * 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.sonar.server.config.ws;
+
+import com.google.common.collect.ImmutableMap;
+import java.net.URL;
+import javax.annotation.Nullable;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.PropertyType;
+import org.sonar.api.config.PropertyDefinition;
+import org.sonar.api.config.PropertyDefinitions;
+import org.sonar.api.config.PropertyFieldDefinition;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.api.utils.System2;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbTester;
+import org.sonar.db.component.ComponentDbTester;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.property.PropertyDbTester;
+import org.sonar.server.component.ComponentFinder;
+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 static java.util.Arrays.asList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.api.PropertyType.LICENSE;
+import static org.sonar.api.web.UserRole.ADMIN;
+import static org.sonar.api.web.UserRole.CODEVIEWER;
+import static org.sonar.api.web.UserRole.USER;
+import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
+import static org.sonar.db.component.ComponentTesting.newModuleDto;
+import static org.sonar.db.component.ComponentTesting.newProjectDto;
+import static org.sonar.db.property.PropertyTesting.newComponentPropertyDto;
+import static org.sonar.db.property.PropertyTesting.newGlobalPropertyDto;
+import static org.sonar.test.JsonAssert.assertJson;
+import static org.sonarqube.ws.MediaTypes.JSON;
+
+public class IndexActionTest {
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ @Rule
+ public UserSessionRule userSession = UserSessionRule.standalone();
+
+ @Rule
+ public DbTester db = DbTester.create(System2.INSTANCE);
+
+ DbClient dbClient = db.getDbClient();
+ PropertyDbTester propertyDb = new PropertyDbTester(db);
+ ComponentDbTester componentDb = new ComponentDbTester(db);
+ PropertyDefinitions definitions = new PropertyDefinitions();
+
+ ComponentDto project;
+
+ WsActionTester ws = new WsActionTester(new IndexAction(dbClient, new ComponentFinder(dbClient), userSession, definitions));
+
+ @Before
+ public void setUp() throws Exception {
+ project = componentDb.insertComponent(newProjectDto());
+ }
+
+ @Test
+ public void return_simple_value() throws Exception {
+ setAuthenticatedUser();
+ definitions.addComponent(PropertyDefinition.builder("foo").build());
+ propertyDb.insertProperties(newGlobalPropertyDto().setKey("foo").setValue("one"));
+
+ executeAndVerify(null, null, "return_simple_value.json");
+ }
+
+ @Test
+ public void return_multi_values() throws Exception {
+ setAuthenticatedUser();
+ // Property never defined, default value is returned
+ definitions.addComponent(PropertyDefinition.builder("default")
+ .multiValues(true)
+ .defaultValue("one,two")
+ .build());
+ // Property defined at global level
+ definitions.addComponent(PropertyDefinition.builder("global")
+ .multiValues(true)
+ .build());
+ propertyDb.insertProperties(newGlobalPropertyDto().setKey("global").setValue("three,four"));
+
+ executeAndVerify(null, null, "return_multi_values.json");
+ }
+
+ @Test
+ public void return_multi_value_with_coma() throws Exception {
+ setAuthenticatedUser();
+ definitions.addComponent(PropertyDefinition.builder("global").multiValues(true).build());
+ propertyDb.insertProperties(newGlobalPropertyDto().setKey("global").setValue("three,four%2Cfive"));
+
+ executeAndVerify(null, null, "return_multi_value_with_coma.json");
+ }
+
+ @Test
+ public void return_property_set() throws Exception {
+ setAuthenticatedUser();
+ definitions.addComponent(PropertyDefinition
+ .builder("foo")
+ .type(PropertyType.PROPERTY_SET)
+ .fields(asList(
+ PropertyFieldDefinition.build("key").name("Key").build(),
+ PropertyFieldDefinition.build("size").name("Size").build()))
+ .build());
+ propertyDb.insertPropertySet("foo", null, ImmutableMap.of("key", "key1", "size", "size1"), ImmutableMap.of("key", "key2"));
+
+ executeAndVerify(null, null, "return_property_set.json");
+ }
+
+ @Test
+ public void return_default_values() throws Exception {
+ setAuthenticatedUser();
+ definitions.addComponent(PropertyDefinition.builder("foo").defaultValue("default").build());
+
+ executeAndVerify(null, null, "return_default_values.json");
+ }
+
+ @Test
+ public void return_global_values() throws Exception {
+ setAuthenticatedUser();
+ definitions.addComponent(PropertyDefinition.builder("property").defaultValue("default").build());
+ propertyDb.insertProperties(
+ // The property is overriding default value
+ newGlobalPropertyDto().setKey("property").setValue("one"));
+
+ executeAndVerify(null, null, "return_global_values.json");
+ }
+
+ @Test
+ public void return_project_values() throws Exception {
+ setUserWithBrowsePermissionOnProject();
+ definitions.addComponent(PropertyDefinition.builder("property").defaultValue("default").build());
+ propertyDb.insertProperties(
+ newGlobalPropertyDto().setKey("property").setValue("one"),
+ // The property is overriding global value
+ newComponentPropertyDto(project).setKey("property").setValue("two"));
+
+ executeAndVerify(project.key(), null, "return_project_values.json");
+ }
+
+ @Test
+ public void return_values_even_if_no_property_definition() throws Exception {
+ setAuthenticatedUser();
+ propertyDb.insertProperties(newGlobalPropertyDto().setKey("globalPropertyWithoutDefinition").setValue("value"));
+
+ executeAndVerify(null, null, "return_values_even_if_no_property_definition.json");
+ }
+
+ @Test
+ public void return_empty_when_property_def_exists_but_no_value() throws Exception {
+ setAuthenticatedUser();
+ definitions.addComponent(PropertyDefinition.builder("foo").build());
+
+ executeAndVerify(null, null, "empty.json");
+ }
+
+ @Test
+ public void return_nothing_when_unknown_key() throws Exception {
+ setAuthenticatedUser();
+ definitions.addComponent(PropertyDefinition.builder("foo").defaultValue("default").build());
+ propertyDb.insertProperties(newGlobalPropertyDto().setKey("bar").setValue(""));
+
+ executeAndVerify(null, "unknown", "empty.json");
+ }
+
+ @Test
+ public void return_module_values() throws Exception {
+ setUserWithBrowsePermissionOnProject();
+ ComponentDto module = componentDb.insertComponent(newModuleDto(project));
+ definitions.addComponent(PropertyDefinition.builder("property").defaultValue("default").build());
+ propertyDb.insertProperties(
+ newGlobalPropertyDto().setKey("property").setValue("one"),
+ // The property is overriding global value
+ newComponentPropertyDto(module).setKey("property").setValue("two"));
+
+ executeAndVerify(module.key(), "property", "return_module_values.json");
+ }
+
+ @Test
+ public void return_inherited_values_on_module() throws Exception {
+ setUserWithBrowsePermissionOnProject();
+ ComponentDto module = componentDb.insertComponent(newModuleDto(project));
+ definitions.addComponents(asList(
+ PropertyDefinition.builder("defaultProperty").defaultValue("default").build(),
+ PropertyDefinition.builder("globalProperty").build(),
+ PropertyDefinition.builder("projectProperty").build(),
+ PropertyDefinition.builder("moduleProperty").build()));
+ propertyDb.insertProperties(
+ newGlobalPropertyDto().setKey("globalProperty").setValue("global"),
+ newComponentPropertyDto(project).setKey("projectProperty").setValue("project"),
+ newComponentPropertyDto(module).setKey("moduleProperty").setValue("module"));
+
+ executeAndVerify(module.key(), null, "return_inherited_values_on_module.json");
+ }
+
+ @Test
+ public void return_inherited_values_on_global_setting() throws Exception {
+ setAuthenticatedUser();
+ definitions.addComponents(asList(
+ PropertyDefinition.builder("defaultProperty").defaultValue("default").build(),
+ PropertyDefinition.builder("globalProperty").build()));
+ propertyDb.insertProperties(
+ newGlobalPropertyDto().setKey("globalProperty").setValue("global"));
+
+ executeAndVerify(null, null, "return_inherited_values_on_global_setting.json");
+ }
+
+ @Test
+ public void does_not_return_value_of_deprecated_key() throws Exception {
+ setAuthenticatedUser();
+ definitions.addComponent(PropertyDefinition.builder("foo").deprecatedKey("deprecated").build());
+ propertyDb.insertProperties(newGlobalPropertyDto().setKey("foo").setValue("one"));
+
+ executeAndVerify(null, "deprecated", "empty.json");
+ }
+
+ @Test
+ public void does_not_returned_secured_and_license_settings_when_not_authenticated() throws Exception {
+ definitions.addComponents(asList(
+ PropertyDefinition.builder("foo").build(),
+ PropertyDefinition.builder("secret.secured").build(),
+ PropertyDefinition.builder("plugin.license.secured").type(LICENSE).build()));
+ propertyDb.insertProperties(
+ newGlobalPropertyDto().setKey("foo").setValue("one"),
+ newGlobalPropertyDto().setKey("secret.secured").setValue("password"),
+ newGlobalPropertyDto().setKey("plugin.license.secured").setValue("ABCD"));
+
+ executeAndVerify(null, null, "does_not_returned_secured_and_license_settings_when_not_authenticated.json");
+ }
+
+ @Test
+ public void does_not_returned_secured_and_license_settings_in_property_set_when_not_authenticated() throws Exception {
+ definitions.addComponent(PropertyDefinition
+ .builder("foo")
+ .type(PropertyType.PROPERTY_SET)
+ .fields(asList(
+ PropertyFieldDefinition.build("key").name("Key").build(),
+ PropertyFieldDefinition.build("plugin.license.secured").name("License").type(LICENSE).build(),
+ PropertyFieldDefinition.build("secret.secured").name("Secured").build()))
+ .build());
+ propertyDb.insertPropertySet("foo", null,
+ ImmutableMap.of("key", "key1", "plugin.license.secured", "ABCD", "secret.secured", "123456"));
+
+ executeAndVerify(null, null, "does_not_returned_secured_and_license_settings_in_property_set_when_not_authenticated.json");
+ }
+
+ @Test
+ public void return_license_with_hash_settings_when_authenticated_but_not_admin() throws Exception {
+ setUserWithBrowsePermissionOnProject();
+ definitions.addComponents(asList(
+ PropertyDefinition.builder("foo").build(),
+ PropertyDefinition.builder("secret.secured").build(),
+ PropertyDefinition.builder("commercial.plugin").type(LICENSE).build(),
+ PropertyDefinition.builder("plugin.license.secured").type(LICENSE).build()));
+ propertyDb.insertProperties(
+ newGlobalPropertyDto().setKey("foo").setValue("one"),
+ newGlobalPropertyDto().setKey("secret.secured").setValue("password"),
+ newGlobalPropertyDto().setKey("commercial.plugin").setValue("ABCD"),
+ newGlobalPropertyDto().setKey("plugin.license.secured").setValue("ABCD"),
+ newGlobalPropertyDto().setKey("plugin.licenseHash.secured").setValue("987654321"));
+
+ executeAndVerify(null, null, "return_license_with_hash_settings_when_authenticated_but_not_admin.json");
+ }
+
+ @Test
+ public void return_secured_and_license_settings_when_system_admin() throws Exception {
+ setUserAsSystemAdmin();
+ definitions.addComponents(asList(
+ PropertyDefinition.builder("foo").build(),
+ PropertyDefinition.builder("secret.secured").build(),
+ PropertyDefinition.builder("plugin.license.secured").type(LICENSE).build()));
+ propertyDb.insertProperties(
+ newGlobalPropertyDto().setKey("foo").setValue("one"),
+ newGlobalPropertyDto().setKey("secret.secured").setValue("password"),
+ newGlobalPropertyDto().setKey("plugin.license.secured").setValue("ABCD"),
+ newGlobalPropertyDto().setKey("plugin.licenseHash.secured").setValue("987654321"));
+
+ executeAndVerify(null, null, "return_secured_and_license_settings_when_system_admin.json");
+ }
+
+ @Test
+ public void return_secured_and_license_settings_when_project_admin() throws Exception {
+ setUserAsProjectAdmin();
+ definitions.addComponents(asList(
+ PropertyDefinition.builder("foo").build(),
+ PropertyDefinition.builder("secret.secured").build(),
+ PropertyDefinition.builder("plugin.license.secured").type(LICENSE).build()));
+ propertyDb.insertProperties(
+ newComponentPropertyDto(project).setKey("foo").setValue("one"),
+ newComponentPropertyDto(project).setKey("secret.secured").setValue("password"),
+ newComponentPropertyDto(project).setKey("plugin.license.secured").setValue("ABCD"),
+ newComponentPropertyDto(project).setKey("plugin.licenseHash.secured").setValue("987654321"));
+
+ executeAndVerify(project.key(), null, "return_secured_and_license_settings_when_project_admin.json");
+ }
+
+ @Test
+ public void return_secured_and_license_settings_in_property_set_when_system_admin() throws Exception {
+ setUserAsSystemAdmin();
+ definitions.addComponent(PropertyDefinition
+ .builder("foo")
+ .type(PropertyType.PROPERTY_SET)
+ .fields(asList(
+ PropertyFieldDefinition.build("key").name("Key").build(),
+ PropertyFieldDefinition.build("plugin.license.secured").name("License").type(LICENSE).build(),
+ PropertyFieldDefinition.build("secret.secured").name("Secured").build()))
+ .build());
+ propertyDb.insertPropertySet("foo", null,
+ ImmutableMap.of("key", "key1", "plugin.license.secured", "ABCD", "secret.secured", "123456"));
+
+ executeAndVerify(null, null, "return_secured_and_license_settings_in_property_set_when_system_admin.json");
+ }
+
+ @Test
+ public void return_all_settings_when_no_component_and_no_key() throws Exception {
+ setUserAsSystemAdmin();
+ definitions.addComponents(asList(
+ PropertyDefinition.builder("foo").build(),
+ PropertyDefinition.builder("secret.secured").build(),
+ PropertyDefinition.builder("plugin.license.secured").type(LICENSE).build()));
+ propertyDb.insertProperties(
+ newGlobalPropertyDto().setKey("foo").setValue("one"),
+ newGlobalPropertyDto().setKey("secret.secured").setValue("password"),
+ newGlobalPropertyDto().setKey("plugin.license.secured").setValue("ABCD"),
+ newGlobalPropertyDto().setKey("not_defined").setValue("ABCD"));
+
+ executeAndVerify(null, null, "return_all_settings_when_no_component_and_no_key.json");
+ }
+
+ @Test
+ public void return_all_project_settings_when_component_and_no_key() throws Exception {
+ setUserAsProjectAdmin();
+ definitions.addComponents(asList(
+ PropertyDefinition.builder("foo").build(),
+ PropertyDefinition.builder("secret.secured").build(),
+ PropertyDefinition.builder("plugin.license.secured").type(LICENSE).build()));
+ propertyDb.insertProperties(
+ newComponentPropertyDto(project).setKey("foo").setValue("one"),
+ newComponentPropertyDto(project).setKey("secret.secured").setValue("password"),
+ newComponentPropertyDto(project).setKey("plugin.license.secured").setValue("ABCD"),
+ newComponentPropertyDto(project).setKey("not_defined").setValue("ABCD"),
+ newGlobalPropertyDto().setKey("global_not_defined").setValue("ABCD"));
+
+ executeAndVerify(project.key(), null, "return_all_project_settings_when_component_and_no_key.json");
+ }
+
+ @Test
+ public void return_only_one_setting_when_key_is_provided() throws Exception {
+ definitions.addComponents(asList(
+ PropertyDefinition.builder("foo").build(),
+ PropertyDefinition.builder("bar").build()));
+ propertyDb.insertProperties(
+ newGlobalPropertyDto().setKey("foo").setValue("one"),
+ newGlobalPropertyDto().setKey("bar").setValue("two"));
+
+ executeAndVerify(project.key(), "foo", "return_only_one_setting_when_key_is_provided.json");
+ executeAndVerify(project.key(), "unknown", "empty.json");
+ }
+
+ @Test
+ public void does_not_fail_when_user_has_not_project_browse_permission() throws Exception {
+ userSession.login("project-admin").addProjectUuidPermissions(CODEVIEWER, project.uuid());
+ definitions.addComponent(PropertyDefinition.builder("foo").build());
+ propertyDb.insertProperties(newComponentPropertyDto(project).setKey("foo").setValue("one"));
+
+ executeAndVerify(project.key(), null, "does_not_fail_when_user_has_not_project_browse_permission.json");
+ }
+
+ @Test
+ public void does_not_fail_when_format_is_set_to_json() throws Exception {
+ setAuthenticatedUser();
+ definitions.addComponent(PropertyDefinition.builder("foo").defaultValue("default").build());
+
+ ws.newRequest().setParam("format", "json").execute();
+ }
+
+ @Test
+ public void fail_when_format_is_set_to_xml() throws Exception {
+ setAuthenticatedUser();
+ definitions.addComponent(PropertyDefinition.builder("foo").defaultValue("default").build());
+
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Value of parameter 'format' (xml) must be one of: [json]");
+ ws.newRequest().setParam("format", "xml").execute();
+ }
+
+ @Test
+ public void test_example_json_response() {
+ setAuthenticatedUser();
+ definitions.addComponent(PropertyDefinition
+ .builder("sonar.test.jira")
+ .defaultValue("abc")
+ .build());
+ definitions.addComponent(PropertyDefinition
+ .builder("sonar.autogenerated")
+ .multiValues(true)
+ .build());
+ propertyDb.insertProperties(newGlobalPropertyDto().setKey("sonar.autogenerated").setValue("val1,val2,val3"));
+ definitions.addComponent(PropertyDefinition
+ .builder("sonar.demo")
+ .type(PropertyType.PROPERTY_SET)
+ .fields(PropertyFieldDefinition.build("text").name("Text").build(),
+ PropertyFieldDefinition.build("boolean").name("Boolean").build())
+ .build());
+ propertyDb.insertPropertySet("sonar.demo", null, ImmutableMap.of("text", "foo", "boolean", "true"), ImmutableMap.of("text", "bar", "boolean", "false"));
+
+ String result = ws.newRequest().setMediaType(JSON).execute().getInput();
+
+ JsonAssert.assertJson(ws.getDef().responseExampleAsString()).isSimilarTo(result);
+ }
+
+ @Test
+ public void test_ws_definition() {
+ WebService.Action action = ws.getDef();
+ assertThat(action).isNotNull();
+ assertThat(action.isInternal()).isFalse();
+ assertThat(action.isPost()).isFalse();
+ assertThat(action.responseExampleAsString()).isNotEmpty();
+ assertThat(action.params()).hasSize(3);
+ }
+
+ private void executeAndVerify(@Nullable String componentKey, @Nullable String key, String expectedFile) {
+ TestRequest request = ws.newRequest().setMediaType(MediaTypes.JSON);
+ if (key != null) {
+ request.setParam("key", key);
+ }
+ if (componentKey != null) {
+ request.setParam("resource", componentKey);
+ }
+ String result = request.execute().getInput();
+ assertJson(result).isSimilarTo(resource(expectedFile));
+ }
+
+ private void setAuthenticatedUser() {
+ userSession.login("user");
+ }
+
+ private void setUserWithBrowsePermissionOnProject() {
+ userSession.login("user").addProjectUuidPermissions(USER, project.uuid());
+ }
+
+ private void setUserAsSystemAdmin() {
+ userSession.login("admin").setGlobalPermissions(SYSTEM_ADMIN);
+ }
+
+ private void setUserAsProjectAdmin() {
+ userSession.login("project-admin")
+ .addProjectUuidPermissions(ADMIN, project.uuid())
+ .addProjectUuidPermissions(USER, project.uuid());
+ }
+
+ protected static URL resource(String s) {
+ Class<IndexActionTest> clazz = IndexActionTest.class;
+ return clazz.getResource(clazz.getSimpleName() + "/" + s);
+ }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/config/ws/PropertiesWsTest.java b/server/sonar-server/src/test/java/org/sonar/server/config/ws/PropertiesWsTest.java
deleted file mode 100644
index c9914b1b94f..00000000000
--- a/server/sonar-server/src/test/java/org/sonar/server/config/ws/PropertiesWsTest.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.sonar.server.config.ws;
-
-import org.junit.Test;
-import org.sonar.api.server.ws.WebService;
-import org.sonar.server.ws.WsTester;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class PropertiesWsTest {
-
- WsTester tester = new WsTester(new PropertiesWs());
-
- @Test
- public void define_ws() {
- WebService.Controller controller = tester.controller("api/properties");
- assertThat(controller).isNotNull();
- assertThat(controller.description()).isNotEmpty();
- assertThat(controller.actions()).hasSize(1);
- }
-
-}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/does_not_fail_when_user_has_not_project_browse_permission.json b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/does_not_fail_when_user_has_not_project_browse_permission.json
new file mode 100644
index 00000000000..d98b4c40613
--- /dev/null
+++ b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/does_not_fail_when_user_has_not_project_browse_permission.json
@@ -0,0 +1,6 @@
+[
+ {
+ "key": "foo",
+ "value": "one"
+ }
+]
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/does_not_returned_secured_and_license_settings_in_property_set_when_not_authenticated.json b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/does_not_returned_secured_and_license_settings_in_property_set_when_not_authenticated.json
new file mode 100644
index 00000000000..1475b5a81e6
--- /dev/null
+++ b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/does_not_returned_secured_and_license_settings_in_property_set_when_not_authenticated.json
@@ -0,0 +1,13 @@
+[
+ {
+ "key": "foo",
+ "value": "1",
+ "values": [
+ "1"
+ ]
+ },
+ {
+ "key": "foo.1.key",
+ "value": "key1"
+ }
+]
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/does_not_returned_secured_and_license_settings_when_not_authenticated.json b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/does_not_returned_secured_and_license_settings_when_not_authenticated.json
new file mode 100644
index 00000000000..d98b4c40613
--- /dev/null
+++ b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/does_not_returned_secured_and_license_settings_when_not_authenticated.json
@@ -0,0 +1,6 @@
+[
+ {
+ "key": "foo",
+ "value": "one"
+ }
+]
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/empty.json b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/empty.json
new file mode 100644
index 00000000000..0d4f101c7a3
--- /dev/null
+++ b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/empty.json
@@ -0,0 +1,2 @@
+[
+]
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_all_project_settings_when_component_and_no_key.json b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_all_project_settings_when_component_and_no_key.json
new file mode 100644
index 00000000000..12d2fd7c1a2
--- /dev/null
+++ b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_all_project_settings_when_component_and_no_key.json
@@ -0,0 +1,22 @@
+[
+ {
+ "key": "secret.secured",
+ "value": "password"
+ },
+ {
+ "key": "foo",
+ "value": "one"
+ },
+ {
+ "key": "not_defined",
+ "value": "ABCD"
+ },
+ {
+ "key": "plugin.license.secured",
+ "value": "ABCD"
+ },
+ {
+ "key": "global_not_defined",
+ "value": "ABCD"
+ }
+]
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_all_settings_when_no_component_and_no_key.json b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_all_settings_when_no_component_and_no_key.json
new file mode 100644
index 00000000000..96409e92995
--- /dev/null
+++ b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_all_settings_when_no_component_and_no_key.json
@@ -0,0 +1,18 @@
+[
+ {
+ "key": "secret.secured",
+ "value": "password"
+ },
+ {
+ "key": "foo",
+ "value": "one"
+ },
+ {
+ "key": "not_defined",
+ "value": "ABCD"
+ },
+ {
+ "key": "plugin.license.secured",
+ "value": "ABCD"
+ }
+]
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_default_values.json b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_default_values.json
new file mode 100644
index 00000000000..4647a4e42ba
--- /dev/null
+++ b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_default_values.json
@@ -0,0 +1,6 @@
+[
+ {
+ "key": "foo",
+ "value": "default"
+ }
+]
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_global_values.json b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_global_values.json
new file mode 100644
index 00000000000..0869d171522
--- /dev/null
+++ b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_global_values.json
@@ -0,0 +1,6 @@
+[
+ {
+ "key": "property",
+ "value": "one"
+ }
+]
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_inherited_values_on_global_setting.json b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_inherited_values_on_global_setting.json
new file mode 100644
index 00000000000..815c45955ff
--- /dev/null
+++ b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_inherited_values_on_global_setting.json
@@ -0,0 +1,10 @@
+[
+ {
+ "key": "defaultProperty",
+ "value": "default"
+ },
+ {
+ "key": "globalProperty",
+ "value": "global"
+ }
+]
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_inherited_values_on_module.json b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_inherited_values_on_module.json
new file mode 100644
index 00000000000..15a3ae5fb4c
--- /dev/null
+++ b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_inherited_values_on_module.json
@@ -0,0 +1,18 @@
+[
+ {
+ "key": "defaultProperty",
+ "value": "default"
+ },
+ {
+ "key": "projectProperty",
+ "value": "project"
+ },
+ {
+ "key": "globalProperty",
+ "value": "global"
+ },
+ {
+ "key": "moduleProperty",
+ "value": "module"
+ }
+]
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_license_with_hash_settings_when_authenticated_but_not_admin.json b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_license_with_hash_settings_when_authenticated_but_not_admin.json
new file mode 100644
index 00000000000..e40076cc580
--- /dev/null
+++ b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_license_with_hash_settings_when_authenticated_but_not_admin.json
@@ -0,0 +1,18 @@
+[
+ {
+ "key": "plugin.licenseHash.secured",
+ "value": "987654321"
+ },
+ {
+ "key": "foo",
+ "value": "one"
+ },
+ {
+ "key": "plugin.license.secured",
+ "value": "ABCD"
+ },
+ {
+ "key": "commercial.plugin",
+ "value": "ABCD"
+ }
+]
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_module_values.json b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_module_values.json
new file mode 100644
index 00000000000..5486106db4f
--- /dev/null
+++ b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_module_values.json
@@ -0,0 +1,6 @@
+[
+ {
+ "key": "property",
+ "value": "two"
+ }
+]
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_multi_value_with_coma.json b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_multi_value_with_coma.json
new file mode 100644
index 00000000000..8411a36aea3
--- /dev/null
+++ b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_multi_value_with_coma.json
@@ -0,0 +1,10 @@
+[
+ {
+ "key": "global",
+ "value": "three,four%2Cfive",
+ "values": [
+ "three",
+ "four,five"
+ ]
+ }
+]
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_multi_values.json b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_multi_values.json
new file mode 100644
index 00000000000..ce4fcb99c7f
--- /dev/null
+++ b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_multi_values.json
@@ -0,0 +1,18 @@
+[
+ {
+ "key": "default",
+ "value": "one,two",
+ "values": [
+ "one",
+ "two"
+ ]
+ },
+ {
+ "key": "global",
+ "value": "three,four",
+ "values": [
+ "three",
+ "four"
+ ]
+ }
+]
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_only_one_setting_when_key_is_provided.json b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_only_one_setting_when_key_is_provided.json
new file mode 100644
index 00000000000..d98b4c40613
--- /dev/null
+++ b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_only_one_setting_when_key_is_provided.json
@@ -0,0 +1,6 @@
+[
+ {
+ "key": "foo",
+ "value": "one"
+ }
+]
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_project_values.json b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_project_values.json
new file mode 100644
index 00000000000..5486106db4f
--- /dev/null
+++ b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_project_values.json
@@ -0,0 +1,6 @@
+[
+ {
+ "key": "property",
+ "value": "two"
+ }
+]
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_property_set.json b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_property_set.json
new file mode 100644
index 00000000000..327d187331c
--- /dev/null
+++ b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_property_set.json
@@ -0,0 +1,22 @@
+[
+ {
+ "key": "foo",
+ "value": "1,2",
+ "values": [
+ "1",
+ "2"
+ ]
+ },
+ {
+ "key": "foo.1.key",
+ "value": "key1"
+ },
+ {
+ "key": "foo.2.key",
+ "value": "key2"
+ },
+ {
+ "key": "foo.1.size",
+ "value": "size1"
+ }
+]
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_secured_and_license_settings_in_property_set_when_system_admin.json b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_secured_and_license_settings_in_property_set_when_system_admin.json
new file mode 100644
index 00000000000..3da8aaba675
--- /dev/null
+++ b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_secured_and_license_settings_in_property_set_when_system_admin.json
@@ -0,0 +1,21 @@
+[
+ {
+ "key": "foo",
+ "value": "1",
+ "values": [
+ "1"
+ ]
+ },
+ {
+ "key": "foo.1.key",
+ "value": "key1"
+ },
+ {
+ "key": "foo.1.plugin.license.secured",
+ "value": "ABCD"
+ },
+ {
+ "key": "foo.1.secret.secured",
+ "value": "123456"
+ }
+]
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_secured_and_license_settings_when_project_admin.json b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_secured_and_license_settings_when_project_admin.json
new file mode 100644
index 00000000000..29261a0ea24
--- /dev/null
+++ b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_secured_and_license_settings_when_project_admin.json
@@ -0,0 +1,18 @@
+[
+ {
+ "key": "secret.secured",
+ "value": "password"
+ },
+ {
+ "key": "plugin.licenseHash.secured",
+ "value": "987654321"
+ },
+ {
+ "key": "foo",
+ "value": "one"
+ },
+ {
+ "key": "plugin.license.secured",
+ "value": "ABCD"
+ }
+]
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_secured_and_license_settings_when_system_admin.json b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_secured_and_license_settings_when_system_admin.json
new file mode 100644
index 00000000000..29261a0ea24
--- /dev/null
+++ b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_secured_and_license_settings_when_system_admin.json
@@ -0,0 +1,18 @@
+[
+ {
+ "key": "secret.secured",
+ "value": "password"
+ },
+ {
+ "key": "plugin.licenseHash.secured",
+ "value": "987654321"
+ },
+ {
+ "key": "foo",
+ "value": "one"
+ },
+ {
+ "key": "plugin.license.secured",
+ "value": "ABCD"
+ }
+]
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_simple_value.json b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_simple_value.json
new file mode 100644
index 00000000000..d98b4c40613
--- /dev/null
+++ b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_simple_value.json
@@ -0,0 +1,6 @@
+[
+ {
+ "key": "foo",
+ "value": "one"
+ }
+]
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_values_even_if_no_property_definition.json b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_values_even_if_no_property_definition.json
new file mode 100644
index 00000000000..c3d4ba19dd4
--- /dev/null
+++ b/server/sonar-server/src/test/resources/org/sonar/server/config/ws/IndexActionTest/return_values_even_if_no_property_definition.json
@@ -0,0 +1,6 @@
+[
+ {
+ "key": "globalPropertyWithoutDefinition",
+ "value": "value"
+ }
+]