]> source.dussan.org Git - sonarqube.git/blob
c5c287b407906f681504fc92e3b1366d7d58fb25
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2021 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.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;
49
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;
72
73 public class ListDefinitionsActionTest {
74
75   @Rule
76   public ExpectedException expectedException = ExpectedException.none();
77   @Rule
78   public UserSessionRule userSession = UserSessionRule.standalone();
79   @Rule
80   public DbTester db = DbTester.create(System2.INSTANCE);
81
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));
89
90   @Before
91   public void setUp() {
92     project = componentDb.insertComponent(ComponentTesting.newPrivateProjectDto());
93   }
94
95   @Test
96   public void return_settings_definitions() {
97     logIn();
98     propertyDefinitions.addComponent(PropertyDefinition
99       .builder("foo")
100       .name("Foo")
101       .description("desc")
102       .category("cat")
103       .subCategory("subCat")
104       .type(PropertyType.TEXT)
105       .defaultValue("default")
106       .multiValues(true)
107       .build());
108
109     ListDefinitionsWsResponse result = executeRequest();
110
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();
121   }
122
123   @Test
124   public void return_settings_definitions_with_minimum_fields() {
125     logIn();
126     propertyDefinitions.addComponent(PropertyDefinition
127       .builder("foo")
128       .build());
129
130     ListDefinitionsWsResponse result = executeRequest();
131
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);
144   }
145
146   @Test
147   public void return_settings_definitions_with_deprecated_key() {
148     logIn();
149     propertyDefinitions.addComponent(PropertyDefinition
150       .builder("foo")
151       .name("Foo")
152       .deprecatedKey("deprecated")
153       .build());
154
155     ListDefinitionsWsResponse result = executeRequest();
156
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");
162   }
163
164   @Test
165   public void return_default_category() {
166     logIn();
167     propertyDefinitions.addComponent(PropertyDefinition.builder("foo").build(), "default");
168     propertyDefinitions.addComponent(PropertyDefinition.builder("foo").category("").build(), "default");
169
170     ListDefinitionsWsResponse result = executeRequest();
171
172     assertThat(result.getDefinitionsList()).hasSize(1);
173     assertThat(result.getDefinitions(0).getCategory()).isEqualTo("default");
174     assertThat(result.getDefinitions(0).getSubCategory()).isEqualTo("default");
175   }
176
177   @Test
178   public void return_single_select_list_property() {
179     logIn();
180     propertyDefinitions.addComponent(PropertyDefinition
181       .builder("foo")
182       .type(PropertyType.SINGLE_SELECT_LIST)
183       .options("one", "two")
184       .build());
185
186     ListDefinitionsWsResponse result = executeRequest();
187
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");
192   }
193
194   @Test
195   public void return_property_set() {
196     logIn();
197     propertyDefinitions.addComponent(PropertyDefinition
198       .builder("foo")
199       .type(PropertyType.PROPERTY_SET)
200       .fields(
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())
203       .build());
204
205     ListDefinitionsWsResponse result = executeRequest();
206
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);
211
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();
217
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");
223   }
224
225   @Test
226   public void return_license_type_in_property_set() {
227     logIn();
228     propertyDefinitions.addComponent(PropertyDefinition
229       .builder("foo")
230       .type(PropertyType.PROPERTY_SET)
231       .fields(PropertyFieldDefinition.build("license").name("License").type(PropertyType.LICENSE).build())
232       .build());
233
234     ListDefinitionsWsResponse result = executeRequest();
235
236     assertThat(result.getDefinitionsList()).hasSize(1);
237     assertThat(result.getDefinitions(0).getFieldsList()).extracting(Settings.Field::getKey, Settings.Field::getType).containsOnly(tuple("license", LICENSE));
238   }
239
240   @Test
241   public void return_global_settings_definitions() {
242     logIn();
243     propertyDefinitions.addComponent(PropertyDefinition.builder("foo").build());
244
245     ListDefinitionsWsResponse result = executeRequest();
246
247     assertThat(result.getDefinitionsList()).hasSize(1);
248   }
249
250   @Test
251   public void definitions_are_ordered_by_category_then_index_then_name_case_insensitive() {
252     logIn();
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());
257
258     ListDefinitionsWsResponse result = executeRequest();
259
260     assertThat(result.getDefinitionsList()).extracting(Definition::getKey)
261       .containsExactly("sonar.prop.41", "sonar.prop.11", "sonar.prop.13", "sonar.prop.12");
262   }
263
264   @Test
265   public void return_project_settings_def_by_project_key() {
266     logInAsProjectUser();
267     propertyDefinitions.addComponent(PropertyDefinition
268       .builder("foo")
269       .onQualifiers(PROJECT)
270       .build());
271
272     ListDefinitionsWsResponse result = executeRequest(project.getDbKey());
273
274     assertThat(result.getDefinitionsList()).hasSize(1);
275   }
276
277   @Test
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()));
285
286     ListDefinitionsWsResponse result = executeRequest();
287
288     assertThat(result.getDefinitionsList()).extracting("key").containsOnly("global", "global-and-project");
289   }
290
291   @Test
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()));
299
300     ListDefinitionsWsResponse result = executeRequest(project.getDbKey());
301
302     assertThat(result.getDefinitionsList()).extracting("key").containsOnly("global-and-project", "only-on-project");
303   }
304
305   @Test
306   public void does_not_return_hidden_properties() {
307     logInAsAdmin();
308     propertyDefinitions.addComponent(PropertyDefinition.builder("foo").hidden().build());
309
310     ListDefinitionsWsResponse result = executeRequest();
311
312     assertThat(result.getDefinitionsList()).isEmpty();
313   }
314
315   @Test
316   public void return_license_type() {
317     logInAsAdmin();
318     propertyDefinitions.addComponents(asList(
319       PropertyDefinition.builder("plugin.license.secured").type(PropertyType.LICENSE).build(),
320       PropertyDefinition.builder("commercial.plugin").type(PropertyType.LICENSE).build()));
321
322     ListDefinitionsWsResponse result = executeRequest();
323
324     assertThat(result.getDefinitionsList()).extracting(Definition::getKey, Definition::getType)
325       .containsOnly(tuple("plugin.license.secured", LICENSE), tuple("commercial.plugin", LICENSE));
326   }
327
328   @Test
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()));
333
334     ListDefinitionsWsResponse result = executeRequest();
335
336     assertThat(result.getDefinitionsList()).extracting(Definition::getKey).containsOnly("foo");
337   }
338
339   @Test
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()));
345
346     ListDefinitionsWsResponse result = executeRequest();
347
348     assertThat(result.getDefinitionsList()).extracting(Definition::getKey).containsOnly("foo", "secret.secured");
349   }
350
351   @Test
352   public void return_secured_settings_when_system_admin() {
353     logInAsAdmin();
354     propertyDefinitions.addComponents(asList(
355       PropertyDefinition.builder("foo").build(),
356       PropertyDefinition.builder("secret.secured").build()));
357
358     ListDefinitionsWsResponse result = executeRequest();
359
360     assertThat(result.getDefinitionsList()).extracting(Definition::getKey).containsOnly("foo", "secret.secured");
361   }
362
363   @Test
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()));
369
370     ListDefinitionsWsResponse result = executeRequest(project.getDbKey());
371
372     assertThat(result.getDefinitionsList()).extracting(Definition::getKey).containsOnly("foo", "secret.secured");
373   }
374
375   @Test
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());
379
380     expectedException.expect(ForbiddenException.class);
381
382     executeRequest(project.getDbKey());
383   }
384
385   @Test
386   public void fail_when_component_not_found() {
387     expectedException.expect(NotFoundException.class);
388     expectedException.expectMessage("Component key 'unknown' not found");
389
390     ws.newRequest()
391       .setParam("component", "unknown")
392       .execute();
393   }
394
395   @Test
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");
403   }
404
405   @Test
406   public void test_example_json_response() {
407     logInAsProjectAdmin();
408     propertyDefinitions.addComponents(asList(
409       PropertyDefinition.builder("sonar.string")
410         .name("String")
411         .description("String property")
412         .type(PropertyType.STRING)
413         .category("general")
414         .subCategory("test")
415         .defaultValue("123")
416         .build(),
417       PropertyDefinition.builder("sonar.list")
418         .name("List")
419         .description("List property")
420         .type(PropertyType.SINGLE_SELECT_LIST)
421         .category("general")
422         .options("a", "b")
423         .build(),
424       PropertyDefinition.builder("sonar.multiValues")
425         .name("Multi values")
426         .description("Multi values property")
427         .type(PropertyType.STRING)
428         .category("general")
429         .multiValues(true)
430         .build(),
431       PropertyDefinition.builder("sonar.propertySet")
432         .name("Property Set")
433         .description("Property Set property")
434         .type(PropertyType.PROPERTY_SET)
435         .category("property")
436         .subCategory("set")
437         .fields(
438           PropertyFieldDefinition.build("text")
439             .name("Text")
440             .description("Text field description")
441             .type(PropertyType.TEXT)
442             .build(),
443           PropertyFieldDefinition.build("list")
444             .name("List")
445             .description("List field description")
446             .type(PropertyType.SINGLE_SELECT_LIST)
447             .options("value1", "value2")
448             .build())
449         .build()));
450
451     String result = ws.newRequest().setMediaType(JSON).execute().getInput();
452
453     JsonAssert.assertJson(ws.getDef().responseExampleAsString()).isSimilarTo(result);
454   }
455
456   private ListDefinitionsWsResponse executeRequest() {
457     return executeRequest(null);
458   }
459
460   private ListDefinitionsWsResponse executeRequest(@Nullable String key) {
461     TestRequest request = ws.newRequest();
462     if (key != null) {
463       request.setParam("component", key);
464     }
465     return request.executeProtobuf(ListDefinitionsWsResponse.class);
466   }
467
468   private void logIn() {
469     userSession.logIn();
470   }
471
472   private void logInAsProjectUser() {
473     userSession.logIn().addProjectPermission(USER, project);
474   }
475
476   private void logInAsAdmin() {
477     userSession.logIn().addPermission(ADMINISTER);
478   }
479
480   private void logInAsProjectAdmin() {
481     userSession.logIn()
482       .addProjectPermission(ADMIN, project)
483       .addProjectPermission(USER, project);
484   }
485
486 }