From 2e3c74b1b96f5a0475fc7c3482621412aa765192 Mon Sep 17 00:00:00 2001 From: Julien Lancelot Date: Mon, 29 Aug 2016 18:37:42 +0200 Subject: [PATCH] SONAR-7975 Return parentValue, parentValues and parentFieldsValues --- .../java/it/settings/PropertySetsTest.java | 4 +- .../test/java/it/settings/SettingsTest.java | 4 +- .../server/settings/ws/ValuesAction.java | 67 +++-- .../server/settings/ws/values-example.json | 5 +- .../server/settings/ws/ValuesActionTest.java | 251 +++++++++++++----- .../sonar/db/property/PropertyDbTester.java | 39 +++ sonar-ws/src/main/protobuf/ws-settings.proto | 12 +- 7 files changed, 283 insertions(+), 99 deletions(-) diff --git a/it/it-tests/src/test/java/it/settings/PropertySetsTest.java b/it/it-tests/src/test/java/it/settings/PropertySetsTest.java index 0252f46788a9..ea55aa7c17cf 100644 --- a/it/it-tests/src/test/java/it/settings/PropertySetsTest.java +++ b/it/it-tests/src/test/java/it/settings/PropertySetsTest.java @@ -120,9 +120,9 @@ public void delete_property_set() throws Exception { private void assertPropertySet(String baseSettingKey, List>... fieldsValues) { Settings.Setting setting = getSetting(baseSettingKey); - assertThat(setting.getFieldsValues().getFieldsValuesList()).hasSize(fieldsValues.length); + assertThat(setting.getFieldsValues().getFieldValuesList()).hasSize(fieldsValues.length); int index = 0; - for (Settings.FieldsValues.Value fieldsValue : setting.getFieldsValues().getFieldsValuesList()) { + for (Settings.FieldValues.Value fieldsValue : setting.getFieldsValues().getFieldValuesList()) { assertThat(fieldsValue.getValue()).containsOnly(fieldsValues[index].toArray(new Map.Entry[] {})); index++; } diff --git a/it/it-tests/src/test/java/it/settings/SettingsTest.java b/it/it-tests/src/test/java/it/settings/SettingsTest.java index a0df434cdac5..d49fafd15fb5 100644 --- a/it/it-tests/src/test/java/it/settings/SettingsTest.java +++ b/it/it-tests/src/test/java/it/settings/SettingsTest.java @@ -68,14 +68,14 @@ public void should_get_settings_default_value() { @Test public void global_property_change_extension_point() throws IOException { orchestrator.getServer().adminWsClient().post("api/properties/create?id=globalPropertyChange.received&value=NEWVALUE"); - assertThat(FileUtils.readFileToString(orchestrator.getServer().getLogs()).contains("Received change: NEWVALUE")); + assertThat(FileUtils.readFileToString(orchestrator.getServer().getLogs())).contains("Received change: [key=globalPropertyChange.received, newValue=NEWVALUE]"); } @Test public void get_default_value() throws Exception { Settings.Setting setting = getSetting(PLUGIN_SETTING_KEY); assertThat(setting.getValue()).isEqualTo("aDefaultValue"); - assertThat(setting.getDefault()).isTrue(); + assertThat(setting.getInherited()).isTrue(); } @Test diff --git a/server/sonar-server/src/main/java/org/sonar/server/settings/ws/ValuesAction.java b/server/sonar-server/src/main/java/org/sonar/server/settings/ws/ValuesAction.java index e12b72add4c7..0e853bbcdeab 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/settings/ws/ValuesAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/settings/ws/ValuesAction.java @@ -21,7 +21,6 @@ import com.google.common.base.Splitter; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -143,10 +142,6 @@ private void checkAdminPermission(Optional component) { } private List loadSettings(DbSession dbSession, Optional component, Set keys) { - if (keys.isEmpty()) { - return Collections.emptyList(); - } - // List of settings must be kept in the following orders : default -> global -> component List settings = new ArrayList<>(); settings.addAll(loadDefaultSettings(keys)); @@ -175,15 +170,16 @@ private Map getKeysToDisplayMap(Set keys) { private static class ValuesResponseBuilder { private final List settings; - private final Optional component; + private final Optional requestedComponent; private final ValuesWsResponse.Builder valuesWsBuilder = ValuesWsResponse.newBuilder(); private final Map settingsBuilderByKey = new HashMap<>(); + private final Map settingsByParentKey = new HashMap<>(); private final Map keysToDisplayMap; - ValuesResponseBuilder(List settings, Optional component, Map keysToDisplayMap) { + ValuesResponseBuilder(List settings, Optional requestedComponent, Map keysToDisplayMap) { this.settings = settings; - this.component = component; + this.requestedComponent = requestedComponent; this.keysToDisplayMap = keysToDisplayMap; } @@ -196,9 +192,9 @@ ValuesWsResponse build() { private void processSettings() { settings.forEach(setting -> { Settings.Setting.Builder valueBuilder = getOrCreateValueBuilder(keysToDisplayMap.get(setting.getKey())); - valueBuilder.setDefault(setting.isDefault()); setInherited(setting, valueBuilder); setValue(setting, valueBuilder); + setParent(setting, valueBuilder); }); } @@ -211,6 +207,14 @@ private Settings.Setting.Builder getOrCreateValueBuilder(String key) { return valueBuilder; } + private void setInherited(Setting setting, Settings.Setting.Builder valueBuilder) { + boolean isDefault = setting.isDefault(); + boolean isGlobal = !requestedComponent.isPresent(); + boolean isOnComponent = requestedComponent.isPresent() && Objects.equals(setting.getComponentId(), requestedComponent.get().getId()); + boolean isSet = isGlobal || isOnComponent; + valueBuilder.setInherited(isDefault || !isSet); + } + private void setValue(Setting setting, Settings.Setting.Builder valueBuilder) { PropertyDefinition definition = setting.getDefinition(); String value = setting.getValue(); @@ -219,25 +223,46 @@ private void setValue(Setting setting, Settings.Setting.Builder valueBuilder) { return; } if (definition.type().equals(PROPERTY_SET)) { - Settings.FieldsValues.Builder builder = Settings.FieldsValues.newBuilder(); - for (Map propertySetMap : setting.getPropertySets()) { - builder.addFieldsValuesBuilder().putAllValue(propertySetMap); - } - valueBuilder.setFieldsValues(builder); + valueBuilder.setFieldsValues(createFieldValuesBuilder(setting.getPropertySets())); } else if (definition.multiValues()) { - List values = COMMA_SPLITTER.splitToList(value).stream().map(v -> v.replace(COMMA_ENCODED_VALUE, ",")).collect(Collectors.toList()); - valueBuilder.setValues(Settings.Values.newBuilder().addAllValues(values)); + valueBuilder.setValues(createValuesBuilder(value)); } else { valueBuilder.setValue(value); } } - private void setInherited(Setting setting, Settings.Setting.Builder valueBuilder) { - if (setting.isDefault()) { - valueBuilder.setInherited(false); - } else { - valueBuilder.setInherited(component.isPresent() && !Objects.equals(setting.getComponentId(), component.get().getId())); + private void setParent(Setting setting, Settings.Setting.Builder valueBuilder) { + Setting parent = settingsByParentKey.get(setting.getKey()); + if (parent != null) { + String value = valueBuilder.getInherited() ? setting.getValue() : parent.getValue(); + PropertyDefinition definition = setting.getDefinition(); + if (definition == null) { + valueBuilder.setParentValue(value); + return; + } + + if (definition.type().equals(PROPERTY_SET)) { + valueBuilder.setParentFieldValues(createFieldValuesBuilder(valueBuilder.getInherited() ? setting.getPropertySets() : parent.getPropertySets())); + } else if (definition.multiValues()) { + valueBuilder.setParentValues(createValuesBuilder(value)); + } else { + valueBuilder.setParentValue(value); + } + } + settingsByParentKey.put(setting.getKey(), setting); + } + + private static Settings.Values.Builder createValuesBuilder(String value) { + List values = COMMA_SPLITTER.splitToList(value).stream().map(v -> v.replace(COMMA_ENCODED_VALUE, ",")).collect(Collectors.toList()); + return Settings.Values.newBuilder().addAllValues(values); + } + + private static Settings.FieldValues.Builder createFieldValuesBuilder(List> fieldValues) { + Settings.FieldValues.Builder builder = Settings.FieldValues.newBuilder(); + for (Map propertySetMap : fieldValues) { + builder.addFieldValuesBuilder().putAllValue(propertySetMap); } + return builder; } } diff --git a/server/sonar-server/src/main/resources/org/sonar/server/settings/ws/values-example.json b/server/sonar-server/src/main/resources/org/sonar/server/settings/ws/values-example.json index 45fbda86e0c2..02d668904ea8 100644 --- a/server/sonar-server/src/main/resources/org/sonar/server/settings/ws/values-example.json +++ b/server/sonar-server/src/main/resources/org/sonar/server/settings/ws/values-example.json @@ -3,8 +3,7 @@ { "key": "sonar.test.jira", "value": "abc", - "default": true, - "inherited": false + "inherited": true }, { "key": "sonar.autogenerated", @@ -13,7 +12,6 @@ "val2", "val3" ], - "default": false, "inherited": false }, { @@ -28,7 +26,6 @@ "text": "bar" } ], - "default": false, "inherited": false } ] diff --git a/server/sonar-server/src/test/java/org/sonar/server/settings/ws/ValuesActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/settings/ws/ValuesActionTest.java index 01eb10674ffc..83f8591b936d 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/settings/ws/ValuesActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/settings/ws/ValuesActionTest.java @@ -21,7 +21,9 @@ package org.sonar.server.settings.ws; import com.google.common.base.Joiner; +import com.google.common.collect.ImmutableMap; import java.io.IOException; +import java.util.Map; import javax.annotation.Nullable; import org.junit.Before; import org.junit.Rule; @@ -34,11 +36,10 @@ import org.sonar.api.server.ws.WebService; import org.sonar.api.utils.System2; import org.sonar.db.DbClient; -import org.sonar.db.DbSession; import org.sonar.db.DbTester; import org.sonar.db.component.ComponentDbTester; import org.sonar.db.component.ComponentDto; -import org.sonar.db.property.PropertyDto; +import org.sonar.db.property.PropertyDbTester; import org.sonar.server.component.ComponentFinder; import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.tester.UserSessionRule; @@ -51,7 +52,6 @@ import static java.util.Arrays.asList; import static org.assertj.core.api.Java6Assertions.assertThat; -import static org.assertj.core.api.Java6Assertions.entry; import static org.sonar.api.web.UserRole.ADMIN; import static org.sonar.api.web.UserRole.USER; import static org.sonar.core.permission.GlobalPermissions.DASHBOARD_SHARING; @@ -76,7 +76,7 @@ public class ValuesActionTest { public DbTester db = DbTester.create(System2.INSTANCE); DbClient dbClient = db.getDbClient(); - DbSession dbSession = db.getSession(); + PropertyDbTester propertyDb = new PropertyDbTester(db); ComponentDbTester componentDb = new ComponentDbTester(db); PropertyDefinitions propertyDefinitions = new PropertyDefinitions(); SettingsFinder settingsFinder = new SettingsFinder(dbClient, propertyDefinitions); @@ -96,7 +96,7 @@ public void return_simple_value() throws Exception { propertyDefinitions.addComponent(PropertyDefinition .builder("foo") .build()); - insertProperties(newGlobalPropertyDto().setKey("foo").setValue("one")); + propertyDb.insertProperties(newGlobalPropertyDto().setKey("foo").setValue("one")); ValuesWsResponse result = executeRequestForGlobalProperties("foo"); @@ -106,7 +106,7 @@ public void return_simple_value() throws Exception { assertThat(value.getValue()).isEqualTo("one"); assertThat(value.hasValues()).isFalse(); assertThat(value.hasFieldsValues()).isFalse(); - assertThat(value.getDefault()).isFalse(); + assertThat(value.getInherited()).isFalse(); } @Test @@ -123,7 +123,7 @@ public void return_multi_values() throws Exception { propertyDefinitions.addComponent(PropertyDefinition.builder("global") .multiValues(true) .build()); - insertProperties(newGlobalPropertyDto().setKey("global").setValue("three,four")); + propertyDb.insertProperties(newGlobalPropertyDto().setKey("global").setValue("three,four")); ValuesWsResponse result = executeRequestForGlobalProperties("default", "global"); assertThat(result.getSettingsList()).hasSize(2); @@ -145,7 +145,7 @@ public void return_multi_values() throws Exception { public void return_multi_value_with_coma() throws Exception { setUserAsSystemAdmin(); propertyDefinitions.addComponent(PropertyDefinition.builder("global").multiValues(true).build()); - insertProperties(newGlobalPropertyDto().setKey("global").setValue("three,four%2Cfive")); + propertyDb.insertProperties(newGlobalPropertyDto().setKey("global").setValue("three,four%2Cfive")); ValuesWsResponse result = executeRequestForGlobalProperties("global"); @@ -165,11 +165,7 @@ public void return_property_set() throws Exception { PropertyFieldDefinition.build("key").name("Key").build(), PropertyFieldDefinition.build("size").name("Size").build())) .build()); - insertProperties( - newGlobalPropertyDto().setKey("foo").setValue("1,2"), - newGlobalPropertyDto().setKey("foo.1.key").setValue("key1"), - newGlobalPropertyDto().setKey("foo.1.size").setValue("size1"), - newGlobalPropertyDto().setKey("foo.2.key").setValue("key2")); + propertyDb.insertPropertySet("foo", null, ImmutableMap.of("key", "key1", "size", "size1"), ImmutableMap.of("key", "key2")); ValuesWsResponse result = executeRequestForGlobalProperties("foo"); @@ -178,10 +174,7 @@ public void return_property_set() throws Exception { assertThat(value.getKey()).isEqualTo("foo"); assertThat(value.hasValue()).isFalse(); assertThat(value.hasValues()).isFalse(); - - assertThat(value.getFieldsValues().getFieldsValuesList()).hasSize(2); - assertThat(value.getFieldsValues().getFieldsValuesList().get(0).getValue()).containsOnly(entry("key", "key1"), entry("size", "size1")); - assertThat(value.getFieldsValues().getFieldsValuesList().get(1).getValue()).containsOnly(entry("key", "key2")); + assertFieldValues(value, ImmutableMap.of("key", "key1", "size", "size1"), ImmutableMap.of("key", "key2")); } @Test @@ -194,11 +187,7 @@ public void return_property_set_for_component() throws Exception { PropertyFieldDefinition.build("key").name("Key").build(), PropertyFieldDefinition.build("size").name("Size").build())) .build()); - insertProperties( - newComponentPropertyDto(project).setKey("foo").setValue("1,2"), - newComponentPropertyDto(project).setKey("foo.1.key").setValue("key1"), - newComponentPropertyDto(project).setKey("foo.1.size").setValue("size1"), - newComponentPropertyDto(project).setKey("foo.2.key").setValue("key2")); + propertyDb.insertPropertySet("foo", project, ImmutableMap.of("key", "key1", "size", "size1"), ImmutableMap.of("key", "key2")); ValuesWsResponse result = executeRequestForProjectProperties("foo"); @@ -207,10 +196,7 @@ public void return_property_set_for_component() throws Exception { assertThat(value.getKey()).isEqualTo("foo"); assertThat(value.hasValue()).isFalse(); assertThat(value.hasValues()).isFalse(); - - assertThat(value.getFieldsValues().getFieldsValuesList()).hasSize(2); - assertThat(value.getFieldsValues().getFieldsValuesList().get(0).getValue()).containsOnly(entry("key", "key1"), entry("size", "size1")); - assertThat(value.getFieldsValues().getFieldsValuesList().get(1).getValue()).containsOnly(entry("key", "key2")); + assertFieldValues(value, ImmutableMap.of("key", "key1", "size", "size1"), ImmutableMap.of("key", "key2")); } @Test @@ -224,28 +210,28 @@ public void return_default_values() throws Exception { ValuesWsResponse result = executeRequestForGlobalProperties("foo"); assertThat(result.getSettingsList()).hasSize(1); - assertSetting(result.getSettings(0), "foo", "default", true, false); + assertSetting(result.getSettings(0), "foo", "default", true); } @Test public void return_global_values() throws Exception { setUserAsSystemAdmin(); propertyDefinitions.addComponent(PropertyDefinition.builder("property").defaultValue("default").build()); - insertProperties( + propertyDb.insertProperties( // The property is overriding default value newGlobalPropertyDto().setKey("property").setValue("one")); ValuesWsResponse result = executeRequestForGlobalProperties("property"); assertThat(result.getSettingsList()).hasSize(1); - assertSetting(result.getSettings(0), "property", "one", false, false); + assertSetting(result.getSettings(0), "property", "one", false); } @Test public void return_project_values() throws Exception { setUserAsSystemAdmin(); propertyDefinitions.addComponent(PropertyDefinition.builder("property").defaultValue("default").build()); - insertProperties( + propertyDb.insertProperties( newGlobalPropertyDto().setKey("property").setValue("one"), // The property is overriding global value newComponentPropertyDto(project).setKey("property").setValue("two")); @@ -253,7 +239,7 @@ public void return_project_values() throws Exception { ValuesWsResponse result = executeRequestForProjectProperties("property"); assertThat(result.getSettingsList()).hasSize(1); - assertSetting(result.getSettings(0), "property", "two", false, false); + assertSetting(result.getSettings(0), "property", "two", false); } @Test @@ -261,25 +247,25 @@ public void return_is_inherited_to_true_when_property_is_defined_only_at_global_ setUserAsSystemAdmin(); propertyDefinitions.addComponent(PropertyDefinition.builder("property").defaultValue("default").build()); // The property is not defined on project - insertProperties(newGlobalPropertyDto().setKey("property").setValue("one")); + propertyDb.insertProperties(newGlobalPropertyDto().setKey("property").setValue("one")); ValuesWsResponse result = executeRequestForProjectProperties("property"); assertThat(result.getSettingsList()).hasSize(1); - assertSetting(result.getSettings(0), "property", "one", false, true); + assertSetting(result.getSettings(0), "property", "one", true); } @Test public void return_values_even_if_no_property_definition() throws Exception { setUserAsSystemAdmin(); - insertProperties(newGlobalPropertyDto().setKey("globalPropertyWithoutDefinition").setValue("value")); + propertyDb.insertProperties(newGlobalPropertyDto().setKey("globalPropertyWithoutDefinition").setValue("value")); ValuesWsResponse result = executeRequestForGlobalProperties("globalPropertyWithoutDefinition"); Settings.Setting globalPropertyWithoutDefinitionValue = result.getSettings(0); assertThat(globalPropertyWithoutDefinitionValue.getKey()).isEqualTo("globalPropertyWithoutDefinition"); assertThat(globalPropertyWithoutDefinitionValue.getValue()).isEqualTo("value"); - assertThat(globalPropertyWithoutDefinitionValue.getDefault()).isFalse(); + assertThat(globalPropertyWithoutDefinitionValue.getInherited()).isFalse(); } @Test @@ -295,13 +281,13 @@ public void return_empty_when_property_def_exists_but_no_value() throws Exceptio } @Test - public void does_return_nothing_when_unknown_keys() throws Exception { + public void return_nothing_when_unknown_keys() throws Exception { setUserAsSystemAdmin(); propertyDefinitions.addComponent(PropertyDefinition .builder("foo") .defaultValue("default") .build()); - insertProperties(newGlobalPropertyDto().setKey("bar").setValue("")); + propertyDb.insertProperties(newGlobalPropertyDto().setKey("bar").setValue("")); ValuesWsResponse result = executeRequestForGlobalProperties("unknown"); @@ -313,7 +299,7 @@ public void return_module_values() throws Exception { setUserAsSystemAdmin(); ComponentDto module = componentDb.insertComponent(newModuleDto(project)); propertyDefinitions.addComponent(PropertyDefinition.builder("property").defaultValue("default").build()); - insertProperties( + propertyDb.insertProperties( newGlobalPropertyDto().setKey("property").setValue("one"), // The property is overriding global value newComponentPropertyDto(module).setKey("property").setValue("two")); @@ -321,31 +307,141 @@ public void return_module_values() throws Exception { ValuesWsResponse result = executeRequestForComponentProperties(module, "property"); assertThat(result.getSettingsList()).hasSize(1); - assertSetting(result.getSettings(0), "property", "two", false, false); + assertSetting(result.getSettings(0), "property", "two", false); } @Test - public void return_inherited_values_on_sub_module() throws Exception { + public void return_inherited_values_on_module() throws Exception { setUserAsSystemAdmin(); ComponentDto module = componentDb.insertComponent(newModuleDto(project)); - ComponentDto subModule = componentDb.insertComponent(newModuleDto(module)); propertyDefinitions.addComponents(asList( PropertyDefinition.builder("defaultProperty").defaultValue("default").build(), PropertyDefinition.builder("globalProperty").build(), PropertyDefinition.builder("projectProperty").build(), PropertyDefinition.builder("moduleProperty").build())); - insertProperties( + propertyDb.insertProperties( newGlobalPropertyDto().setKey("globalProperty").setValue("global"), newComponentPropertyDto(project).setKey("projectProperty").setValue("project"), newComponentPropertyDto(module).setKey("moduleProperty").setValue("module")); - ValuesWsResponse result = executeRequestForComponentProperties(subModule, "defaultProperty", "globalProperty", "projectProperty", "moduleProperty"); + ValuesWsResponse result = executeRequestForComponentProperties(module, "defaultProperty", "globalProperty", "projectProperty", "moduleProperty"); assertThat(result.getSettingsList()).hasSize(4); - assertSetting(result.getSettings(0), "defaultProperty", "default", true, false); - assertSetting(result.getSettings(1), "globalProperty", "global", false, true); - assertSetting(result.getSettings(2), "projectProperty", "project", false, true); - assertSetting(result.getSettings(3), "moduleProperty", "module", false, true); + assertSetting(result.getSettings(0), "defaultProperty", "default", true); + assertSetting(result.getSettings(1), "globalProperty", "global", true); + assertSetting(result.getSettings(2), "projectProperty", "project", true); + assertSetting(result.getSettings(3), "moduleProperty", "module", false); + } + + @Test + public void return_inherited_values_on_global_setting() throws Exception { + setUserAsSystemAdmin(); + propertyDefinitions.addComponents(asList( + PropertyDefinition.builder("defaultProperty").defaultValue("default").build(), + PropertyDefinition.builder("globalProperty").build())); + propertyDb.insertProperties( + newGlobalPropertyDto().setKey("globalProperty").setValue("global")); + + ValuesWsResponse result = executeRequestForGlobalProperties("defaultProperty", "globalProperty"); + + assertThat(result.getSettingsList()).hasSize(2); + assertSetting(result.getSettings(0), "defaultProperty", "default", true); + assertSetting(result.getSettings(1), "globalProperty", "global", false); + } + + @Test + public void return_parent_value() throws Exception { + setUserAsSystemAdmin(); + ComponentDto module = componentDb.insertComponent(newModuleDto(project)); + ComponentDto subModule = componentDb.insertComponent(newModuleDto(module)); + propertyDefinitions.addComponents(asList( + PropertyDefinition.builder("foo").defaultValue("default").build())); + propertyDb.insertProperties( + newGlobalPropertyDto().setKey("foo").setValue("global"), + newComponentPropertyDto(project).setKey("foo").setValue("project"), + newComponentPropertyDto(module).setKey("foo").setValue("module")); + + assertParentValue(executeRequestForComponentProperties(subModule, "foo").getSettings(0), "module"); + assertParentValue(executeRequestForComponentProperties(module, "foo").getSettings(0), "project"); + assertParentValue(executeRequestForComponentProperties(project, "foo").getSettings(0), "global"); + assertParentValue(executeRequestForGlobalProperties("foo").getSettings(0), "default"); + } + + @Test + public void return_parent_values() throws Exception { + setUserAsSystemAdmin(); + ComponentDto module = componentDb.insertComponent(newModuleDto(project)); + ComponentDto subModule = componentDb.insertComponent(newModuleDto(module)); + propertyDefinitions.addComponents(asList( + PropertyDefinition.builder("foo").defaultValue("default1,default2").multiValues(true).build())); + propertyDb.insertProperties( + newGlobalPropertyDto().setKey("foo").setValue("global1,global2"), + newComponentPropertyDto(project).setKey("foo").setValue("project1,project2"), + newComponentPropertyDto(module).setKey("foo").setValue("module1,module2")); + + assertParentValues(executeRequestForComponentProperties(subModule, "foo").getSettings(0), "module1", "module2"); + assertParentValues(executeRequestForComponentProperties(module, "foo").getSettings(0), "project1", "project2"); + assertParentValues(executeRequestForComponentProperties(project, "foo").getSettings(0), "global1", "global2"); + assertParentValues(executeRequestForGlobalProperties("foo").getSettings(0), "default1", "default2"); + } + + @Test + public void return_parent_field_values() throws Exception { + setUserAsSystemAdmin(); + ComponentDto module = componentDb.insertComponent(newModuleDto(project)); + ComponentDto subModule = componentDb.insertComponent(newModuleDto(module)); + propertyDefinitions.addComponent(PropertyDefinition + .builder("foo") + .type(PropertyType.PROPERTY_SET) + .fields(asList( + PropertyFieldDefinition.build("key").name("Key").build(), + PropertyFieldDefinition.build("size").name("Size").build())) + .build()); + propertyDb.insertPropertySet("foo", null, ImmutableMap.of("key", "keyG1", "size", "sizeG1")); + propertyDb.insertPropertySet("foo", project, ImmutableMap.of("key", "keyP1", "size", "sizeP1")); + propertyDb.insertPropertySet("foo", module, ImmutableMap.of("key", "keyM1", "size", "sizeM1")); + + assertParentFieldValues(executeRequestForComponentProperties(subModule, "foo").getSettings(0), ImmutableMap.of("key", "keyM1", "size", "sizeM1")); + assertParentFieldValues(executeRequestForComponentProperties(module, "foo").getSettings(0), ImmutableMap.of("key", "keyP1", "size", "sizeP1")); + assertParentFieldValues(executeRequestForComponentProperties(project, "foo").getSettings(0), ImmutableMap.of("key", "keyG1", "size", "sizeG1")); + assertParentFieldValues(executeRequestForGlobalProperties("foo").getSettings(0)); + } + + @Test + public void return_no_parent_value() throws Exception { + setUserAsSystemAdmin(); + ComponentDto module = componentDb.insertComponent(newModuleDto(project)); + ComponentDto subModule = componentDb.insertComponent(newModuleDto(module)); + propertyDefinitions.addComponents(asList( + PropertyDefinition.builder("simple").build(), + PropertyDefinition.builder("multi").multiValues(true).build(), + PropertyDefinition.builder("set") + .type(PropertyType.PROPERTY_SET) + .fields(asList( + PropertyFieldDefinition.build("key").name("Key").build(), + PropertyFieldDefinition.build("size").name("Size").build())) + .build())); + propertyDb.insertProperties( + newComponentPropertyDto(module).setKey("simple").setValue("module"), + newComponentPropertyDto(module).setKey("multi").setValue("module1,module2")); + propertyDb.insertPropertySet("set", module, ImmutableMap.of("key", "keyM1", "size", "sizeM1")); + + assertParentValue(executeRequestForComponentProperties(subModule, "simple").getSettings(0), null); + assertParentValues(executeRequestForComponentProperties(subModule, "multi").getSettings(0)); + assertParentFieldValues(executeRequestForComponentProperties(subModule, "set").getSettings(0)); + } + + @Test + public void return_parent_value_when_no_definition() throws Exception { + setUserAsSystemAdmin(); + ComponentDto module = componentDb.insertComponent(newModuleDto(project)); + propertyDb.insertProperties( + newGlobalPropertyDto().setKey("foo").setValue("global"), + newComponentPropertyDto(project).setKey("foo").setValue("project")); + + assertParentValue(executeRequestForComponentProperties(module, "foo").getSettings(0), "project"); + assertParentValue(executeRequestForComponentProperties(project, "foo").getSettings(0), "global"); + assertParentValue(executeRequestForGlobalProperties("foo").getSettings(0), null); } @Test @@ -355,7 +451,7 @@ public void return_value_of_deprecated_key() throws Exception { .builder("foo") .deprecatedKey("deprecated") .build()); - insertProperties(newGlobalPropertyDto().setKey("foo").setValue("one")); + propertyDb.insertProperties(newGlobalPropertyDto().setKey("foo").setValue("one")); ValuesWsResponse result = executeRequestForGlobalProperties("deprecated"); @@ -376,19 +472,14 @@ public void test_example_json_response() { .builder("sonar.autogenerated") .multiValues(true) .build()); - insertProperties(newGlobalPropertyDto().setKey("sonar.autogenerated").setValue("val1,val2,val3")); + propertyDb.insertProperties(newGlobalPropertyDto().setKey("sonar.autogenerated").setValue("val1,val2,val3")); propertyDefinitions.addComponent(PropertyDefinition .builder("sonar.demo") .type(PropertyType.PROPERTY_SET) .fields(PropertyFieldDefinition.build("text").name("Text").build(), PropertyFieldDefinition.build("boolean").name("Boolean").build()) .build()); - insertProperties( - newGlobalPropertyDto().setKey("sonar.demo").setValue("1,2"), - newGlobalPropertyDto().setKey("sonar.demo.1.text").setValue("foo"), - newGlobalPropertyDto().setKey("sonar.demo.1.boolean").setValue("true"), - newGlobalPropertyDto().setKey("sonar.demo.2.text").setValue("bar"), - newGlobalPropertyDto().setKey("sonar.demo.2.boolean").setValue("false")); + propertyDb.insertPropertySet("sonar.demo", null, ImmutableMap.of("text", "foo", "boolean", "true"), ImmutableMap.of("text", "bar", "boolean", "false")); String result = ws.newRequest() .setParam("keys", "sonar.test.jira,sonar.autogenerated,sonar.demo") @@ -435,7 +526,7 @@ public void fail_when_deprecated_key_and_new_key_are_used() throws Exception { .builder("foo") .deprecatedKey("deprecated") .build()); - insertProperties(newGlobalPropertyDto().setKey("foo").setValue("one")); + propertyDb.insertProperties(newGlobalPropertyDto().setKey("foo").setValue("one")); expectedException.expect(IllegalArgumentException.class); expectedException.expectMessage("'foo' and 'deprecated' cannot be used at the same time as they refer to the same setting"); @@ -490,18 +581,48 @@ private void setUserAsProjectAdmin() { userSession.login("project-admin").addProjectUuidPermissions(ADMIN, project.uuid()); } - private void insertProperties(PropertyDto... properties) { - for (PropertyDto propertyDto : properties) { - dbClient.propertiesDao().insertProperty(dbSession, propertyDto); - } - dbSession.commit(); - } - - private void assertSetting(Settings.Setting setting, String expectedKey, String expectedValue, boolean expectedDefault, boolean expectedInherited) { + private void assertSetting(Settings.Setting setting, String expectedKey, String expectedValue, boolean expectedInherited) { assertThat(setting.getKey()).isEqualTo(expectedKey); assertThat(setting.getValue()).isEqualTo(expectedValue); - assertThat(setting.getDefault()).isEqualTo(expectedDefault); assertThat(setting.getInherited()).isEqualTo(expectedInherited); } + private void assertFieldValues(Settings.Setting setting, Map... fieldsValues) { + assertThat(setting.getFieldsValues().getFieldValuesList()).hasSize(fieldsValues.length); + int index = 0; + for (Settings.FieldValues.Value fieldsValue : setting.getFieldsValues().getFieldValuesList()) { + assertThat(fieldsValue.getValue()).isEqualTo(fieldsValues[index]); + index++; + } + } + + private void assertParentValue(Settings.Setting setting, @Nullable String parentValue) { + if (parentValue == null) { + assertThat(setting.hasParentValue()).isFalse(); + } else { + assertThat(setting.getParentValue()).isEqualTo(parentValue); + } + } + + private void assertParentValues(Settings.Setting setting, String... parentValues) { + if (parentValues.length == 0) { + assertThat(setting.hasParentValues()).isFalse(); + } else { + assertThat(setting.getParentValues().getValuesList()).containsOnly(parentValues); + } + } + + private void assertParentFieldValues(Settings.Setting setting, Map... fieldsValues) { + if (fieldsValues.length == 0) { + assertThat(setting.hasParentFieldValues()).isFalse(); + } else { + assertThat(setting.getParentFieldValues().getFieldValuesList()).hasSize(fieldsValues.length); + int index = 0; + for (Settings.FieldValues.Value fieldsValue : setting.getParentFieldValues().getFieldValuesList()) { + assertThat(fieldsValue.getValue()).isEqualTo(fieldsValues[index]); + index++; + } + } + } + } diff --git a/sonar-db/src/test/java/org/sonar/db/property/PropertyDbTester.java b/sonar-db/src/test/java/org/sonar/db/property/PropertyDbTester.java index dfc451f4c565..bbef4a057f30 100644 --- a/sonar-db/src/test/java/org/sonar/db/property/PropertyDbTester.java +++ b/sonar-db/src/test/java/org/sonar/db/property/PropertyDbTester.java @@ -20,9 +20,19 @@ package org.sonar.db.property; +import com.google.common.base.Joiner; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import javax.annotation.Nullable; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.DbTester; +import org.sonar.db.component.ComponentDto; + +import static java.util.Arrays.asList; +import static org.sonar.db.property.PropertyTesting.newComponentPropertyDto; +import static org.sonar.db.property.PropertyTesting.newGlobalPropertyDto; public class PropertyDbTester { private final DbTester db; @@ -43,9 +53,38 @@ public PropertyDto insertProperty(PropertyDto property) { } public void insertProperties(PropertyDto... properties) { + insertProperties(asList(properties)); + } + + public void insertProperties(List properties) { for (PropertyDto propertyDto : properties) { dbClient.propertiesDao().insertProperty(dbSession, propertyDto); } dbSession.commit(); } + + public void insertPropertySet(String settingBaseKey, @Nullable ComponentDto componentDto, Map... fieldValues) { + int index = 1; + List propertyDtos = new ArrayList<>(); + List ids = new ArrayList<>(); + for (Map fieldValue : fieldValues) { + for (Map.Entry entry : fieldValue.entrySet()) { + String key = settingBaseKey + "." + index + "." + entry.getKey(); + if (componentDto != null) { + propertyDtos.add(newComponentPropertyDto(componentDto).setKey(key).setValue(entry.getValue())); + } else { + propertyDtos.add(newGlobalPropertyDto().setKey(key).setValue(entry.getValue())); + } + } + ids.add(Integer.toString(index)); + index++; + } + String idsValue = Joiner.on(",").join(ids); + if (componentDto != null) { + propertyDtos.add(newComponentPropertyDto(componentDto).setKey(settingBaseKey).setValue(idsValue)); + } else { + propertyDtos.add(newGlobalPropertyDto().setKey(settingBaseKey).setValue(idsValue)); + } + insertProperties(propertyDtos); + } } diff --git a/sonar-ws/src/main/protobuf/ws-settings.proto b/sonar-ws/src/main/protobuf/ws-settings.proto index 9b92fbd59a0c..18298563495f 100644 --- a/sonar-ws/src/main/protobuf/ws-settings.proto +++ b/sonar-ws/src/main/protobuf/ws-settings.proto @@ -76,17 +76,19 @@ message Setting { optional string key = 1; optional string value = 2; optional Values values = 3; - optional FieldsValues fieldsValues = 4; - optional bool default = 5; - optional bool inherited = 6; + optional FieldValues fieldsValues = 4; + optional bool inherited = 5; + optional string parentValue = 6; + optional Values parentValues = 7; + optional FieldValues parentFieldValues = 8; } message Values { repeated string values = 1; } -message FieldsValues { - repeated Value fieldsValues = 1; +message FieldValues { + repeated Value fieldValues = 1; message Value { map value = 1;