3 * Copyright (C) 2009-2021 SonarSource SA
4 * mailto:info AT sonarsource DOT com
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 3 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 package org.sonar.server.setting.ws;
22 import javax.annotation.Nullable;
23 import org.junit.Before;
24 import org.junit.Rule;
25 import org.junit.Test;
26 import org.junit.rules.ExpectedException;
27 import org.sonar.api.PropertyType;
28 import org.sonar.api.config.PropertyDefinition;
29 import org.sonar.api.config.PropertyDefinitions;
30 import org.sonar.api.config.PropertyFieldDefinition;
31 import org.sonar.api.server.ws.WebService;
32 import org.sonar.api.server.ws.WebService.Param;
33 import org.sonar.api.utils.System2;
34 import org.sonar.db.DbClient;
35 import org.sonar.db.DbTester;
36 import org.sonar.db.component.ComponentDbTester;
37 import org.sonar.db.component.ComponentDto;
38 import org.sonar.db.component.ComponentTesting;
39 import org.sonar.server.component.TestComponentFinder;
40 import org.sonar.server.exceptions.ForbiddenException;
41 import org.sonar.server.exceptions.NotFoundException;
42 import org.sonar.server.tester.UserSessionRule;
43 import org.sonar.server.ws.TestRequest;
44 import org.sonar.server.ws.WsActionTester;
45 import org.sonar.test.JsonAssert;
46 import org.sonarqube.ws.Settings;
47 import org.sonarqube.ws.Settings.Definition;
48 import org.sonarqube.ws.Settings.ListDefinitionsWsResponse;
50 import static java.util.Arrays.asList;
51 import static org.assertj.core.api.Assertions.assertThat;
52 import static org.assertj.core.groups.Tuple.tuple;
53 import static org.sonar.api.resources.Qualifiers.MODULE;
54 import static org.sonar.api.resources.Qualifiers.PROJECT;
55 import static org.sonar.api.web.UserRole.ADMIN;
56 import static org.sonar.api.web.UserRole.CODEVIEWER;
57 import static org.sonar.api.web.UserRole.USER;
58 import static org.sonar.db.permission.GlobalPermission.ADMINISTER;
59 import static org.sonar.db.permission.GlobalPermission.SCAN;
60 import static org.sonarqube.ws.MediaTypes.JSON;
61 import static org.sonarqube.ws.Settings.Definition.CategoryOneOfCase.CATEGORYONEOF_NOT_SET;
62 import static org.sonarqube.ws.Settings.Definition.DefaultValueOneOfCase.DEFAULTVALUEONEOF_NOT_SET;
63 import static org.sonarqube.ws.Settings.Definition.DeprecatedKeyOneOfCase.DEPRECATEDKEYONEOF_NOT_SET;
64 import static org.sonarqube.ws.Settings.Definition.NameOneOfCase.NAMEONEOF_NOT_SET;
65 import static org.sonarqube.ws.Settings.Definition.SubCategoryOneOfCase.SUBCATEGORYONEOF_NOT_SET;
66 import static org.sonarqube.ws.Settings.Type.BOOLEAN;
67 import static org.sonarqube.ws.Settings.Type.LICENSE;
68 import static org.sonarqube.ws.Settings.Type.PROPERTY_SET;
69 import static org.sonarqube.ws.Settings.Type.SINGLE_SELECT_LIST;
70 import static org.sonarqube.ws.Settings.Type.STRING;
71 import static org.sonarqube.ws.Settings.Type.TEXT;
73 public class ListDefinitionsActionTest {
76 public ExpectedException expectedException = ExpectedException.none();
78 public UserSessionRule userSession = UserSessionRule.standalone();
80 public DbTester db = DbTester.create(System2.INSTANCE);
82 private DbClient dbClient = db.getDbClient();
83 private ComponentDbTester componentDb = new ComponentDbTester(db);
84 private ComponentDto project;
85 private PropertyDefinitions propertyDefinitions = new PropertyDefinitions(System2.INSTANCE);
86 private SettingsWsSupport support = new SettingsWsSupport(userSession);
87 private WsActionTester ws = new WsActionTester(
88 new ListDefinitionsAction(dbClient, TestComponentFinder.from(db), userSession, propertyDefinitions, support));
92 project = componentDb.insertComponent(ComponentTesting.newPrivateProjectDto());
96 public void return_settings_definitions() {
98 propertyDefinitions.addComponent(PropertyDefinition
103 .subCategory("subCat")
104 .type(PropertyType.TEXT)
105 .defaultValue("default")
109 ListDefinitionsWsResponse result = executeRequest();
111 assertThat(result.getDefinitionsList()).hasSize(1);
112 Definition definition = result.getDefinitions(0);
113 assertThat(definition.getKey()).isEqualTo("foo");
114 assertThat(definition.getName()).isEqualTo("Foo");
115 assertThat(definition.getDescription()).isEqualTo("desc");
116 assertThat(definition.getCategory()).isEqualTo("cat");
117 assertThat(definition.getSubCategory()).isEqualTo("subCat");
118 assertThat(definition.getType()).isEqualTo(TEXT);
119 assertThat(definition.getDefaultValue()).isEqualTo("default");
120 assertThat(definition.getMultiValues()).isTrue();
124 public void return_settings_definitions_with_minimum_fields() {
126 propertyDefinitions.addComponent(PropertyDefinition
130 ListDefinitionsWsResponse result = executeRequest();
132 assertThat(result.getDefinitionsList()).hasSize(1);
133 Definition definition = result.getDefinitions(0);
134 assertThat(definition.getKey()).isEqualTo("foo");
135 assertThat(definition.getType()).isEqualTo(STRING);
136 assertThat(definition.getNameOneOfCase()).isEqualTo(NAMEONEOF_NOT_SET);
137 assertThat(definition.getCategoryOneOfCase()).isEqualTo(CATEGORYONEOF_NOT_SET);
138 assertThat(definition.getSubCategoryOneOfCase()).isEqualTo(SUBCATEGORYONEOF_NOT_SET);
139 assertThat(definition.getDefaultValueOneOfCase()).isEqualTo(DEFAULTVALUEONEOF_NOT_SET);
140 assertThat(definition.getMultiValues()).isFalse();
141 assertThat(definition.getOptionsCount()).isZero();
142 assertThat(definition.getFieldsCount()).isZero();
143 assertThat(definition.getDeprecatedKeyOneOfCase()).isEqualTo(DEPRECATEDKEYONEOF_NOT_SET);
147 public void return_settings_definitions_with_deprecated_key() {
149 propertyDefinitions.addComponent(PropertyDefinition
152 .deprecatedKey("deprecated")
155 ListDefinitionsWsResponse result = executeRequest();
157 assertThat(result.getDefinitionsList()).hasSize(1);
158 Definition definition = result.getDefinitions(0);
159 assertThat(definition.getKey()).isEqualTo("foo");
160 assertThat(definition.getName()).isEqualTo("Foo");
161 assertThat(definition.getDeprecatedKey()).isEqualTo("deprecated");
165 public void return_default_category() {
167 propertyDefinitions.addComponent(PropertyDefinition.builder("foo").build(), "default");
168 propertyDefinitions.addComponent(PropertyDefinition.builder("foo").category("").build(), "default");
170 ListDefinitionsWsResponse result = executeRequest();
172 assertThat(result.getDefinitionsList()).hasSize(1);
173 assertThat(result.getDefinitions(0).getCategory()).isEqualTo("default");
174 assertThat(result.getDefinitions(0).getSubCategory()).isEqualTo("default");
178 public void return_single_select_list_property() {
180 propertyDefinitions.addComponent(PropertyDefinition
182 .type(PropertyType.SINGLE_SELECT_LIST)
183 .options("one", "two")
186 ListDefinitionsWsResponse result = executeRequest();
188 assertThat(result.getDefinitionsList()).hasSize(1);
189 Definition definition = result.getDefinitions(0);
190 assertThat(definition.getType()).isEqualTo(SINGLE_SELECT_LIST);
191 assertThat(definition.getOptionsList()).containsExactly("one", "two");
195 public void return_property_set() {
197 propertyDefinitions.addComponent(PropertyDefinition
199 .type(PropertyType.PROPERTY_SET)
201 PropertyFieldDefinition.build("boolean").name("Boolean").description("boolean desc").type(PropertyType.BOOLEAN).build(),
202 PropertyFieldDefinition.build("list").name("List").description("list desc").type(PropertyType.SINGLE_SELECT_LIST).options("one", "two").build())
205 ListDefinitionsWsResponse result = executeRequest();
207 assertThat(result.getDefinitionsList()).hasSize(1);
208 Definition definition = result.getDefinitions(0);
209 assertThat(definition.getType()).isEqualTo(PROPERTY_SET);
210 assertThat(definition.getFieldsList()).hasSize(2);
212 assertThat(definition.getFields(0).getKey()).isEqualTo("boolean");
213 assertThat(definition.getFields(0).getName()).isEqualTo("Boolean");
214 assertThat(definition.getFields(0).getDescription()).isEqualTo("boolean desc");
215 assertThat(definition.getFields(0).getType()).isEqualTo(BOOLEAN);
216 assertThat(definition.getFields(0).getOptionsCount()).isZero();
218 assertThat(definition.getFields(1).getKey()).isEqualTo("list");
219 assertThat(definition.getFields(1).getName()).isEqualTo("List");
220 assertThat(definition.getFields(1).getDescription()).isEqualTo("list desc");
221 assertThat(definition.getFields(1).getType()).isEqualTo(SINGLE_SELECT_LIST);
222 assertThat(definition.getFields(1).getOptionsList()).containsExactly("one", "two");
226 public void return_license_type_in_property_set() {
228 propertyDefinitions.addComponent(PropertyDefinition
230 .type(PropertyType.PROPERTY_SET)
231 .fields(PropertyFieldDefinition.build("license").name("License").type(PropertyType.LICENSE).build())
234 ListDefinitionsWsResponse result = executeRequest();
236 assertThat(result.getDefinitionsList()).hasSize(1);
237 assertThat(result.getDefinitions(0).getFieldsList()).extracting(Settings.Field::getKey, Settings.Field::getType).containsOnly(tuple("license", LICENSE));
241 public void return_global_settings_definitions() {
243 propertyDefinitions.addComponent(PropertyDefinition.builder("foo").build());
245 ListDefinitionsWsResponse result = executeRequest();
247 assertThat(result.getDefinitionsList()).hasSize(1);
251 public void definitions_are_ordered_by_category_then_index_then_name_case_insensitive() {
253 propertyDefinitions.addComponent(PropertyDefinition.builder("sonar.prop.11").category("cat-1").index(1).name("prop 1").build());
254 propertyDefinitions.addComponent(PropertyDefinition.builder("sonar.prop.12").category("cat-1").index(2).name("prop 2").build());
255 propertyDefinitions.addComponent(PropertyDefinition.builder("sonar.prop.13").category("CAT-1").index(1).name("prop 3").build());
256 propertyDefinitions.addComponent(PropertyDefinition.builder("sonar.prop.41").category("cat-0").index(25).name("prop 1").build());
258 ListDefinitionsWsResponse result = executeRequest();
260 assertThat(result.getDefinitionsList()).extracting(Definition::getKey)
261 .containsExactly("sonar.prop.41", "sonar.prop.11", "sonar.prop.13", "sonar.prop.12");
265 public void return_project_settings_def_by_project_key() {
266 logInAsProjectUser();
267 propertyDefinitions.addComponent(PropertyDefinition
269 .onQualifiers(PROJECT)
272 ListDefinitionsWsResponse result = executeRequest(project.getDbKey());
274 assertThat(result.getDefinitionsList()).hasSize(1);
278 public void return_only_global_properties_when_no_component_parameter() {
279 logInAsProjectUser();
280 propertyDefinitions.addComponents(asList(
281 PropertyDefinition.builder("global").build(),
282 PropertyDefinition.builder("global-and-project").onQualifiers(PROJECT).build(),
283 PropertyDefinition.builder("only-on-project").onlyOnQualifiers(PROJECT).build(),
284 PropertyDefinition.builder("only-on-module").onlyOnQualifiers(MODULE).build()));
286 ListDefinitionsWsResponse result = executeRequest();
288 assertThat(result.getDefinitionsList()).extracting("key").containsOnly("global", "global-and-project");
292 public void return_only_properties_available_for_component_qualifier() {
293 logInAsProjectUser();
294 propertyDefinitions.addComponents(asList(
295 PropertyDefinition.builder("global").build(),
296 PropertyDefinition.builder("global-and-project").onQualifiers(PROJECT).build(),
297 PropertyDefinition.builder("only-on-project").onlyOnQualifiers(PROJECT).build(),
298 PropertyDefinition.builder("only-on-module").onlyOnQualifiers(MODULE).build()));
300 ListDefinitionsWsResponse result = executeRequest(project.getDbKey());
302 assertThat(result.getDefinitionsList()).extracting("key").containsOnly("global-and-project", "only-on-project");
306 public void does_not_return_hidden_properties() {
308 propertyDefinitions.addComponent(PropertyDefinition.builder("foo").hidden().build());
310 ListDefinitionsWsResponse result = executeRequest();
312 assertThat(result.getDefinitionsList()).isEmpty();
316 public void return_license_type() {
318 propertyDefinitions.addComponents(asList(
319 PropertyDefinition.builder("plugin.license.secured").type(PropertyType.LICENSE).build(),
320 PropertyDefinition.builder("commercial.plugin").type(PropertyType.LICENSE).build()));
322 ListDefinitionsWsResponse result = executeRequest();
324 assertThat(result.getDefinitionsList()).extracting(Definition::getKey, Definition::getType)
325 .containsOnly(tuple("plugin.license.secured", LICENSE), tuple("commercial.plugin", LICENSE));
329 public void does_not_returned_secured_and_license_settings_when_not_authenticated() {
330 propertyDefinitions.addComponents(asList(
331 PropertyDefinition.builder("foo").build(),
332 PropertyDefinition.builder("secret.secured").build()));
334 ListDefinitionsWsResponse result = executeRequest();
336 assertThat(result.getDefinitionsList()).extracting(Definition::getKey).containsOnly("foo");
340 public void return_secured_settings_when_not_authenticated_but_with_scan_permission() {
341 userSession.anonymous().addPermission(SCAN);
342 propertyDefinitions.addComponents(asList(
343 PropertyDefinition.builder("foo").build(),
344 PropertyDefinition.builder("secret.secured").build()));
346 ListDefinitionsWsResponse result = executeRequest();
348 assertThat(result.getDefinitionsList()).extracting(Definition::getKey).containsOnly("foo", "secret.secured");
352 public void return_secured_settings_when_system_admin() {
354 propertyDefinitions.addComponents(asList(
355 PropertyDefinition.builder("foo").build(),
356 PropertyDefinition.builder("secret.secured").build()));
358 ListDefinitionsWsResponse result = executeRequest();
360 assertThat(result.getDefinitionsList()).extracting(Definition::getKey).containsOnly("foo", "secret.secured");
364 public void return_secured_settings_when_project_admin() {
365 logInAsProjectAdmin();
366 propertyDefinitions.addComponents(asList(
367 PropertyDefinition.builder("foo").onQualifiers(PROJECT).build(),
368 PropertyDefinition.builder("secret.secured").onQualifiers(PROJECT).build()));
370 ListDefinitionsWsResponse result = executeRequest(project.getDbKey());
372 assertThat(result.getDefinitionsList()).extracting(Definition::getKey).containsOnly("foo", "secret.secured");
376 public void fail_when_user_has_not_project_browse_permission() {
377 userSession.logIn("project-admin").addProjectPermission(CODEVIEWER, project);
378 propertyDefinitions.addComponent(PropertyDefinition.builder("foo").build());
380 expectedException.expect(ForbiddenException.class);
382 executeRequest(project.getDbKey());
386 public void fail_when_component_not_found() {
387 expectedException.expect(NotFoundException.class);
388 expectedException.expectMessage("Component key 'unknown' not found");
391 .setParam("component", "unknown")
396 public void test_ws_definition() {
397 WebService.Action action = ws.getDef();
398 assertThat(action).isNotNull();
399 assertThat(action.isInternal()).isFalse();
400 assertThat(action.isPost()).isFalse();
401 assertThat(action.responseExampleAsString()).isNotEmpty();
402 assertThat(action.params()).extracting(Param::key).containsExactlyInAnyOrder("component");
406 public void test_example_json_response() {
407 logInAsProjectAdmin();
408 propertyDefinitions.addComponents(asList(
409 PropertyDefinition.builder("sonar.string")
411 .description("String property")
412 .type(PropertyType.STRING)
417 PropertyDefinition.builder("sonar.list")
419 .description("List property")
420 .type(PropertyType.SINGLE_SELECT_LIST)
424 PropertyDefinition.builder("sonar.multiValues")
425 .name("Multi values")
426 .description("Multi values property")
427 .type(PropertyType.STRING)
431 PropertyDefinition.builder("sonar.propertySet")
432 .name("Property Set")
433 .description("Property Set property")
434 .type(PropertyType.PROPERTY_SET)
435 .category("property")
438 PropertyFieldDefinition.build("text")
440 .description("Text field description")
441 .type(PropertyType.TEXT)
443 PropertyFieldDefinition.build("list")
445 .description("List field description")
446 .type(PropertyType.SINGLE_SELECT_LIST)
447 .options("value1", "value2")
451 String result = ws.newRequest().setMediaType(JSON).execute().getInput();
453 JsonAssert.assertJson(ws.getDef().responseExampleAsString()).isSimilarTo(result);
456 private ListDefinitionsWsResponse executeRequest() {
457 return executeRequest(null);
460 private ListDefinitionsWsResponse executeRequest(@Nullable String key) {
461 TestRequest request = ws.newRequest();
463 request.setParam("component", key);
465 return request.executeProtobuf(ListDefinitionsWsResponse.class);
468 private void logIn() {
472 private void logInAsProjectUser() {
473 userSession.logIn().addProjectPermission(USER, project);
476 private void logInAsAdmin() {
477 userSession.logIn().addPermission(ADMINISTER);
480 private void logInAsProjectAdmin() {
482 .addProjectPermission(ADMIN, project)
483 .addProjectPermission(USER, project);