diff options
author | Julien Lancelot <julien.lancelot@sonarsource.com> | 2016-08-16 17:34:13 +0200 |
---|---|---|
committer | Julien Lancelot <julien.lancelot@sonarsource.com> | 2016-08-18 11:46:41 +0200 |
commit | 3a4fb4b364f2c04411adbb4d26d1952f94d8934e (patch) | |
tree | aa220a38326ae1dc0b699b38c0e1216907a58696 /server | |
parent | cc95453e800ca4b1537e8e1aa9a58fab8c4a1f03 (diff) | |
download | sonarqube-3a4fb4b364f2c04411adbb4d26d1952f94d8934e.tar.gz sonarqube-3a4fb4b364f2c04411adbb4d26d1952f94d8934e.zip |
SONAR-7968 Create /api/settings/list_definitions WS
Diffstat (limited to 'server')
15 files changed, 811 insertions, 8 deletions
diff --git a/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java b/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java index 0af579d220b..84c62415f17 100644 --- a/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java +++ b/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java @@ -113,7 +113,6 @@ import org.sonar.server.plugins.InstalledPluginReferentialFactory; import org.sonar.server.plugins.ServerExtensionInstaller; import org.sonar.server.plugins.privileged.PrivilegedPluginsBootstraper; import org.sonar.server.plugins.privileged.PrivilegedPluginsStopper; -import org.sonar.server.properties.ProjectSettingsFactory; import org.sonar.server.qualityprofile.BuiltInProfiles; import org.sonar.server.qualityprofile.QProfileComparison; import org.sonar.server.qualityprofile.QProfileLookup; @@ -129,6 +128,7 @@ import org.sonar.server.rule.RuleRepositories; import org.sonar.server.rule.index.RuleIndex; import org.sonar.server.rule.index.RuleIndexer; import org.sonar.server.search.EsSearchModule; +import org.sonar.server.settings.ProjectSettingsFactory; import org.sonar.server.startup.LogServerId; import org.sonar.server.test.index.TestIndexer; import org.sonar.server.user.DefaultUserFinder; diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/SettingsRepositoryImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/SettingsRepositoryImpl.java index 19f5f5939f3..ec0829d5983 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/SettingsRepositoryImpl.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/task/projectanalysis/component/SettingsRepositoryImpl.java @@ -22,7 +22,7 @@ package org.sonar.server.computation.task.projectanalysis.component; import java.util.Collection; import java.util.Map; import org.sonar.api.config.Settings; -import org.sonar.server.properties.ProjectSettingsFactory; +import org.sonar.server.settings.ProjectSettingsFactory; import org.sonar.server.util.cache.CacheLoader; import org.sonar.server.util.cache.MemoryCache; diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java index 015abc77720..e92fc98886d 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java @@ -176,7 +176,6 @@ import org.sonar.server.plugins.ws.UninstallAction; import org.sonar.server.plugins.ws.UpdatesAction; import org.sonar.server.project.ws.ProjectsWsModule; import org.sonar.server.projectlink.ws.ProjectLinksModule; -import org.sonar.server.properties.ProjectSettingsFactory; import org.sonar.server.qualitygate.QualityGateModule; import org.sonar.server.qualityprofile.BuiltInProfiles; import org.sonar.server.qualityprofile.QProfileBackuper; @@ -235,6 +234,8 @@ import org.sonar.server.rule.ws.RuleMapper; import org.sonar.server.rule.ws.RuleQueryFactory; import org.sonar.server.rule.ws.RulesWs; import org.sonar.server.rule.ws.TagsAction; +import org.sonar.server.settings.ProjectSettingsFactory; +import org.sonar.server.settings.ws.SettingsWsModule; import org.sonar.server.source.HtmlSourceDecorator; import org.sonar.server.source.SourceService; import org.sonar.server.source.ws.HashAction; @@ -580,8 +581,9 @@ public class PlatformLevel4 extends PlatformLevel { TestIndex.class, TestIndexer.class, - // Properties + // Settings PropertiesWs.class, + SettingsWsModule.class, TypeValidationModule.class, diff --git a/server/sonar-server/src/main/java/org/sonar/server/properties/ProjectSettingsFactory.java b/server/sonar-server/src/main/java/org/sonar/server/settings/ProjectSettingsFactory.java index 5bb613c80c1..fe9c4e60c53 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/properties/ProjectSettingsFactory.java +++ b/server/sonar-server/src/main/java/org/sonar/server/settings/ProjectSettingsFactory.java @@ -17,7 +17,7 @@ * 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.properties; +package org.sonar.server.settings; import java.util.List; import org.sonar.api.ce.ComputeEngineSide; diff --git a/server/sonar-server/src/main/java/org/sonar/server/properties/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/settings/package-info.java index 3bedb52cb00..f24dcdd32dc 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/properties/package-info.java +++ b/server/sonar-server/src/main/java/org/sonar/server/settings/package-info.java @@ -18,6 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ @ParametersAreNonnullByDefault -package org.sonar.server.properties; +package org.sonar.server.settings; import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-server/src/main/java/org/sonar/server/settings/ws/ListDefinitionsAction.java b/server/sonar-server/src/main/java/org/sonar/server/settings/ws/ListDefinitionsAction.java new file mode 100644 index 00000000000..1475d0ab153 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/settings/ws/ListDefinitionsAction.java @@ -0,0 +1,167 @@ +/* + * 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.settings.ws; + +import java.util.List; +import javax.annotation.CheckForNull; +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.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.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.ListDefinitionsWsResponse; + +import static org.elasticsearch.common.Strings.isNullOrEmpty; +import static org.sonar.core.util.Uuids.UUID_EXAMPLE_01; +import static org.sonar.server.ws.WsUtils.writeProtobuf; + +public class ListDefinitionsAction implements SettingsWsAction { + + private static final String PARAM_COMPONENT_ID = "componentId"; + private static final String PARAM_COMPONENT_KEY = "componentKey"; + + private final DbClient dbClient; + private final ComponentFinder componentFinder; + private final UserSession userSession; + private final PropertyDefinitions propertyDefinitions; + + public ListDefinitionsAction(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("list_definitions") + .setDescription(String.format("Returns definitions of properties.<br>" + + "Either '%s' or '%s' could be provided, not both.<br> " + + "Requires one of the following permissions: " + + "<ul>" + + "<li>'Administer System'</li>" + + "<li>'Administer' rights on the specified component</li>" + + "</ul>", PARAM_COMPONENT_ID, PARAM_COMPONENT_KEY)) + .setResponseExample(getClass().getResource("list_definitions-example.json")) + .setSince("6.1") + .setHandler(this); + + action.createParam(PARAM_COMPONENT_ID) + .setDescription("Component id") + .setExampleValue(UUID_EXAMPLE_01); + + action.createParam(PARAM_COMPONENT_KEY) + .setDescription("Component key") + .setExampleValue("my_component_key"); + } + + @Override + public void handle(Request request, Response response) throws Exception { + writeProtobuf(doHandle(request), request, response); + } + + private ListDefinitionsWsResponse doHandle(Request request) { + String qualifier = getQualifier(request); + ListDefinitionsWsResponse.Builder wsResponse = ListDefinitionsWsResponse.newBuilder(); + + propertyDefinitions.getAll().stream() + .filter(definition -> qualifier == null ? definition.global() : definition.qualifiers().contains(qualifier)) + .filter(definition -> !definition.type().equals(PropertyType.LICENSE)) + .forEach(definition -> addDefinition(definition, wsResponse)); + return wsResponse.build(); + } + + private void addDefinition(PropertyDefinition definition, ListDefinitionsWsResponse.Builder wsResponse) { + String key = definition.key(); + Settings.Definition.Builder builder = wsResponse.addDefinitionsBuilder() + .setKey(key) + .setType(Settings.Type.valueOf(definition.type().name())) + .setMultiValues(definition.multiValues()); + String name = definition.name(); + if (!isNullOrEmpty(name)) { + builder.setName(name); + } + String description = definition.description(); + if (!isNullOrEmpty(description)) { + builder.setDescription(description); + } + String category = propertyDefinitions.getCategory(key); + if (!isNullOrEmpty(category)) { + builder.setCategory(category); + } + String subCategory = propertyDefinitions.getSubCategory(key); + if (!isNullOrEmpty(subCategory)) { + builder.setSubCategory(subCategory); + } + String defaultValue = definition.defaultValue(); + if (!isNullOrEmpty(defaultValue)) { + builder.setDefaultValue(defaultValue); + } + List<String> options = definition.options(); + if (!options.isEmpty()) { + builder.addAllOptions(options); + } + List<PropertyFieldDefinition> fields = definition.fields(); + if (!fields.isEmpty()) { + fields.stream() + .filter(fieldDefinition -> !fieldDefinition.type().equals(PropertyType.LICENSE)) + .forEach(fieldDefinition -> addField(fieldDefinition, builder)); + } + } + + private static void addField(PropertyFieldDefinition fieldDefinition, Settings.Definition.Builder builder) { + builder.addFieldsBuilder() + .setKey(fieldDefinition.key()) + .setName(fieldDefinition.name()) + .setType(Settings.Type.valueOf(fieldDefinition.type().name())) + .setIndicativeSize(fieldDefinition.indicativeSize()) + .addAllOptions(fieldDefinition.options()) + .build(); + } + + @CheckForNull + private String getQualifier(Request request) { + DbSession dbSession = dbClient.openSession(false); + try { + if (request.hasParam(PARAM_COMPONENT_ID) || request.hasParam(PARAM_COMPONENT_KEY)) { + ComponentDto component = componentFinder.getByUuidOrKey(dbSession, request.param(PARAM_COMPONENT_ID), request.param(PARAM_COMPONENT_KEY), + ComponentFinder.ParamNames.ID_AND_KEY); + userSession.checkComponentUuidPermission(UserRole.ADMIN, component.uuid()); + return component.qualifier(); + } else { + userSession.checkPermission(GlobalPermissions.SYSTEM_ADMIN); + return null; + } + } finally { + dbClient.closeSession(dbSession); + } + } + +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/settings/ws/SettingsWs.java b/server/sonar-server/src/main/java/org/sonar/server/settings/ws/SettingsWs.java new file mode 100644 index 00000000000..6ed340e0884 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/settings/ws/SettingsWs.java @@ -0,0 +1,42 @@ +/* + * 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.settings.ws; + +import org.sonar.api.server.ws.WebService; + +public class SettingsWs implements WebService { + + private final SettingsWsAction[] actions; + + public SettingsWs(SettingsWsAction... actions) { + this.actions = actions; + } + + @Override + public void define(Context context) { + NewController controller = context.createController("api/settings") + .setDescription("Manage settings.") + .setSince("6.1"); + for (SettingsWsAction action : actions) { + action.define(controller); + } + controller.done(); + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/settings/ws/SettingsWsAction.java b/server/sonar-server/src/main/java/org/sonar/server/settings/ws/SettingsWsAction.java new file mode 100644 index 00000000000..63b8724eded --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/settings/ws/SettingsWsAction.java @@ -0,0 +1,26 @@ +/* + * 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.settings.ws; + +import org.sonar.server.ws.WsAction; + +public interface SettingsWsAction extends WsAction { + // marker interface +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/settings/ws/SettingsWsModule.java b/server/sonar-server/src/main/java/org/sonar/server/settings/ws/SettingsWsModule.java new file mode 100644 index 00000000000..fb0e42953f7 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/settings/ws/SettingsWsModule.java @@ -0,0 +1,31 @@ +/* + * 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.settings.ws; + +import org.sonar.core.platform.Module; + +public class SettingsWsModule extends Module { + @Override + protected void configureModule() { + add( + SettingsWs.class, + ListDefinitionsAction.class); + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/settings/ws/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/settings/ws/package-info.java new file mode 100644 index 00000000000..c144acaebf8 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/settings/ws/package-info.java @@ -0,0 +1,23 @@ +/* + * 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. + */ +@ParametersAreNonnullByDefault +package org.sonar.server.settings.ws; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-server/src/main/resources/org/sonar/server/settings/ws/list_definitions-example.json b/server/sonar-server/src/main/resources/org/sonar/server/settings/ws/list_definitions-example.json new file mode 100644 index 00000000000..79b4e317ebd --- /dev/null +++ b/server/sonar-server/src/main/resources/org/sonar/server/settings/ws/list_definitions-example.json @@ -0,0 +1,70 @@ +{ + "definitions": [ + { + "key": "sonar.string", + "name": "String", + "description": "String property", + "type": "STRING", + "category": "general", + "subCategory": "test", + "multiValues": false, + "defaultValue": "123", + "options": [], + "fields": [] + }, + { + "key": "sonar.list", + "name": "List", + "description": "List property", + "type": "SINGLE_SELECT_LIST", + "category": "general", + "subCategory": "general", + "multiValues": false, + "options": [ + "a", + "b" + ], + "fields": [] + }, + { + "key": "sonar.multiValues", + "name": "Multi values", + "description": "Multi values property", + "type": "STRING", + "category": "general", + "subCategory": "general", + "multiValues": true, + "options": [], + "fields": [] + }, + { + "key": "sonar.propertySet", + "name": "Property Set", + "description": "Property Set property", + "type": "PROPERTY_SET", + "category": "property", + "subCategory": "set", + "multiValues": false, + "options": [], + "fields": [ + { + "key": "text", + "name": "Text", + "type": "TEXT", + "indicativeSize": 10, + "options": [] + }, + { + "key": "list", + "name": "List", + "type": "SINGLE_SELECT_LIST", + "indicativeSize": 20, + "options": [ + "value1", + "value2" + ] + } + ] + } + ] +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/SettingsRepositoryTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/SettingsRepositoryTest.java index 173cebac3dc..7ac0c490f36 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/SettingsRepositoryTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/task/projectanalysis/component/SettingsRepositoryTest.java @@ -32,7 +32,7 @@ import org.sonar.db.component.ComponentDto; import org.sonar.db.component.ComponentTesting; import org.sonar.db.property.PropertiesDao; import org.sonar.db.property.PropertyDto; -import org.sonar.server.properties.ProjectSettingsFactory; +import org.sonar.server.settings.ProjectSettingsFactory; import static org.assertj.core.api.Assertions.assertThat; import static org.sonar.server.computation.task.projectanalysis.component.Component.Type.PROJECT; diff --git a/server/sonar-server/src/test/java/org/sonar/server/properties/ProjectSettingsFactoryTest.java b/server/sonar-server/src/test/java/org/sonar/server/settings/ProjectSettingsFactoryTest.java index 30dc66bb638..7f6fed937eb 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/properties/ProjectSettingsFactoryTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/settings/ProjectSettingsFactoryTest.java @@ -17,7 +17,7 @@ * 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.properties; +package org.sonar.server.settings; import org.junit.Test; import org.sonar.api.config.Settings; diff --git a/server/sonar-server/src/test/java/org/sonar/server/settings/ws/ListDefinitionsActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/settings/ws/ListDefinitionsActionTest.java new file mode 100644 index 00000000000..2365b157c6b --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/settings/ws/ListDefinitionsActionTest.java @@ -0,0 +1,408 @@ +/* + * 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.settings.ws; + +import java.io.IOException; +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.server.component.ComponentFinder; +import org.sonar.server.exceptions.ForbiddenException; +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.Settings; +import org.sonarqube.ws.Settings.ListDefinitionsWsResponse; + +import static java.util.Arrays.asList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.sonar.api.resources.Qualifiers.MODULE; +import static org.sonar.api.resources.Qualifiers.PROJECT; +import static org.sonar.api.web.UserRole.ADMIN; +import static org.sonar.api.web.UserRole.USER; +import static org.sonar.core.permission.GlobalPermissions.DASHBOARD_SHARING; +import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN; +import static org.sonar.db.component.ComponentTesting.newProjectDto; +import static org.sonarqube.ws.Settings.Type.BOOLEAN; +import static org.sonarqube.ws.Settings.Type.PROPERTY_SET; +import static org.sonarqube.ws.Settings.Type.SINGLE_SELECT_LIST; +import static org.sonarqube.ws.Settings.Type.STRING; +import static org.sonarqube.ws.Settings.Type.TEXT; + +public class ListDefinitionsActionTest { + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Rule + public UserSessionRule userSession = UserSessionRule.standalone(); + + @Rule + public DbTester db = DbTester.create(System2.INSTANCE); + + DbClient dbClient = db.getDbClient(); + ComponentDbTester componentDb = new ComponentDbTester(db); + + ComponentDto project; + + PropertyDefinitions propertyDefinitions = new PropertyDefinitions(); + + WsActionTester ws = new WsActionTester(new ListDefinitionsAction(dbClient, new ComponentFinder(dbClient), userSession, propertyDefinitions)); + + @Before + public void setUp() throws Exception { + project = insertProject(); + } + + @Test + public void return_settings_definitions() { + setUserAsSystemAdmin(); + propertyDefinitions.addComponent(PropertyDefinition + .builder("foo") + .name("Foo") + .description("desc") + .category("cat") + .subCategory("subCat") + .type(PropertyType.TEXT) + .defaultValue("default") + .multiValues(true) + .build()); + + ListDefinitionsWsResponse result = newRequest(); + assertThat(result.getDefinitionsList()).hasSize(1); + + Settings.Definition definition = result.getDefinitions(0); + assertThat(definition.getKey()).isEqualTo("foo"); + assertThat(definition.getName()).isEqualTo("Foo"); + assertThat(definition.getDescription()).isEqualTo("desc"); + assertThat(definition.getCategory()).isEqualTo("cat"); + assertThat(definition.getSubCategory()).isEqualTo("subCat"); + assertThat(definition.getType()).isEqualTo(TEXT); + assertThat(definition.getDefaultValue()).isEqualTo("default"); + assertThat(definition.getMultiValues()).isTrue(); + } + + @Test + public void return_settings_definitions_with_minimum_fields() { + setUserAsSystemAdmin(); + propertyDefinitions.addComponent(PropertyDefinition + .builder("foo") + .build()); + + ListDefinitionsWsResponse result = newRequest(); + assertThat(result.getDefinitionsList()).hasSize(1); + + Settings.Definition definition = result.getDefinitions(0); + assertThat(definition.getKey()).isEqualTo("foo"); + assertThat(definition.getType()).isEqualTo(STRING); + assertThat(definition.hasName()).isFalse(); + assertThat(definition.hasCategory()).isFalse(); + assertThat(definition.hasSubCategory()).isFalse(); + assertThat(definition.hasDefaultValue()).isFalse(); + assertThat(definition.getMultiValues()).isFalse(); + assertThat(definition.getOptionsCount()).isZero(); + assertThat(definition.getFieldsCount()).isZero(); + } + + @Test + public void return_default_category() throws Exception { + setUserAsSystemAdmin(); + propertyDefinitions.addComponent(PropertyDefinition.builder("foo").build(), "default"); + propertyDefinitions.addComponent(PropertyDefinition.builder("foo").category("").build(), "default"); + + ListDefinitionsWsResponse result = newRequest(); + assertThat(result.getDefinitionsList()).hasSize(1); + assertThat(result.getDefinitions(0).getCategory()).isEqualTo("default"); + assertThat(result.getDefinitions(0).getSubCategory()).isEqualTo("default"); + } + + @Test + public void return_single_select_list_property() throws Exception { + setUserAsSystemAdmin(); + propertyDefinitions.addComponent(PropertyDefinition + .builder("foo") + .type(PropertyType.SINGLE_SELECT_LIST) + .options("one", "two") + .build()); + + ListDefinitionsWsResponse result = newRequest(); + assertThat(result.getDefinitionsList()).hasSize(1); + + Settings.Definition definition = result.getDefinitions(0); + assertThat(definition.getType()).isEqualTo(SINGLE_SELECT_LIST); + assertThat(definition.getOptionsList()).containsExactly("one", "two"); + } + + @Test + public void return_property_set() throws Exception { + setUserAsSystemAdmin(); + propertyDefinitions.addComponent(PropertyDefinition + .builder("foo") + .type(PropertyType.PROPERTY_SET) + .fields( + PropertyFieldDefinition.build("boolean").name("Boolean").type(PropertyType.BOOLEAN).indicativeSize(15).build(), + PropertyFieldDefinition.build("list").name("List").type(PropertyType.SINGLE_SELECT_LIST).options("one", "two").build()) + .build()); + + ListDefinitionsWsResponse result = newRequest(); + assertThat(result.getDefinitionsList()).hasSize(1); + + Settings.Definition definition = result.getDefinitions(0); + assertThat(definition.getType()).isEqualTo(PROPERTY_SET); + assertThat(definition.getFieldsList()).hasSize(2); + + assertThat(definition.getFields(0).getKey()).isEqualTo("boolean"); + assertThat(definition.getFields(0).getName()).isEqualTo("Boolean"); + assertThat(definition.getFields(0).getType()).isEqualTo(BOOLEAN); + assertThat(definition.getFields(0).getOptionsCount()).isZero(); + assertThat(definition.getFields(0).getIndicativeSize()).isEqualTo(15); + + assertThat(definition.getFields(1).getKey()).isEqualTo("list"); + assertThat(definition.getFields(1).getName()).isEqualTo("List"); + assertThat(definition.getFields(1).getType()).isEqualTo(SINGLE_SELECT_LIST); + assertThat(definition.getFields(1).getOptionsList()).containsExactly("one", "two"); + // 20 is the default value + assertThat(definition.getFields(1).getIndicativeSize()).isEqualTo(20); + } + + @Test + public void does_not_return_license_type_property_set() throws Exception { + setUserAsSystemAdmin(); + propertyDefinitions.addComponent(PropertyDefinition + .builder("foo") + .type(PropertyType.PROPERTY_SET) + .fields(PropertyFieldDefinition.build("license").name("License").type(PropertyType.LICENSE).build()) + .build()); + + ListDefinitionsWsResponse result = newRequest(); + assertThat(result.getDefinitionsList()).hasSize(1); + assertThat(result.getDefinitions(0).getFieldsList()).isEmpty(); + } + + @Test + public void return_global_settings_definitions() { + setUserAsSystemAdmin(); + propertyDefinitions.addComponent(PropertyDefinition.builder("foo").build()); + + ListDefinitionsWsResponse result = newRequest(); + assertThat(result.getDefinitionsList()).hasSize(1); + } + + @Test + public void return_project_settings_def_by_project_key() { + setUserAsProjectAdmin(); + propertyDefinitions.addComponent(PropertyDefinition + .builder("foo") + .onQualifiers(PROJECT) + .build()); + + ListDefinitionsWsResponse result = newRequest(null, project.key()); + assertThat(result.getDefinitionsList()).hasSize(1); + } + + @Test + public void return_project_settings_def_by_project_id() { + setUserAsProjectAdmin(); + propertyDefinitions.addComponent(PropertyDefinition + .builder("foo") + .onQualifiers(PROJECT) + .build()); + + ListDefinitionsWsResponse result = newRequest(project.uuid(), null); + assertThat(result.getDefinitionsList()).hasSize(1); + } + + @Test + public void return_only_global_properties_when_no_component_parameter() throws Exception { + setUserAsSystemAdmin(); + propertyDefinitions.addComponents(asList( + PropertyDefinition.builder("global").build(), + PropertyDefinition.builder("global-and-project").onQualifiers(PROJECT).build(), + PropertyDefinition.builder("only-on-project").onlyOnQualifiers(PROJECT).build(), + PropertyDefinition.builder("only-on-module").onlyOnQualifiers(MODULE).build())); + + ListDefinitionsWsResponse result = newRequest(); + assertThat(result.getDefinitionsList()).extracting("key").containsOnly("global", "global-and-project"); + } + + @Test + public void return_only_properties_available_for_component_qualifier() throws Exception { + setUserAsProjectAdmin(); + propertyDefinitions.addComponents(asList( + PropertyDefinition.builder("global").build(), + PropertyDefinition.builder("global-and-project").onQualifiers(PROJECT).build(), + PropertyDefinition.builder("only-on-project").onlyOnQualifiers(PROJECT).build(), + PropertyDefinition.builder("only-on-module").onlyOnQualifiers(MODULE).build())); + + ListDefinitionsWsResponse result = newRequest(project.uuid(), null); + assertThat(result.getDefinitionsList()).extracting("key").containsOnly("global-and-project", "only-on-project"); + } + + @Test + public void does_not_return_hidden_properties() throws Exception { + setUserAsSystemAdmin(); + propertyDefinitions.addComponent(PropertyDefinition.builder("foo").hidden().build()); + + ListDefinitionsWsResponse result = newRequest(); + assertThat(result.getDefinitionsList()).isEmpty(); + } + + @Test + public void does_not_return_license_type() throws Exception { + setUserAsSystemAdmin(); + propertyDefinitions.addComponent(PropertyDefinition.builder("license").type(PropertyType.LICENSE).build()); + + ListDefinitionsWsResponse result = newRequest(); + assertThat(result.getDefinitionsList()).isEmpty(); + } + + @Test + public void fail_when_id_and_key_are_set() throws Exception { + setUserAsProjectAdmin(); + + expectedException.expect(IllegalArgumentException.class); + newRequest(project.uuid(), project.key()); + } + + @Test + public void fail_when_not_system_admin() throws Exception { + userSession.login("not-admin").setGlobalPermissions(DASHBOARD_SHARING); + propertyDefinitions.addComponent(PropertyDefinition.builder("foo").build()); + + expectedException.expect(ForbiddenException.class); + newRequest(); + } + + @Test + public void fail_when_not_project_admin() throws Exception { + userSession.login("project-admin").addProjectUuidPermissions(USER, project.uuid()); + propertyDefinitions.addComponent(PropertyDefinition.builder("foo").build()); + + expectedException.expect(ForbiddenException.class); + newRequest(project.uuid(), null); + } + + @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(2); + } + + @Test + public void test_example_json_response() { + setUserAsSystemAdmin(); + propertyDefinitions.addComponents(asList( + PropertyDefinition.builder("sonar.string") + .name("String") + .description("String property") + .type(PropertyType.STRING) + .category("general") + .subCategory("test") + .defaultValue("123") + .build(), + PropertyDefinition.builder("sonar.list") + .name("List") + .description("List property") + .type(PropertyType.SINGLE_SELECT_LIST) + .category("general") + .options("a", "b") + .build(), + PropertyDefinition.builder("sonar.multiValues") + .name("Multi values") + .description("Multi values property") + .type(PropertyType.STRING) + .category("general") + .multiValues(true) + .build(), + PropertyDefinition.builder("sonar.propertySet") + .name("Property Set") + .description("Property Set property") + .type(PropertyType.PROPERTY_SET) + .category("property") + .subCategory("set") + .fields( + PropertyFieldDefinition.build("text") + .name("Text") + .type(PropertyType.TEXT) + .indicativeSize(10) + .build(), + PropertyFieldDefinition.build("list") + .name("List") + .type(PropertyType.SINGLE_SELECT_LIST) + .options("value1", "value2") + .build()) + .build())); + + String result = ws.newRequest().setMediaType(MediaTypes.JSON).execute().getInput(); + JsonAssert.assertJson(ws.getDef().responseExampleAsString()).isSimilarTo(result); + } + + private ComponentDto insertProject() { + return componentDb.insertComponent(newProjectDto()); + } + + private ListDefinitionsWsResponse newRequest() { + return newRequest(null, null); + } + + private ListDefinitionsWsResponse newRequest(@Nullable String id, @Nullable String key) { + TestRequest request = ws.newRequest() + .setMediaType(MediaTypes.PROTOBUF); + if (id != null) { + request.setParam("componentId", id); + } + if (key != null) { + request.setParam("componentKey", key); + } + try { + return ListDefinitionsWsResponse.parseFrom(request.execute().getInputStream()); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + private void setUserAsSystemAdmin() { + userSession.login("admin").setGlobalPermissions(SYSTEM_ADMIN); + } + + private void setUserAsProjectAdmin() { + userSession.login("project-admin").addProjectUuidPermissions(ADMIN, project.uuid()); + } + +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/settings/ws/SettingsWsModuleTest.java b/server/sonar-server/src/test/java/org/sonar/server/settings/ws/SettingsWsModuleTest.java new file mode 100644 index 00000000000..e37e98e1523 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/settings/ws/SettingsWsModuleTest.java @@ -0,0 +1,34 @@ +/* + * 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.settings.ws; + +import org.junit.Test; +import org.sonar.core.platform.ComponentContainer; + +import static org.assertj.core.api.Assertions.assertThat; + +public class SettingsWsModuleTest { + @Test + public void verify_count_of_added_components() { + ComponentContainer container = new ComponentContainer(); + new SettingsWsModule().configure(container); + assertThat(container.size()).isEqualTo(2 + 2); + } +} |