You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ValuesActionTest.java 41KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947
  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. import com.google.common.base.Joiner;
  22. import com.google.common.collect.ImmutableMap;
  23. import java.util.Comparator;
  24. import java.util.List;
  25. import java.util.Map;
  26. import java.util.stream.Collectors;
  27. import javax.annotation.Nullable;
  28. import org.junit.Before;
  29. import org.junit.Rule;
  30. import org.junit.Test;
  31. import org.junit.rules.ExpectedException;
  32. import org.sonar.api.PropertyType;
  33. import org.sonar.api.config.Configuration;
  34. import org.sonar.api.config.PropertyDefinition;
  35. import org.sonar.api.config.PropertyDefinitions;
  36. import org.sonar.api.config.PropertyFieldDefinition;
  37. import org.sonar.api.config.internal.MapSettings;
  38. import org.sonar.api.server.ws.WebService;
  39. import org.sonar.api.utils.System2;
  40. import org.sonar.api.web.UserRole;
  41. import org.sonar.db.DbClient;
  42. import org.sonar.db.DbTester;
  43. import org.sonar.db.component.ComponentDbTester;
  44. import org.sonar.db.component.ComponentDto;
  45. import org.sonar.db.component.ComponentTesting;
  46. import org.sonar.db.permission.GlobalPermission;
  47. import org.sonar.db.property.PropertyDbTester;
  48. import org.sonar.process.ProcessProperties;
  49. import org.sonar.server.component.TestComponentFinder;
  50. import org.sonar.server.exceptions.ForbiddenException;
  51. import org.sonar.server.exceptions.NotFoundException;
  52. import org.sonar.server.tester.UserSessionRule;
  53. import org.sonar.server.ws.TestRequest;
  54. import org.sonar.server.ws.WsActionTester;
  55. import org.sonar.test.JsonAssert;
  56. import org.sonarqube.ws.Settings;
  57. import org.sonarqube.ws.Settings.ValuesWsResponse;
  58. import static java.lang.String.format;
  59. import static java.util.Arrays.asList;
  60. import static java.util.Comparator.comparing;
  61. import static org.assertj.core.api.Assertions.assertThat;
  62. import static org.assertj.core.groups.Tuple.tuple;
  63. import static org.sonar.api.resources.Qualifiers.MODULE;
  64. import static org.sonar.api.resources.Qualifiers.PROJECT;
  65. import static org.sonar.api.web.UserRole.ADMIN;
  66. import static org.sonar.api.web.UserRole.CODEVIEWER;
  67. import static org.sonar.api.web.UserRole.USER;
  68. import static org.sonar.core.permission.GlobalPermissions.SCAN_EXECUTION;
  69. import static org.sonar.db.component.ComponentTesting.newModuleDto;
  70. import static org.sonar.db.permission.GlobalPermission.SCAN;
  71. import static org.sonar.db.property.PropertyTesting.newComponentPropertyDto;
  72. import static org.sonar.db.property.PropertyTesting.newGlobalPropertyDto;
  73. import static org.sonar.process.ProcessProperties.Property.SONARCLOUD_ENABLED;
  74. import static org.sonarqube.ws.MediaTypes.JSON;
  75. import static org.sonarqube.ws.Settings.Setting.ParentValueOneOfCase.PARENTVALUEONEOF_NOT_SET;
  76. public class ValuesActionTest {
  77. private static Joiner COMMA_JOINER = Joiner.on(",");
  78. @Rule
  79. public ExpectedException expectedException = ExpectedException.none();
  80. @Rule
  81. public UserSessionRule userSession = UserSessionRule.standalone();
  82. @Rule
  83. public DbTester db = DbTester.create(System2.INSTANCE);
  84. private DbClient dbClient = db.getDbClient();
  85. private PropertyDbTester propertyDb = new PropertyDbTester(db);
  86. private ComponentDbTester componentDb = new ComponentDbTester(db);
  87. private PropertyDefinitions definitions = new PropertyDefinitions(System2.INSTANCE);
  88. private SettingsWsSupport support = new SettingsWsSupport(userSession);
  89. private ComponentDto project;
  90. @Before
  91. public void setUp() {
  92. project = componentDb.insertComponent(ComponentTesting.newPrivateProjectDto());
  93. }
  94. @Test
  95. public void return_simple_value() {
  96. logIn();
  97. definitions.addComponent(PropertyDefinition
  98. .builder("foo")
  99. .build());
  100. propertyDb.insertProperties(null, null, null, null, newGlobalPropertyDto().setKey("foo").setValue("one"));
  101. ValuesWsResponse result = executeRequestForGlobalProperties("foo");
  102. assertThat(result.getSettingsList()).hasSize(1);
  103. Settings.Setting value = result.getSettings(0);
  104. assertThat(value.getKey()).isEqualTo("foo");
  105. assertThat(value.getValue()).isEqualTo("one");
  106. assertThat(value.getInherited()).isFalse();
  107. }
  108. @Test
  109. public void return_multi_values() {
  110. logIn();
  111. // Property never defined, default value is returned
  112. definitions.addComponent(PropertyDefinition.builder("default")
  113. .multiValues(true)
  114. .defaultValue("one,two")
  115. .build());
  116. // Property defined at global level
  117. definitions.addComponent(PropertyDefinition.builder("global")
  118. .multiValues(true)
  119. .build());
  120. propertyDb.insertProperties(null, null, null, null, newGlobalPropertyDto().setKey("global").setValue("three,four"));
  121. ValuesWsResponse result = executeRequestForGlobalProperties("default", "global");
  122. assertThat(result.getSettingsList()).hasSize(2);
  123. Settings.Setting foo = result.getSettings(0);
  124. assertThat(foo.getKey()).isEqualTo("default");
  125. assertThat(foo.getValues().getValuesList()).containsOnly("one", "two");
  126. Settings.Setting bar = result.getSettings(1);
  127. assertThat(bar.getKey()).isEqualTo("global");
  128. assertThat(bar.getValues().getValuesList()).containsOnly("three", "four");
  129. }
  130. @Test
  131. public void return_multi_value_with_coma() {
  132. logIn();
  133. definitions.addComponent(PropertyDefinition.builder("global").multiValues(true).build());
  134. propertyDb.insertProperties(null, null, null, null, newGlobalPropertyDto().setKey("global").setValue("three,four%2Cfive"));
  135. ValuesWsResponse result = executeRequestForGlobalProperties("global");
  136. assertThat(result.getSettingsList()).hasSize(1);
  137. Settings.Setting setting = result.getSettings(0);
  138. assertThat(setting.getKey()).isEqualTo("global");
  139. assertThat(setting.getValues().getValuesList()).containsOnly("three", "four,five");
  140. }
  141. @Test
  142. public void return_property_set() {
  143. logIn();
  144. definitions.addComponent(PropertyDefinition
  145. .builder("foo")
  146. .type(PropertyType.PROPERTY_SET)
  147. .fields(asList(
  148. PropertyFieldDefinition.build("key").name("Key").build(),
  149. PropertyFieldDefinition.build("size").name("Size").build()))
  150. .build());
  151. propertyDb.insertPropertySet("foo", null, ImmutableMap.of("key", "key1", "size", "size1"), ImmutableMap.of("key", "key2"));
  152. ValuesWsResponse result = executeRequestForGlobalProperties("foo");
  153. assertThat(result.getSettingsList()).hasSize(1);
  154. Settings.Setting value = result.getSettings(0);
  155. assertThat(value.getKey()).isEqualTo("foo");
  156. assertFieldValues(value, ImmutableMap.of("key", "key1", "size", "size1"), ImmutableMap.of("key", "key2"));
  157. }
  158. @Test
  159. public void return_property_set_for_component() {
  160. logInAsProjectUser();
  161. definitions.addComponent(PropertyDefinition
  162. .builder("foo")
  163. .type(PropertyType.PROPERTY_SET)
  164. .onQualifiers(PROJECT)
  165. .fields(asList(
  166. PropertyFieldDefinition.build("key").name("Key").build(),
  167. PropertyFieldDefinition.build("size").name("Size").build()))
  168. .build());
  169. propertyDb.insertPropertySet("foo", project, ImmutableMap.of("key", "key1", "size", "size1"), ImmutableMap.of("key", "key2"));
  170. ValuesWsResponse result = executeRequestForProjectProperties("foo");
  171. assertThat(result.getSettingsList()).hasSize(1);
  172. Settings.Setting value = result.getSettings(0);
  173. assertThat(value.getKey()).isEqualTo("foo");
  174. assertFieldValues(value, ImmutableMap.of("key", "key1", "size", "size1"), ImmutableMap.of("key", "key2"));
  175. }
  176. @Test
  177. public void return_default_values() {
  178. logIn();
  179. definitions.addComponent(PropertyDefinition
  180. .builder("foo")
  181. .defaultValue("default")
  182. .build());
  183. ValuesWsResponse result = executeRequestForGlobalProperties("foo");
  184. assertThat(result.getSettingsList()).hasSize(1);
  185. assertSetting(result.getSettings(0), "foo", "default", true);
  186. }
  187. @Test
  188. public void return_global_values() {
  189. logIn();
  190. definitions.addComponent(PropertyDefinition.builder("property").defaultValue("default").build());
  191. propertyDb.insertProperties(null, null, null,
  192. // The property is overriding default value
  193. null, newGlobalPropertyDto().setKey("property").setValue("one"));
  194. ValuesWsResponse result = executeRequestForGlobalProperties("property");
  195. assertThat(result.getSettingsList()).hasSize(1);
  196. assertSetting(result.getSettings(0), "property", "one", false);
  197. }
  198. @Test
  199. public void return_project_values() {
  200. logInAsProjectUser();
  201. definitions.addComponent(
  202. PropertyDefinition.builder("property").defaultValue("default").onQualifiers(PROJECT).build());
  203. propertyDb.insertProperties(null, null, null,
  204. null, newGlobalPropertyDto().setKey("property").setValue("one"));
  205. propertyDb.insertProperties(null, project.getKey(), project.name(), project.qualifier(),
  206. // The property is overriding global value
  207. newComponentPropertyDto(project).setKey("property").setValue("two"));
  208. ValuesWsResponse result = executeRequestForProjectProperties("property");
  209. assertThat(result.getSettingsList()).hasSize(1);
  210. assertSetting(result.getSettings(0), "property", "two", false);
  211. }
  212. @Test
  213. public void return_settings_defined_only_at_global_level_when_loading_project_settings() {
  214. logInAsProjectUser();
  215. definitions.addComponents(asList(
  216. PropertyDefinition.builder("global").build(),
  217. PropertyDefinition.builder("global.default").defaultValue("default").build(),
  218. PropertyDefinition.builder("project").onQualifiers(PROJECT).build()));
  219. propertyDb.insertProperties(null, null, null,
  220. null, newGlobalPropertyDto().setKey("global").setValue("one"));
  221. propertyDb.insertProperties(null, project.getKey(), project.name(), project.qualifier(),
  222. newComponentPropertyDto(project).setKey("project").setValue("two"));
  223. ValuesWsResponse result = executeRequestForProjectProperties();
  224. assertThat(result.getSettingsList()).extracting(Settings.Setting::getKey, Settings.Setting::getValue)
  225. .containsOnly(tuple("project", "two"), tuple("global.default", "default"), tuple("global", "one"));
  226. }
  227. @Test
  228. public void return_is_inherited_to_true_when_property_is_defined_only_at_global_level() {
  229. logInAsProjectUser();
  230. definitions.addComponent(PropertyDefinition.builder("property").defaultValue("default").onQualifiers(PROJECT).build());
  231. // The property is not defined on project
  232. propertyDb.insertProperties(null, null, null, null,
  233. newGlobalPropertyDto().setKey("property").setValue("one"));
  234. ValuesWsResponse result = executeRequestForProjectProperties("property");
  235. assertThat(result.getSettingsList()).hasSize(1);
  236. assertSetting(result.getSettings(0), "property", "one", true);
  237. }
  238. @Test
  239. public void return_values_even_if_no_property_definition() {
  240. logIn();
  241. propertyDb.insertProperties(null, null, null, null,
  242. newGlobalPropertyDto().setKey("globalPropertyWithoutDefinition").setValue("value"));
  243. ValuesWsResponse result = executeRequestForGlobalProperties("globalPropertyWithoutDefinition");
  244. Settings.Setting globalPropertyWithoutDefinitionValue = result.getSettings(0);
  245. assertThat(globalPropertyWithoutDefinitionValue.getKey()).isEqualTo("globalPropertyWithoutDefinition");
  246. assertThat(globalPropertyWithoutDefinitionValue.getValue()).isEqualTo("value");
  247. assertThat(globalPropertyWithoutDefinitionValue.getInherited()).isFalse();
  248. }
  249. @Test
  250. public void return_values_of_component_even_if_no_property_definition() {
  251. logInAsProjectUser();
  252. propertyDb.insertProperties(null, project.getKey(), project.name(), project.qualifier(),
  253. newComponentPropertyDto(project).setKey("property").setValue("foo"));
  254. ValuesWsResponse response = executeRequestForComponentProperties(project, "property");
  255. assertThat(response.getSettingsCount()).isEqualTo(1);
  256. assertSetting(response.getSettings(0), "property", "foo", false);
  257. }
  258. @Test
  259. public void return_empty_when_property_def_exists_but_no_value() {
  260. logIn();
  261. definitions.addComponent(PropertyDefinition
  262. .builder("foo")
  263. .build());
  264. ValuesWsResponse result = executeRequestForGlobalProperties("foo");
  265. assertThat(result.getSettingsList()).isEmpty();
  266. }
  267. @Test
  268. public void return_nothing_when_unknown_keys() {
  269. logIn();
  270. definitions.addComponent(PropertyDefinition
  271. .builder("foo")
  272. .defaultValue("default")
  273. .build());
  274. propertyDb.insertProperties(null, null, null, null,
  275. newGlobalPropertyDto().setKey("bar").setValue(""));
  276. ValuesWsResponse result = executeRequestForGlobalProperties("unknown");
  277. assertThat(result.getSettingsList()).isEmpty();
  278. }
  279. @Test
  280. public void return_module_values() {
  281. logInAsProjectUser();
  282. ComponentDto module = componentDb.insertComponent(newModuleDto(project));
  283. definitions.addComponent(PropertyDefinition.builder("property").defaultValue("default").onQualifiers(PROJECT, MODULE).build());
  284. propertyDb.insertProperties(null, null, null, null,
  285. newGlobalPropertyDto().setKey("property").setValue("one"));
  286. propertyDb.insertProperties(null, module.getKey(), module.name(), module.qualifier(),
  287. // The property is overriding global value
  288. newComponentPropertyDto(module).setKey("property").setValue("two"));
  289. ValuesWsResponse result = executeRequestForComponentProperties(module, "property");
  290. assertThat(result.getSettingsList()).hasSize(1);
  291. assertSetting(result.getSettings(0), "property", "two", false);
  292. }
  293. @Test
  294. public void return_inherited_values_on_module() {
  295. logInAsProjectUser();
  296. ComponentDto module = componentDb.insertComponent(newModuleDto(project));
  297. definitions.addComponents(asList(
  298. PropertyDefinition.builder("defaultProperty").defaultValue("default").onQualifiers(PROJECT, MODULE).build(),
  299. PropertyDefinition.builder("globalProperty").onQualifiers(PROJECT, MODULE).build(),
  300. PropertyDefinition.builder("projectProperty").onQualifiers(PROJECT, MODULE).build(),
  301. PropertyDefinition.builder("moduleProperty").onQualifiers(PROJECT, MODULE).build()));
  302. propertyDb.insertProperties(null, null, null, null,
  303. newGlobalPropertyDto().setKey("globalProperty").setValue("global"));
  304. propertyDb.insertProperties(null, project.getKey(), project.name(), project.qualifier(),
  305. newComponentPropertyDto(project).setKey("projectProperty").setValue("project"));
  306. propertyDb.insertProperties(null, module.getKey(), module.name(), module.qualifier(),
  307. newComponentPropertyDto(module).setKey("moduleProperty").setValue("module"));
  308. ValuesWsResponse result = executeRequestForComponentProperties(module, "defaultProperty", "globalProperty", "projectProperty", "moduleProperty");
  309. assertThat(result.getSettingsList()).hasSize(4);
  310. assertSetting(result.getSettings(0), "defaultProperty", "default", true);
  311. assertSetting(result.getSettings(1), "globalProperty", "global", true);
  312. assertSetting(result.getSettings(2), "projectProperty", "project", true);
  313. assertSetting(result.getSettings(3), "moduleProperty", "module", false);
  314. }
  315. @Test
  316. public void return_inherited_values_on_global_setting() {
  317. logIn();
  318. definitions.addComponents(asList(
  319. PropertyDefinition.builder("defaultProperty").defaultValue("default").build(),
  320. PropertyDefinition.builder("globalProperty").build()));
  321. propertyDb.insertProperties(null, null, null, null,
  322. newGlobalPropertyDto().setKey("globalProperty").setValue("global"));
  323. ValuesWsResponse result = executeRequestForGlobalProperties("defaultProperty", "globalProperty");
  324. assertThat(result.getSettingsList()).hasSize(2);
  325. assertSetting(result.getSettings(0), "defaultProperty", "default", true);
  326. assertSetting(result.getSettings(1), "globalProperty", "global", false);
  327. }
  328. @Test
  329. public void return_parent_value() {
  330. logInAsProjectUser();
  331. ComponentDto module = componentDb.insertComponent(newModuleDto(project));
  332. ComponentDto subModule = componentDb.insertComponent(newModuleDto(module));
  333. definitions.addComponents(asList(
  334. PropertyDefinition.builder("foo").defaultValue("default").onQualifiers(PROJECT, MODULE).build()));
  335. propertyDb.insertProperties(null, null, null, null,
  336. newGlobalPropertyDto().setKey("foo").setValue("global"));
  337. propertyDb.insertProperties(null, project.getKey(), project.name(), project.qualifier(),
  338. newComponentPropertyDto(project).setKey("foo").setValue("project"));
  339. propertyDb.insertProperties(null, module.getKey(), module.name(), module.qualifier(),
  340. newComponentPropertyDto(module).setKey("foo").setValue("module"));
  341. assertParentValue(executeRequestForComponentProperties(subModule, "foo").getSettings(0), "module");
  342. assertParentValue(executeRequestForComponentProperties(module, "foo").getSettings(0), "project");
  343. assertParentValue(executeRequestForComponentProperties(project, "foo").getSettings(0), "global");
  344. assertParentValue(executeRequestForGlobalProperties("foo").getSettings(0), "default");
  345. }
  346. @Test
  347. public void return_parent_values() {
  348. logInAsProjectUser();
  349. ComponentDto module = componentDb.insertComponent(newModuleDto(project));
  350. ComponentDto subModule = componentDb.insertComponent(newModuleDto(module));
  351. definitions.addComponents(asList(
  352. PropertyDefinition.builder("foo").defaultValue("default1,default2").multiValues(true).onQualifiers(PROJECT, MODULE).build()));
  353. propertyDb.insertProperties(null, null, null, null,
  354. newGlobalPropertyDto().setKey("foo").setValue("global1,global2"));
  355. propertyDb.insertProperties(null, project.getKey(), project.name(), project.qualifier(),
  356. newComponentPropertyDto(project).setKey("foo").setValue("project1,project2"));
  357. propertyDb.insertProperties(null, module.getKey(), module.name(), module.qualifier(),
  358. newComponentPropertyDto(module).setKey("foo").setValue("module1,module2"));
  359. assertParentValues(executeRequestForComponentProperties(subModule, "foo").getSettings(0), "module1", "module2");
  360. assertParentValues(executeRequestForComponentProperties(module, "foo").getSettings(0), "project1", "project2");
  361. assertParentValues(executeRequestForComponentProperties(project, "foo").getSettings(0), "global1", "global2");
  362. assertParentValues(executeRequestForGlobalProperties("foo").getSettings(0), "default1", "default2");
  363. }
  364. @Test
  365. public void return_parent_field_values() {
  366. logInAsProjectUser();
  367. ComponentDto module = componentDb.insertComponent(newModuleDto(project));
  368. ComponentDto subModule = componentDb.insertComponent(newModuleDto(module));
  369. definitions.addComponent(PropertyDefinition
  370. .builder("foo")
  371. .onQualifiers(PROJECT, MODULE)
  372. .type(PropertyType.PROPERTY_SET)
  373. .fields(asList(
  374. PropertyFieldDefinition.build("key").name("Key").build(),
  375. PropertyFieldDefinition.build("size").name("Size").build()))
  376. .build());
  377. propertyDb.insertPropertySet("foo", null, ImmutableMap.of("key", "keyG1", "size", "sizeG1"));
  378. propertyDb.insertPropertySet("foo", project, ImmutableMap.of("key", "keyP1", "size", "sizeP1"));
  379. propertyDb.insertPropertySet("foo", module, ImmutableMap.of("key", "keyM1", "size", "sizeM1"));
  380. assertParentFieldValues(executeRequestForComponentProperties(subModule, "foo").getSettings(0), ImmutableMap.of("key", "keyM1", "size", "sizeM1"));
  381. assertParentFieldValues(executeRequestForComponentProperties(module, "foo").getSettings(0), ImmutableMap.of("key", "keyP1", "size", "sizeP1"));
  382. assertParentFieldValues(executeRequestForComponentProperties(project, "foo").getSettings(0), ImmutableMap.of("key", "keyG1", "size", "sizeG1"));
  383. assertParentFieldValues(executeRequestForGlobalProperties("foo").getSettings(0));
  384. }
  385. @Test
  386. public void return_no_parent_value() {
  387. logInAsProjectUser();
  388. ComponentDto module = componentDb.insertComponent(newModuleDto(project));
  389. ComponentDto subModule = componentDb.insertComponent(newModuleDto(module));
  390. definitions.addComponents(asList(
  391. PropertyDefinition.builder("simple").onQualifiers(PROJECT, MODULE).build(),
  392. PropertyDefinition.builder("multi").multiValues(true).onQualifiers(PROJECT, MODULE).build(),
  393. PropertyDefinition.builder("set")
  394. .type(PropertyType.PROPERTY_SET)
  395. .onQualifiers(PROJECT, MODULE)
  396. .fields(asList(
  397. PropertyFieldDefinition.build("key").name("Key").build(),
  398. PropertyFieldDefinition.build("size").name("Size").build()))
  399. .build()));
  400. propertyDb.insertProperties(null, module.getKey(), module.name(), module.qualifier(),
  401. newComponentPropertyDto(module).setKey("simple").setValue("module"),
  402. newComponentPropertyDto(module).setKey("multi").setValue("module1,module2"));
  403. propertyDb.insertPropertySet("set", module, ImmutableMap.of("key", "keyM1", "size", "sizeM1"));
  404. assertParentValue(executeRequestForComponentProperties(subModule, "simple").getSettings(0), null);
  405. assertParentValues(executeRequestForComponentProperties(subModule, "multi").getSettings(0));
  406. assertParentFieldValues(executeRequestForComponentProperties(subModule, "set").getSettings(0));
  407. }
  408. @Test
  409. public void return_parent_value_when_no_definition() {
  410. logInAsProjectUser();
  411. ComponentDto module = componentDb.insertComponent(newModuleDto(project));
  412. propertyDb.insertProperties(null, null, null, null,
  413. newGlobalPropertyDto().setKey("foo").setValue("global"));
  414. propertyDb.insertProperties(null, project.getKey(), project.name(), project.qualifier(),
  415. newComponentPropertyDto(project).setKey("foo").setValue("project"));
  416. assertParentValue(executeRequestForComponentProperties(module, "foo").getSettings(0), "project");
  417. assertParentValue(executeRequestForComponentProperties(project, "foo").getSettings(0), "global");
  418. assertParentValue(executeRequestForGlobalProperties("foo").getSettings(0), null);
  419. }
  420. @Test
  421. public void return_value_of_deprecated_key() {
  422. logIn();
  423. definitions.addComponent(PropertyDefinition
  424. .builder("foo")
  425. .deprecatedKey("deprecated")
  426. .build());
  427. propertyDb.insertProperties(null, null, null, null,
  428. newGlobalPropertyDto().setKey("foo").setValue("one"));
  429. ValuesWsResponse result = executeRequestForGlobalProperties("deprecated");
  430. assertThat(result.getSettingsList()).hasSize(1);
  431. Settings.Setting value = result.getSettings(0);
  432. assertThat(value.getKey()).isEqualTo("deprecated");
  433. assertThat(value.getValue()).isEqualTo("one");
  434. }
  435. @Test
  436. public void do_not_return_secured_settings_when_not_authenticated() {
  437. definitions.addComponents(asList(
  438. PropertyDefinition.builder("foo").build(),
  439. PropertyDefinition.builder("secret.secured").build()));
  440. propertyDb.insertProperties(null, null, null, null,
  441. newGlobalPropertyDto().setKey("foo").setValue("one"),
  442. newGlobalPropertyDto().setKey("secret.secured").setValue("password"));
  443. ValuesWsResponse result = executeRequestForGlobalProperties();
  444. assertThat(result.getSettingsList()).extracting(Settings.Setting::getKey).containsOnly("foo");
  445. }
  446. @Test
  447. public void do_not_return_secured_settings_in_property_set_when_not_authenticated() {
  448. definitions.addComponent(PropertyDefinition
  449. .builder("foo")
  450. .type(PropertyType.PROPERTY_SET)
  451. .fields(asList(
  452. PropertyFieldDefinition.build("key").name("Key").build(),
  453. PropertyFieldDefinition.build("secret.secured").name("Secured").build()))
  454. .build());
  455. propertyDb.insertPropertySet("foo", null, ImmutableMap.of("key", "key1", "secret.secured", "123456"));
  456. ValuesWsResponse result = executeRequestForGlobalProperties();
  457. assertFieldValues(result.getSettings(0), ImmutableMap.of("key", "key1"));
  458. }
  459. @Test
  460. public void return_global_secured_settings_when_not_authenticated_but_with_scan_permission() {
  461. userSession.anonymous().addPermission(SCAN);
  462. definitions.addComponents(asList(
  463. PropertyDefinition.builder("foo").build(),
  464. PropertyDefinition.builder("secret.secured").build()));
  465. propertyDb.insertProperties(null, null, null, null,
  466. newGlobalPropertyDto().setKey("foo").setValue("one"),
  467. newGlobalPropertyDto().setKey("secret.secured").setValue("password"));
  468. ValuesWsResponse result = executeRequestForGlobalProperties();
  469. assertThat(result.getSettingsList()).extracting(Settings.Setting::getKey).containsOnly("foo", "secret.secured");
  470. }
  471. @Test
  472. public void return_component_secured_settings_when_not_authenticated_but_with_project_scan_permission() {
  473. userSession
  474. .addProjectPermission(USER, project)
  475. .addProjectPermission(SCAN_EXECUTION, project);
  476. definitions.addComponents(asList(
  477. PropertyDefinition.builder("foo").onQualifiers(PROJECT).build(),
  478. PropertyDefinition.builder("global.secret.secured").build(),
  479. PropertyDefinition.builder("secret.secured").onQualifiers(PROJECT).build()));
  480. propertyDb.insertProperties(null, null, null, null,
  481. newGlobalPropertyDto().setKey("global.secret.secured").setValue("very secret"));
  482. propertyDb.insertProperties(null, project.getKey(), project.name(), project.qualifier(),
  483. newComponentPropertyDto(project).setKey("foo").setValue("one"),
  484. newComponentPropertyDto(project).setKey("secret.secured").setValue("password"));
  485. ValuesWsResponse result = executeRequestForProjectProperties();
  486. assertThat(result.getSettingsList()).extracting(Settings.Setting::getKey).containsOnly("foo", "global.secret.secured", "secret.secured");
  487. }
  488. @Test
  489. public void return_component_secured_settings_even_if_not_defined_when_not_authenticated_but_with_scan_permission() {
  490. userSession
  491. .addProjectPermission(USER, project)
  492. .addProjectPermission(SCAN_EXECUTION, project);
  493. propertyDb.insertProperties(null, project.getKey(), project.name(), project.qualifier(),
  494. newComponentPropertyDto(project).setKey("not-defined.secured").setValue("123"));
  495. ValuesWsResponse result = executeRequestForProjectProperties("not-defined.secured");
  496. assertThat(result.getSettingsList()).extracting(Settings.Setting::getKey).containsOnly("not-defined.secured");
  497. }
  498. @Test
  499. public void return_secured_settings_when_system_admin() {
  500. logInAsAdmin();
  501. definitions.addComponents(asList(
  502. PropertyDefinition.builder("foo").build(),
  503. PropertyDefinition.builder("secret.secured").build()));
  504. propertyDb.insertProperties(null, null, null, null,
  505. newGlobalPropertyDto().setKey("foo").setValue("one"),
  506. newGlobalPropertyDto().setKey("secret.secured").setValue("password"));
  507. ValuesWsResponse result = executeRequestForGlobalProperties();
  508. assertThat(result.getSettingsList()).extracting(Settings.Setting::getKey).containsOnly("foo", "secret.secured");
  509. }
  510. @Test
  511. public void return_secured_settings_when_project_admin() {
  512. logInAsProjectAdmin();
  513. definitions.addComponents(asList(
  514. PropertyDefinition.builder("foo").onQualifiers(PROJECT).build(),
  515. PropertyDefinition.builder("global.secret.secured").build(),
  516. PropertyDefinition.builder("secret.secured").onQualifiers(PROJECT).build()));
  517. propertyDb.insertProperties(null, null, null, null,
  518. newGlobalPropertyDto().setKey("global.secret.secured").setValue("very secret"));
  519. propertyDb.insertProperties(null, project.getKey(), project.name(), project.qualifier(),
  520. newComponentPropertyDto(project).setKey("foo").setValue("one"),
  521. newComponentPropertyDto(project).setKey("secret.secured").setValue("password"));
  522. ValuesWsResponse result = executeRequestForProjectProperties();
  523. List<Settings.Setting> settingsList = result.getSettingsList().stream().sorted(comparing(Settings.Setting::getKey)).collect(Collectors.toList());
  524. assertThat(settingsList).extracting(Settings.Setting::getKey).containsExactly("foo", "global.secret.secured", "secret.secured");
  525. assertThat(settingsList).extracting(Settings.Setting::hasValue).containsExactly(true, false, false);
  526. }
  527. @Test
  528. public void return_secured_settings_even_if_not_defined_when_project_admin() {
  529. logInAsProjectAdmin();
  530. propertyDb.insertProperties(null, project.getKey(), project.name(), project.qualifier(),
  531. newComponentPropertyDto(project).setKey("not-defined.secured").setValue("123"));
  532. ValuesWsResponse result = executeRequestForProjectProperties("not-defined.secured");
  533. assertThat(result.getSettingsList()).extracting(Settings.Setting::getKey).containsOnly("not-defined.secured");
  534. }
  535. @Test
  536. public void return_secured_settings_in_property_set_when_system_admin() {
  537. logInAsAdmin();
  538. definitions.addComponent(PropertyDefinition
  539. .builder("foo")
  540. .type(PropertyType.PROPERTY_SET)
  541. .fields(asList(
  542. PropertyFieldDefinition.build("key").name("Key").build(),
  543. PropertyFieldDefinition.build("secret.secured").name("Secured").build()))
  544. .build());
  545. propertyDb.insertPropertySet("foo", null, ImmutableMap.of("key", "key1", "secret.secured", "123456"));
  546. ValuesWsResponse result = executeRequestForGlobalProperties();
  547. assertFieldValues(result.getSettings(0), ImmutableMap.of("key", "key1", "secret.secured", "123456"));
  548. }
  549. @Test
  550. public void return_global_settings_from_definitions_when_no_component_and_no_keys() {
  551. logInAsAdmin();
  552. definitions.addComponents(asList(
  553. PropertyDefinition.builder("foo").build(),
  554. PropertyDefinition.builder("secret.secured").build()));
  555. propertyDb.insertProperties(null, null, null, null,
  556. newGlobalPropertyDto().setKey("foo").setValue("one"),
  557. newGlobalPropertyDto().setKey("secret.secured").setValue("password"));
  558. ValuesWsResponse result = executeRequestForGlobalProperties();
  559. assertThat(result.getSettingsList()).extracting(Settings.Setting::getKey).containsOnly("foo", "secret.secured");
  560. }
  561. @Test
  562. public void return_project_settings_from_definitions_when_component_and_no_keys() {
  563. logInAsProjectAdmin();
  564. definitions.addComponents(asList(
  565. PropertyDefinition.builder("foo").onQualifiers(PROJECT).build(),
  566. PropertyDefinition.builder("secret.secured").onQualifiers(PROJECT).build()));
  567. propertyDb.insertProperties(null, project.getKey(), project.name(), project.qualifier(),
  568. newComponentPropertyDto(project).setKey("foo").setValue("one"),
  569. newComponentPropertyDto(project).setKey("secret.secured").setValue("password"));
  570. ValuesWsResponse result = executeRequestForProjectProperties();
  571. assertThat(result.getSettingsList()).extracting(Settings.Setting::getKey).containsOnly("foo", "secret.secured");
  572. }
  573. @Test
  574. public void return_additional_settings_specific_for_scanner_when_no_keys() {
  575. logInAsAdmin();
  576. definitions.addComponent(PropertyDefinition.builder("secret.secured").build());
  577. propertyDb.insertProperties(null, null, null, null,
  578. newGlobalPropertyDto().setKey("sonar.core.id").setValue("ID"),
  579. newGlobalPropertyDto().setKey("sonar.core.startTime").setValue("2017-01-01"));
  580. ValuesWsResponse result = executeRequestForGlobalProperties();
  581. assertThat(result.getSettingsList()).extracting(Settings.Setting::getKey).containsOnly("sonar.core.id", "sonar.core.startTime");
  582. }
  583. @Test
  584. public void return_simple_value_with_non_ascii_characters() {
  585. logIn();
  586. definitions.addComponent(PropertyDefinition
  587. .builder("foo")
  588. .build());
  589. propertyDb.insertProperties(null, null, null, null,
  590. newGlobalPropertyDto().setKey("foo").setValue("fi±∞…"));
  591. ValuesWsResponse result = executeRequestForGlobalProperties("foo");
  592. assertThat(result.getSettings(0).getValue()).isEqualTo("fi±∞…");
  593. }
  594. @Test
  595. public void fail_when_user_has_not_project_browse_permission() {
  596. userSession.logIn("project-admin").addProjectPermission(CODEVIEWER, project);
  597. definitions.addComponent(PropertyDefinition.builder("foo").build());
  598. expectedException.expect(ForbiddenException.class);
  599. executeRequest(project.getDbKey(), "foo");
  600. }
  601. @Test
  602. public void fail_when_deprecated_key_and_new_key_are_used() {
  603. logIn();
  604. definitions.addComponent(PropertyDefinition
  605. .builder("foo")
  606. .deprecatedKey("deprecated")
  607. .build());
  608. propertyDb.insertProperties(null, null, null, null,
  609. newGlobalPropertyDto().setKey("foo").setValue("one"));
  610. expectedException.expect(IllegalArgumentException.class);
  611. expectedException.expectMessage("'foo' and 'deprecated' cannot be used at the same time as they refer to the same setting");
  612. executeRequestForGlobalProperties("foo", "deprecated");
  613. }
  614. @Test
  615. public void fail_when_component_not_found() {
  616. expectedException.expect(NotFoundException.class);
  617. expectedException.expectMessage("Component key 'unknown' not found");
  618. newTester().newRequest()
  619. .setParam("keys", "foo")
  620. .setParam("component", "unknown")
  621. .execute();
  622. }
  623. @Test
  624. public void test_example_json_response() {
  625. logIn();
  626. definitions.addComponent(PropertyDefinition
  627. .builder("sonar.test.jira")
  628. .defaultValue("abc")
  629. .build());
  630. definitions.addComponent(PropertyDefinition
  631. .builder("sonar.autogenerated")
  632. .multiValues(true)
  633. .build());
  634. propertyDb.insertProperties(null, null, null, null,
  635. newGlobalPropertyDto().setKey("sonar.autogenerated").setValue("val1,val2,val3"));
  636. definitions.addComponent(PropertyDefinition
  637. .builder("sonar.demo")
  638. .type(PropertyType.PROPERTY_SET)
  639. .fields(PropertyFieldDefinition.build("text").name("Text").build(),
  640. PropertyFieldDefinition.build("boolean").name("Boolean").build())
  641. .build());
  642. propertyDb.insertPropertySet("sonar.demo", null, ImmutableMap.of("text", "foo", "boolean", "true"), ImmutableMap.of("text", "bar", "boolean", "false"));
  643. String result = newTester().newRequest()
  644. .setParam("keys", "sonar.test.jira,sonar.autogenerated,sonar.demo")
  645. .setMediaType(JSON)
  646. .execute()
  647. .getInput();
  648. JsonAssert.assertJson(newTester().getDef().responseExampleAsString()).isSimilarTo(result);
  649. }
  650. @Test
  651. public void fail_when_using_branch_db_key() {
  652. ComponentDto project = db.components().insertPrivateProject();
  653. userSession.logIn().addProjectPermission(UserRole.USER, project);
  654. ComponentDto branch = db.components().insertProjectBranch(project);
  655. expectedException.expect(NotFoundException.class);
  656. expectedException.expectMessage(format("Component key '%s' not found", branch.getDbKey()));
  657. newTester().newRequest()
  658. .setParam("keys", "foo")
  659. .setParam("component", branch.getDbKey())
  660. .execute();
  661. }
  662. @Test
  663. public void fail_when_setting_key_is_defined_in_sonar_properties() {
  664. ComponentDto project = db.components().insertPrivateProject();
  665. userSession.logIn().addProjectPermission(UserRole.USER, project);
  666. String settingKey = ProcessProperties.Property.JDBC_URL.getKey();
  667. expectedException.expect(IllegalArgumentException.class);
  668. expectedException.expectMessage(format("Setting '%s' can only be used in sonar.properties", settingKey));
  669. newTester().newRequest()
  670. .setParam("keys", settingKey)
  671. .setParam("component", project.getKey())
  672. .execute();
  673. }
  674. @Test
  675. public void test_ws_definition() {
  676. WebService.Action action = newTester().getDef();
  677. assertThat(action).isNotNull();
  678. assertThat(action.isInternal()).isFalse();
  679. assertThat(action.isPost()).isFalse();
  680. assertThat(action.responseExampleAsString()).isNotEmpty();
  681. assertThat(action.params()).extracting(WebService.Param::key).containsExactlyInAnyOrder("keys", "component");
  682. }
  683. @Test
  684. public void global_secured_properties_require_system_admin_permission() {
  685. PropertyDefinition securedDef = PropertyDefinition.builder("my.password.secured").build();
  686. PropertyDefinition standardDef = PropertyDefinition.builder("my.property").build();
  687. definitions.addComponents(asList(securedDef, standardDef));
  688. propertyDb.insertProperties(null, null, null, null,
  689. newGlobalPropertyDto().setKey(securedDef.key()).setValue("securedValue"),
  690. newGlobalPropertyDto().setKey(standardDef.key()).setValue("standardValue"));
  691. // anonymous
  692. WsActionTester tester = newTester();
  693. ValuesWsResponse response = executeRequest(tester, null, securedDef.key(), standardDef.key());
  694. assertThat(response.getSettingsList()).extracting(Settings.Setting::getKey).containsExactly("my.property");
  695. // only scan global permission
  696. userSession.logIn()
  697. .addPermission(GlobalPermission.SCAN);
  698. response = executeRequest(tester, null, securedDef.key(), standardDef.key());
  699. assertThat(response.getSettingsList()).extracting(Settings.Setting::getKey).containsExactly("my.password.secured", "my.property");
  700. assertThat(response.getSettingsList()).extracting(Settings.Setting::hasValue).containsExactly(false, true);
  701. // global administrator
  702. userSession.logIn()
  703. .addPermission(GlobalPermission.ADMINISTER);
  704. response = executeRequest(tester, null, securedDef.key(), standardDef.key());
  705. assertThat(response.getSettingsList()).extracting(Settings.Setting::getKey).containsExactly("my.password.secured", "my.property");
  706. assertThat(response.getSettingsList()).extracting(Settings.Setting::hasValue).containsExactly(false, true);
  707. // system administrator
  708. userSession.logIn().setSystemAdministrator();
  709. response = executeRequest(tester, null, securedDef.key(), standardDef.key());
  710. assertThat(response.getSettingsList()).extracting(Settings.Setting::getKey).containsExactly("my.password.secured", "my.property");
  711. assertThat(response.getSettingsList()).extracting(Settings.Setting::hasValue).containsExactly(false, true);
  712. }
  713. private ValuesWsResponse executeRequestForComponentProperties(ComponentDto componentDto, String... keys) {
  714. return executeRequest(componentDto.getDbKey(), keys);
  715. }
  716. private ValuesWsResponse executeRequestForProjectProperties(String... keys) {
  717. return executeRequest(project.getDbKey(), keys);
  718. }
  719. private ValuesWsResponse executeRequestForGlobalProperties(String... keys) {
  720. return executeRequest(null, keys);
  721. }
  722. private ValuesWsResponse executeRequest(@Nullable String componentKey, String... keys) {
  723. return executeRequest(newTester(), componentKey, keys);
  724. }
  725. private ValuesWsResponse executeRequest(WsActionTester tester, @Nullable String componentKey, String... keys) {
  726. TestRequest request = tester.newRequest();
  727. if (keys.length > 0) {
  728. request.setParam("keys", COMMA_JOINER.join(keys));
  729. }
  730. if (componentKey != null) {
  731. request.setParam("component", componentKey);
  732. }
  733. return request.executeProtobuf(ValuesWsResponse.class);
  734. }
  735. private void logIn() {
  736. userSession.logIn();
  737. }
  738. private void logInAsProjectUser() {
  739. userSession.logIn().addProjectPermission(USER, project);
  740. }
  741. private void logInAsAdmin() {
  742. userSession.logIn().setSystemAdministrator();
  743. }
  744. private void logInAsProjectAdmin() {
  745. userSession.logIn()
  746. .addProjectPermission(ADMIN, project)
  747. .addProjectPermission(USER, project);
  748. }
  749. private void assertSetting(Settings.Setting setting, String expectedKey, String expectedValue, boolean expectedInherited) {
  750. assertThat(setting.getKey()).isEqualTo(expectedKey);
  751. assertThat(setting.getValue()).isEqualTo(expectedValue);
  752. assertThat(setting.getInherited()).isEqualTo(expectedInherited);
  753. }
  754. private void assertFieldValues(Settings.Setting setting, Map<String, String>... fieldsValues) {
  755. assertThat(setting.getFieldValues().getFieldValuesList()).hasSize(fieldsValues.length);
  756. int index = 0;
  757. for (Settings.FieldValues.Value fieldsValue : setting.getFieldValues().getFieldValuesList()) {
  758. assertThat(fieldsValue.getValue()).isEqualTo(fieldsValues[index]);
  759. index++;
  760. }
  761. }
  762. private void assertParentValue(Settings.Setting setting, @Nullable String parentValue) {
  763. if (parentValue == null) {
  764. assertThat(setting.getParentValueOneOfCase()).isEqualTo(PARENTVALUEONEOF_NOT_SET);
  765. } else {
  766. assertThat(setting.getParentValue()).isEqualTo(parentValue);
  767. }
  768. }
  769. private void assertParentValues(Settings.Setting setting, String... parentValues) {
  770. if (parentValues.length == 0) {
  771. assertThat(setting.getParentValueOneOfCase()).isEqualTo(PARENTVALUEONEOF_NOT_SET);
  772. } else {
  773. assertThat(setting.getParentValues().getValuesList()).containsOnly(parentValues);
  774. }
  775. }
  776. private void assertParentFieldValues(Settings.Setting setting, Map<String, String>... fieldsValues) {
  777. if (fieldsValues.length == 0) {
  778. assertThat(setting.getParentValueOneOfCase()).isEqualTo(PARENTVALUEONEOF_NOT_SET);
  779. } else {
  780. assertThat(setting.getParentFieldValues().getFieldValuesList()).hasSize(fieldsValues.length);
  781. int index = 0;
  782. for (Settings.FieldValues.Value fieldsValue : setting.getParentFieldValues().getFieldValuesList()) {
  783. assertThat(fieldsValue.getValue()).isEqualTo(fieldsValues[index]);
  784. index++;
  785. }
  786. }
  787. }
  788. private WsActionTester newTester() {
  789. MapSettings settings = new MapSettings();
  790. Configuration configuration = settings.asConfig();
  791. return new WsActionTester(new ValuesAction(dbClient, TestComponentFinder.from(db), userSession, definitions, support, configuration));
  792. }
  793. private WsActionTester newSonarCloudTester() {
  794. MapSettings settings = new MapSettings().setProperty(SONARCLOUD_ENABLED.getKey(), "true");
  795. Configuration configuration = settings.asConfig();
  796. return new WsActionTester(new ValuesAction(dbClient, TestComponentFinder.from(db), userSession, definitions, support, configuration));
  797. }
  798. }