]> source.dussan.org Git - sonarqube.git/blob
54d458221da8c92f270506cebe05b2f59ad2a547
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2023 SonarSource SA
4  * mailto:info AT sonarsource DOT com
5  *
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.
10  *
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.
15  *
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.
19  */
20 package org.sonar.server.setting.ws;
21
22 import javax.annotation.Nullable;
23 import org.junit.Before;
24 import org.junit.Rule;
25 import org.junit.Test;
26 import org.sonar.api.PropertyType;
27 import org.sonar.api.config.PropertyDefinition;
28 import org.sonar.api.config.PropertyDefinitions;
29 import org.sonar.api.config.PropertyFieldDefinition;
30 import org.sonar.api.server.ws.WebService;
31 import org.sonar.api.server.ws.WebService.Param;
32 import org.sonar.api.utils.System2;
33 import org.sonar.db.DbClient;
34 import org.sonar.db.DbTester;
35 import org.sonar.db.component.ComponentDbTester;
36 import org.sonar.db.component.ComponentDto;
37 import org.sonar.db.component.ComponentTesting;
38 import org.sonar.server.component.TestComponentFinder;
39 import org.sonar.server.exceptions.ForbiddenException;
40 import org.sonar.server.exceptions.NotFoundException;
41 import org.sonar.server.tester.UserSessionRule;
42 import org.sonar.server.ws.TestRequest;
43 import org.sonar.server.ws.WsActionTester;
44 import org.sonar.test.JsonAssert;
45 import org.sonarqube.ws.Settings;
46 import org.sonarqube.ws.Settings.Definition;
47 import org.sonarqube.ws.Settings.ListDefinitionsWsResponse;
48
49 import static java.util.Arrays.asList;
50 import static org.assertj.core.api.Assertions.assertThat;
51 import static org.assertj.core.api.Assertions.assertThatThrownBy;
52 import static org.assertj.core.groups.Tuple.tuple;
53 import static org.sonar.api.resources.Qualifiers.PROJECT;
54 import static org.sonar.api.web.UserRole.ADMIN;
55 import static org.sonar.api.web.UserRole.CODEVIEWER;
56 import static org.sonar.api.web.UserRole.USER;
57 import static org.sonar.db.permission.GlobalPermission.ADMINISTER;
58 import static org.sonar.db.permission.GlobalPermission.SCAN;
59 import static org.sonarqube.ws.MediaTypes.JSON;
60 import static org.sonarqube.ws.Settings.Definition.CategoryOneOfCase.CATEGORYONEOF_NOT_SET;
61 import static org.sonarqube.ws.Settings.Definition.DefaultValueOneOfCase.DEFAULTVALUEONEOF_NOT_SET;
62 import static org.sonarqube.ws.Settings.Definition.DeprecatedKeyOneOfCase.DEPRECATEDKEYONEOF_NOT_SET;
63 import static org.sonarqube.ws.Settings.Definition.NameOneOfCase.NAMEONEOF_NOT_SET;
64 import static org.sonarqube.ws.Settings.Definition.SubCategoryOneOfCase.SUBCATEGORYONEOF_NOT_SET;
65 import static org.sonarqube.ws.Settings.Type.BOOLEAN;
66 import static org.sonarqube.ws.Settings.Type.LICENSE;
67 import static org.sonarqube.ws.Settings.Type.PROPERTY_SET;
68 import static org.sonarqube.ws.Settings.Type.SINGLE_SELECT_LIST;
69 import static org.sonarqube.ws.Settings.Type.STRING;
70 import static org.sonarqube.ws.Settings.Type.TEXT;
71
72 public class ListDefinitionsActionTest {
73
74   @Rule
75   public UserSessionRule userSession = UserSessionRule.standalone();
76   @Rule
77   public DbTester db = DbTester.create(System2.INSTANCE);
78
79   private DbClient dbClient = db.getDbClient();
80   private ComponentDbTester componentDb = new ComponentDbTester(db);
81   private ComponentDto project;
82   private PropertyDefinitions propertyDefinitions = new PropertyDefinitions(System2.INSTANCE);
83   private SettingsWsSupport support = new SettingsWsSupport(userSession);
84   private WsActionTester ws = new WsActionTester(
85     new ListDefinitionsAction(dbClient, TestComponentFinder.from(db), userSession, propertyDefinitions, support));
86
87   @Before
88   public void setUp() {
89     project = componentDb.insertComponent(ComponentTesting.newPrivateProjectDto());
90   }
91
92   @Test
93   public void return_settings_definitions() {
94     logIn();
95     propertyDefinitions.addComponent(PropertyDefinition
96       .builder("foo")
97       .name("Foo")
98       .description("desc")
99       .category("cat")
100       .subCategory("subCat")
101       .type(PropertyType.TEXT)
102       .defaultValue("default")
103       .multiValues(true)
104       .build());
105
106     ListDefinitionsWsResponse result = executeRequest();
107
108     assertThat(result.getDefinitionsList()).hasSize(1);
109     Definition definition = result.getDefinitions(0);
110     assertThat(definition.getKey()).isEqualTo("foo");
111     assertThat(definition.getName()).isEqualTo("Foo");
112     assertThat(definition.getDescription()).isEqualTo("desc");
113     assertThat(definition.getCategory()).isEqualTo("cat");
114     assertThat(definition.getSubCategory()).isEqualTo("subCat");
115     assertThat(definition.getType()).isEqualTo(TEXT);
116     assertThat(definition.getDefaultValue()).isEqualTo("default");
117     assertThat(definition.getMultiValues()).isTrue();
118   }
119
120   @Test
121   public void return_settings_definitions_with_minimum_fields() {
122     logIn();
123     propertyDefinitions.addComponent(PropertyDefinition
124       .builder("foo")
125       .build());
126
127     ListDefinitionsWsResponse result = executeRequest();
128
129     assertThat(result.getDefinitionsList()).hasSize(1);
130     Definition definition = result.getDefinitions(0);
131     assertThat(definition.getKey()).isEqualTo("foo");
132     assertThat(definition.getType()).isEqualTo(STRING);
133     assertThat(definition.getNameOneOfCase()).isEqualTo(NAMEONEOF_NOT_SET);
134     assertThat(definition.getCategoryOneOfCase()).isEqualTo(CATEGORYONEOF_NOT_SET);
135     assertThat(definition.getSubCategoryOneOfCase()).isEqualTo(SUBCATEGORYONEOF_NOT_SET);
136     assertThat(definition.getDefaultValueOneOfCase()).isEqualTo(DEFAULTVALUEONEOF_NOT_SET);
137     assertThat(definition.getMultiValues()).isFalse();
138     assertThat(definition.getOptionsCount()).isZero();
139     assertThat(definition.getFieldsCount()).isZero();
140     assertThat(definition.getDeprecatedKeyOneOfCase()).isEqualTo(DEPRECATEDKEYONEOF_NOT_SET);
141   }
142
143   @Test
144   public void return_settings_definitions_with_deprecated_key() {
145     logIn();
146     propertyDefinitions.addComponent(PropertyDefinition
147       .builder("foo")
148       .name("Foo")
149       .deprecatedKey("deprecated")
150       .build());
151
152     ListDefinitionsWsResponse result = executeRequest();
153
154     assertThat(result.getDefinitionsList()).hasSize(1);
155     Definition definition = result.getDefinitions(0);
156     assertThat(definition.getKey()).isEqualTo("foo");
157     assertThat(definition.getName()).isEqualTo("Foo");
158     assertThat(definition.getDeprecatedKey()).isEqualTo("deprecated");
159   }
160
161   @Test
162   public void return_default_category() {
163     logIn();
164     propertyDefinitions.addComponent(PropertyDefinition.builder("foo").build(), "default");
165     propertyDefinitions.addComponent(PropertyDefinition.builder("foo").category("").build(), "default");
166
167     ListDefinitionsWsResponse result = executeRequest();
168
169     assertThat(result.getDefinitionsList()).hasSize(1);
170     assertThat(result.getDefinitions(0).getCategory()).isEqualTo("default");
171     assertThat(result.getDefinitions(0).getSubCategory()).isEqualTo("default");
172   }
173
174   @Test
175   public void return_single_select_list_property() {
176     logIn();
177     propertyDefinitions.addComponent(PropertyDefinition
178       .builder("foo")
179       .type(PropertyType.SINGLE_SELECT_LIST)
180       .options("one", "two")
181       .build());
182
183     ListDefinitionsWsResponse result = executeRequest();
184
185     assertThat(result.getDefinitionsList()).hasSize(1);
186     Definition definition = result.getDefinitions(0);
187     assertThat(definition.getType()).isEqualTo(SINGLE_SELECT_LIST);
188     assertThat(definition.getOptionsList()).containsExactly("one", "two");
189   }
190
191   @Test
192   public void return_JSON_property() {
193     logIn();
194     propertyDefinitions.addComponent(PropertyDefinition
195       .builder("foo")
196       .type(PropertyType.JSON)
197       .build());
198
199     ListDefinitionsWsResponse result = executeRequest();
200
201     assertThat(result.getDefinitionsList()).hasSize(1);
202     Definition definition = result.getDefinitions(0);
203     assertThat(definition.getType()).isEqualTo(Settings.Type.JSON);
204   }
205
206   @Test
207   public void return_property_set() {
208     logIn();
209     propertyDefinitions.addComponent(PropertyDefinition
210       .builder("foo")
211       .type(PropertyType.PROPERTY_SET)
212       .fields(
213         PropertyFieldDefinition.build("boolean").name("Boolean").description("boolean desc").type(PropertyType.BOOLEAN).build(),
214         PropertyFieldDefinition.build("list").name("List").description("list desc").type(PropertyType.SINGLE_SELECT_LIST).options("one", "two").build())
215       .build());
216
217     ListDefinitionsWsResponse result = executeRequest();
218
219     assertThat(result.getDefinitionsList()).hasSize(1);
220     Definition definition = result.getDefinitions(0);
221     assertThat(definition.getType()).isEqualTo(PROPERTY_SET);
222     assertThat(definition.getFieldsList()).hasSize(2);
223
224     assertThat(definition.getFields(0).getKey()).isEqualTo("boolean");
225     assertThat(definition.getFields(0).getName()).isEqualTo("Boolean");
226     assertThat(definition.getFields(0).getDescription()).isEqualTo("boolean desc");
227     assertThat(definition.getFields(0).getType()).isEqualTo(BOOLEAN);
228     assertThat(definition.getFields(0).getOptionsCount()).isZero();
229
230     assertThat(definition.getFields(1).getKey()).isEqualTo("list");
231     assertThat(definition.getFields(1).getName()).isEqualTo("List");
232     assertThat(definition.getFields(1).getDescription()).isEqualTo("list desc");
233     assertThat(definition.getFields(1).getType()).isEqualTo(SINGLE_SELECT_LIST);
234     assertThat(definition.getFields(1).getOptionsList()).containsExactly("one", "two");
235   }
236
237   @Test
238   public void return_license_type_in_property_set() {
239     logIn();
240     propertyDefinitions.addComponent(PropertyDefinition
241       .builder("foo")
242       .type(PropertyType.PROPERTY_SET)
243       .fields(PropertyFieldDefinition.build("license").name("License").type(PropertyType.LICENSE).build())
244       .build());
245
246     ListDefinitionsWsResponse result = executeRequest();
247
248     assertThat(result.getDefinitionsList()).hasSize(1);
249     assertThat(result.getDefinitions(0).getFieldsList()).extracting(Settings.Field::getKey, Settings.Field::getType).containsOnly(tuple("license", LICENSE));
250   }
251
252   @Test
253   public void return_global_settings_definitions() {
254     logIn();
255     propertyDefinitions.addComponent(PropertyDefinition.builder("foo").build());
256
257     ListDefinitionsWsResponse result = executeRequest();
258
259     assertThat(result.getDefinitionsList()).hasSize(1);
260   }
261
262   @Test
263   public void definitions_are_ordered_by_category_then_index_then_name_case_insensitive() {
264     logIn();
265     propertyDefinitions.addComponent(PropertyDefinition.builder("sonar.prop.11").category("cat-1").index(1).name("prop 1").build());
266     propertyDefinitions.addComponent(PropertyDefinition.builder("sonar.prop.12").category("cat-1").index(2).name("prop 2").build());
267     propertyDefinitions.addComponent(PropertyDefinition.builder("sonar.prop.13").category("CAT-1").index(1).name("prop 3").build());
268     propertyDefinitions.addComponent(PropertyDefinition.builder("sonar.prop.41").category("cat-0").index(25).name("prop 1").build());
269
270     ListDefinitionsWsResponse result = executeRequest();
271
272     assertThat(result.getDefinitionsList()).extracting(Definition::getKey)
273       .containsExactly("sonar.prop.41", "sonar.prop.11", "sonar.prop.13", "sonar.prop.12");
274   }
275
276   @Test
277   public void return_project_settings_def_by_project_key() {
278     logInAsProjectUser();
279     propertyDefinitions.addComponent(PropertyDefinition
280       .builder("foo")
281       .onQualifiers(PROJECT)
282       .build());
283
284     ListDefinitionsWsResponse result = executeRequest(project.getKey());
285
286     assertThat(result.getDefinitionsList()).hasSize(1);
287   }
288
289   @Test
290   public void return_only_global_properties_when_no_component_parameter() {
291     logInAsProjectUser();
292     propertyDefinitions.addComponents(asList(
293       PropertyDefinition.builder("global").build(),
294       PropertyDefinition.builder("global-and-project").onQualifiers(PROJECT).build(),
295       PropertyDefinition.builder("only-on-project").onlyOnQualifiers(PROJECT).build()));
296
297     ListDefinitionsWsResponse result = executeRequest();
298
299     assertThat(result.getDefinitionsList()).extracting("key").containsOnly("global", "global-and-project");
300   }
301
302   @Test
303   public void return_only_properties_available_for_component_qualifier() {
304     logInAsProjectUser();
305     propertyDefinitions.addComponents(asList(
306       PropertyDefinition.builder("global").build(),
307       PropertyDefinition.builder("global-and-project").onQualifiers(PROJECT).build(),
308       PropertyDefinition.builder("only-on-project").onlyOnQualifiers(PROJECT).build()));
309
310     ListDefinitionsWsResponse result = executeRequest(project.getKey());
311
312     assertThat(result.getDefinitionsList()).extracting("key").containsOnly("global-and-project", "only-on-project");
313   }
314
315   @Test
316   public void does_not_return_hidden_properties() {
317     logInAsAdmin();
318     propertyDefinitions.addComponent(PropertyDefinition.builder("foo").hidden().build());
319
320     ListDefinitionsWsResponse result = executeRequest();
321
322     assertThat(result.getDefinitionsList()).isEmpty();
323   }
324
325   @Test
326   public void return_license_type() {
327     logInAsAdmin();
328     propertyDefinitions.addComponents(asList(
329       PropertyDefinition.builder("plugin.license.secured").type(PropertyType.LICENSE).build(),
330       PropertyDefinition.builder("commercial.plugin").type(PropertyType.LICENSE).build()));
331
332     ListDefinitionsWsResponse result = executeRequest();
333
334     assertThat(result.getDefinitionsList()).extracting(Definition::getKey, Definition::getType)
335       .containsOnly(tuple("plugin.license.secured", LICENSE), tuple("commercial.plugin", LICENSE));
336   }
337
338   @Test
339   public void does_not_returned_secured_and_license_settings_when_not_authenticated() {
340     propertyDefinitions.addComponents(asList(
341       PropertyDefinition.builder("foo").build(),
342       PropertyDefinition.builder("secret.secured").build()));
343
344     ListDefinitionsWsResponse result = executeRequest();
345
346     assertThat(result.getDefinitionsList()).extracting(Definition::getKey).containsOnly("foo");
347   }
348
349   @Test
350   public void return_secured_settings_when_not_authenticated_but_with_scan_permission() {
351     userSession.anonymous().addPermission(SCAN);
352     propertyDefinitions.addComponents(asList(
353       PropertyDefinition.builder("foo").build(),
354       PropertyDefinition.builder("secret.secured").build()));
355
356     ListDefinitionsWsResponse result = executeRequest();
357
358     assertThat(result.getDefinitionsList()).extracting(Definition::getKey).containsOnly("foo", "secret.secured");
359   }
360
361   @Test
362   public void return_secured_settings_when_system_admin() {
363     logInAsAdmin();
364     propertyDefinitions.addComponents(asList(
365       PropertyDefinition.builder("foo").build(),
366       PropertyDefinition.builder("secret.secured").build()));
367
368     ListDefinitionsWsResponse result = executeRequest();
369
370     assertThat(result.getDefinitionsList()).extracting(Definition::getKey).containsOnly("foo", "secret.secured");
371   }
372
373   @Test
374   public void return_secured_settings_when_project_admin() {
375     logInAsProjectAdmin();
376     propertyDefinitions.addComponents(asList(
377       PropertyDefinition.builder("foo").onQualifiers(PROJECT).build(),
378       PropertyDefinition.builder("secret.secured").onQualifiers(PROJECT).build()));
379
380     ListDefinitionsWsResponse result = executeRequest(project.getKey());
381
382     assertThat(result.getDefinitionsList()).extracting(Definition::getKey).containsOnly("foo", "secret.secured");
383   }
384
385   @Test
386   public void fail_when_user_has_not_project_browse_permission() {
387     userSession.logIn("project-admin").addProjectPermission(CODEVIEWER, project);
388     propertyDefinitions.addComponent(PropertyDefinition.builder("foo").build());
389
390     assertThatThrownBy(() -> executeRequest(project.getKey()))
391       .isInstanceOf(ForbiddenException.class);
392   }
393
394   @Test
395   public void fail_when_component_not_found() {
396     assertThatThrownBy(() -> {
397       ws.newRequest()
398         .setParam("component", "unknown")
399         .execute();
400     })
401       .isInstanceOf(NotFoundException.class)
402       .hasMessage("Component key 'unknown' not found");
403   }
404
405   @Test
406   public void test_ws_definition() {
407     WebService.Action action = ws.getDef();
408     assertThat(action).isNotNull();
409     assertThat(action.isInternal()).isFalse();
410     assertThat(action.isPost()).isFalse();
411     assertThat(action.responseExampleAsString()).isNotEmpty();
412     assertThat(action.params()).extracting(Param::key).containsExactlyInAnyOrder("component");
413   }
414
415   @Test
416   public void test_example_json_response() {
417     logInAsProjectAdmin();
418     propertyDefinitions.addComponents(asList(
419       PropertyDefinition.builder("sonar.string")
420         .name("String")
421         .description("String property")
422         .type(PropertyType.STRING)
423         .category("general")
424         .subCategory("test")
425         .defaultValue("123")
426         .build(),
427       PropertyDefinition.builder("sonar.list")
428         .name("List")
429         .description("List property")
430         .type(PropertyType.SINGLE_SELECT_LIST)
431         .category("general")
432         .options("a", "b")
433         .build(),
434       PropertyDefinition.builder("sonar.multiValues")
435         .name("Multi values")
436         .description("Multi values property")
437         .type(PropertyType.STRING)
438         .category("general")
439         .multiValues(true)
440         .build(),
441       PropertyDefinition.builder("sonar.propertySet")
442         .name("Property Set")
443         .description("Property Set property")
444         .type(PropertyType.PROPERTY_SET)
445         .category("property")
446         .subCategory("set")
447         .fields(
448           PropertyFieldDefinition.build("text")
449             .name("Text")
450             .description("Text field description")
451             .type(PropertyType.TEXT)
452             .build(),
453           PropertyFieldDefinition.build("list")
454             .name("List")
455             .description("List field description")
456             .type(PropertyType.SINGLE_SELECT_LIST)
457             .options("value1", "value2")
458             .build())
459         .build()));
460
461     String result = ws.newRequest().setMediaType(JSON).execute().getInput();
462
463     JsonAssert.assertJson(ws.getDef().responseExampleAsString()).isSimilarTo(result);
464   }
465
466   private ListDefinitionsWsResponse executeRequest() {
467     return executeRequest(null);
468   }
469
470   private ListDefinitionsWsResponse executeRequest(@Nullable String key) {
471     TestRequest request = ws.newRequest();
472     if (key != null) {
473       request.setParam("component", key);
474     }
475     return request.executeProtobuf(ListDefinitionsWsResponse.class);
476   }
477
478   private void logIn() {
479     userSession.logIn();
480   }
481
482   private void logInAsProjectUser() {
483     userSession.logIn().addProjectPermission(USER, project);
484   }
485
486   private void logInAsAdmin() {
487     userSession.logIn().addPermission(ADMINISTER);
488   }
489
490   private void logInAsProjectAdmin() {
491     userSession.logIn()
492       .addProjectPermission(ADMIN, project)
493       .addProjectPermission(USER, project);
494   }
495
496 }