Explorar el Código

SONAR-7975 Return inherited values in /api/settings/values for modules

tags/6.1-RC1
Julien Lancelot hace 7 años
padre
commit
f4d9bd4f13

+ 112
- 0
server/sonar-server/src/main/java/org/sonar/server/settings/ws/Setting.java Ver fichero

@@ -0,0 +1,112 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

package org.sonar.server.settings.ws;

import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableTable;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.sonar.api.config.PropertyDefinition;
import org.sonar.db.property.PropertyDto;

public class Setting {

private static final Splitter DOT_SPLITTER = Splitter.on(".").omitEmptyStrings();

private final String key;
private final Long componentId;
private final String value;
private final PropertyDefinition definition;
private final List<Map<String, String>> propertySets;
private final boolean isDefault;

/**
* Use this constructor to create setting from a property dto, and that can have a definition or not
*/
Setting(PropertyDto propertyDto, List<PropertyDto> propertyDtoSetValues, @Nullable PropertyDefinition definition) {
this.key = propertyDto.getKey();
this.value = propertyDto.getValue();
this.componentId = propertyDto.getResourceId();
this.definition = definition;
this.propertySets = buildPropertySetValuesAsMap(key, propertyDtoSetValues);
this.isDefault = false;
}

/**
* Use this constructor to create setting for default value
*/
Setting(PropertyDefinition definition) {
this.key = definition.key();
this.value = definition.defaultValue();
this.componentId = null;
this.definition = definition;
this.propertySets = Collections.emptyList();
this.isDefault = true;
}

public String getKey() {
return key;
}

@CheckForNull
public Long getComponentId() {
return componentId;
}

@CheckForNull
public PropertyDefinition getDefinition() {
return definition;
}

public String getValue() {
return value;
}

public boolean isDefault() {
return isDefault;
}

public List<Map<String, String>> getPropertySets() {
return propertySets;
}

private static List<Map<String, String>> buildPropertySetValuesAsMap(String propertyKey, List<PropertyDto> propertySets) {
if (propertySets.isEmpty()) {
return Collections.emptyList();
}
ImmutableTable.Builder<String, String, String> tableBuilder = new ImmutableTable.Builder<>();
propertySets.forEach(property -> {
List<String> setIdWithFieldKey = DOT_SPLITTER.splitToList(property.getKey().replace(propertyKey + ".", ""));
String setId = setIdWithFieldKey.get(0);
String fieldKey = setIdWithFieldKey.get(1);
tableBuilder.put(setId, fieldKey, property.getValue());
});
ImmutableTable<String, String, String> table = tableBuilder.build();
return table.rowKeySet().stream()
.map(table::row)
.collect(Collectors.toList());
}

}

+ 107
- 0
server/sonar-server/src/main/java/org/sonar/server/settings/ws/SettingsFinder.java Ver fichero

@@ -0,0 +1,107 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

package org.sonar.server.settings.ws;

import com.google.common.base.Splitter;
import com.google.common.collect.Multimap;
import com.google.common.collect.Ordering;
import com.google.common.collect.TreeMultimap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import org.sonar.api.config.PropertyDefinitions;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.property.PropertyDto;

import static org.sonar.api.PropertyType.PROPERTY_SET;

public class SettingsFinder {

private static final Splitter DOT_SPLITTER = Splitter.on(".").omitEmptyStrings();
private static final Splitter COMMA_SPLITTER = Splitter.on(",");

private final DbClient dbClient;
private final PropertyDefinitions definitions;

public SettingsFinder(DbClient dbClient, PropertyDefinitions definitions) {
this.dbClient = dbClient;
this.definitions = definitions;
}

public List<Setting> loadGlobalSettings(DbSession dbSession, Set<String> keys) {
List<PropertyDto> properties = dbClient.propertiesDao().selectGlobalPropertiesByKeys(dbSession, keys);
List<PropertyDto> propertySets = dbClient.propertiesDao().selectGlobalPropertiesByKeys(dbSession, getPropertySetKeys(properties));
return properties.stream()
.map(property -> new Setting(property, getPropertySets(property.getKey(), propertySets, null), definitions.get(property.getKey())))
.collect(Collectors.toList());
}

/**
* Return list of settings by component uuid, sorted from project to lowest module
*/
public Multimap<String, Setting> loadComponentSettings(DbSession dbSession, Set<String> keys, ComponentDto component) {
List<String> componentUuids = DOT_SPLITTER.splitToList(component.moduleUuidPath());
List<ComponentDto> componentDtos = dbClient.componentDao().selectByUuids(dbSession, componentUuids);
Set<Long> componentIds = componentDtos.stream().map(ComponentDto::getId).collect(Collectors.toSet());
Map<Long, String> uuidsById = componentDtos.stream().collect(Collectors.toMap(ComponentDto::getId, ComponentDto::uuid));
List<PropertyDto> properties = dbClient.propertiesDao().selectPropertiesByKeysAndComponentIds(dbSession, keys, componentIds);
List<PropertyDto> propertySets = dbClient.propertiesDao().selectPropertiesByKeysAndComponentIds(dbSession, getPropertySetKeys(properties), componentIds);

Multimap<String, Setting> settingsByUuid = TreeMultimap.create(Ordering.explicit(componentUuids), Ordering.arbitrary());
for (PropertyDto propertyDto : properties) {
Long componentId = propertyDto.getResourceId();
String componentUuid = uuidsById.get(componentId);
String propertyKey = propertyDto.getKey();
settingsByUuid.put(componentUuid,
new Setting(propertyDto, getPropertySets(propertyKey, propertySets, componentId), definitions.get(propertyKey)));
}
return settingsByUuid;
}

private Set<String> getPropertySetKeys(List<PropertyDto> properties) {
Set<String> propertySetKeys = new HashSet<>();
properties.stream()
.filter(propertyDto -> definitions.get(propertyDto.getKey()) != null)
.filter(propertyDto -> definitions.get(propertyDto.getKey()).type().equals(PROPERTY_SET))
.forEach(propertyDto -> definitions.get(propertyDto.getKey()).fields()
.forEach(field -> COMMA_SPLITTER.splitToList(propertyDto.getValue())
.forEach(setId -> propertySetKeys.add(generatePropertySetKey(propertyDto.getKey(), setId, field.key())))));
return propertySetKeys;
}

private static String generatePropertySetKey(String propertyBaseKey, String id, String fieldKey) {
return propertyBaseKey + "." + id + "." + fieldKey;
}

private static List<PropertyDto> getPropertySets(String propertyKey, List<PropertyDto> propertySets, @Nullable Long componentId) {
return propertySets.stream()
.filter(propertyDto -> Objects.equals(propertyDto.getResourceId(), componentId))
.filter(propertyDto -> propertyDto.getKey().startsWith(propertyKey + "."))
.collect(Collectors.toList());
}

}

+ 2
- 1
server/sonar-server/src/main/java/org/sonar/server/settings/ws/SettingsWsModule.java Ver fichero

@@ -29,6 +29,7 @@ public class SettingsWsModule extends Module {
SetAction.class,
SettingsWsComponentParameters.class,
ListDefinitionsAction.class,
ValuesAction.class);
ValuesAction.class,
SettingsFinder.class);
}
}

+ 69
- 168
server/sonar-server/src/main/java/org/sonar/server/settings/ws/ValuesAction.java Ver fichero

@@ -20,24 +20,24 @@
package org.sonar.server.settings.ws;

import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableTable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import org.sonar.api.config.PropertyDefinition;
import org.sonar.api.config.PropertyDefinitions;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
import org.sonar.core.util.stream.Collectors;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto;
import org.sonar.db.property.PropertyDto;
import org.sonarqube.ws.Settings;
import org.sonarqube.ws.Settings.ValuesWsResponse;

@@ -52,16 +52,18 @@ public class ValuesAction implements SettingsWsAction {

private static final Splitter COMMA_SPLITTER = Splitter.on(",");

static final String PARAM_KEYS = "keys";
private static final String PARAM_KEYS = "keys";

private final DbClient dbClient;
private final SettingsWsComponentParameters settingsWsComponentParameters;
private final PropertyDefinitions propertyDefinitions;
private final SettingsFinder settingsFinder;

public ValuesAction(DbClient dbClient, SettingsWsComponentParameters settingsWsComponentParameters, PropertyDefinitions propertyDefinitions) {
public ValuesAction(DbClient dbClient, SettingsWsComponentParameters settingsWsComponentParameters, PropertyDefinitions propertyDefinitions, SettingsFinder settingsFinder) {
this.dbClient = dbClient;
this.settingsWsComponentParameters = settingsWsComponentParameters;
this.propertyDefinitions = propertyDefinitions;
this.settingsFinder = settingsFinder;
}

@Override
@@ -93,89 +95,63 @@ public class ValuesAction implements SettingsWsAction {
private ValuesWsResponse doHandle(Request request) {
DbSession dbSession = dbClient.openSession(true);
try {
ComponentDto component = settingsWsComponentParameters.getComponent(dbSession, request);
settingsWsComponentParameters.checkAdminPermission(component);
ComponentDto componentDto = settingsWsComponentParameters.getComponent(dbSession, request);
settingsWsComponentParameters.checkAdminPermission(componentDto);
Set<String> keys = new HashSet<>(request.mandatoryParamAsStrings(PARAM_KEYS));

ValuesWsResponse.Builder valuesBuilder = ValuesWsResponse.newBuilder();
new SettingsBuilder(dbSession, valuesBuilder, getDefinitions(keys), keys, component).build();
ValuesWsResponse response = valuesBuilder.build();
return response;
Optional<ComponentDto> component = Optional.ofNullable(componentDto);
return new ValuesResponseBuilder(loadSettings(dbSession, component, keys), component).build();
} finally {
dbClient.closeSession(dbSession);
}
}

private class SettingsBuilder {
private final DbSession dbSession;
private final ComponentDto component;
private List<Setting> loadSettings(DbSession dbSession, Optional<ComponentDto> component, Set<String> keys) {
if (keys.isEmpty()) {
return Collections.emptyList();
}

// List of settings must be kept in the following orders : default -> global -> component
List<Setting> settings = new ArrayList<>();
settings.addAll(loadDefaultSettings(keys));
settings.addAll(settingsFinder.loadGlobalSettings(dbSession, keys));
if (component.isPresent()) {
settings.addAll(settingsFinder.loadComponentSettings(dbSession, keys, component.get()).values());
}
return settings;
}

private List<Setting> loadDefaultSettings(Set<String> keys) {
return propertyDefinitions.getAll().stream()
.filter(definition -> keys.contains(definition.key()))
.filter(defaultProperty -> !isNullOrEmpty(defaultProperty.defaultValue()))
.map(Setting::new)
.collect(Collectors.toList());
}

private final ValuesWsResponse.Builder valuesWsBuilder;
private final Map<String, PropertyDefinition> definitionsByKey;
private final Set<String> keys;
private final Set<String> propertySetKeys;
private class ValuesResponseBuilder {
private final List<Setting> settings;
private final Optional<ComponentDto> component;

private final ValuesWsResponse.Builder valuesWsBuilder = ValuesWsResponse.newBuilder();
private final Map<String, Settings.Setting.Builder> settingsBuilderByKey = new HashMap<>();

SettingsBuilder(DbSession dbSession, ValuesWsResponse.Builder valuesWsBuilder, List<PropertyDefinition> definitions,
Set<String> keys, @Nullable ComponentDto component) {
this.dbSession = dbSession;
this.valuesWsBuilder = valuesWsBuilder;
this.definitionsByKey = definitions.stream()
.collect(Collectors.toMap(PropertyDefinition::key, Function.identity()));
this.keys = keys;
ValuesResponseBuilder(List<Setting> settings, Optional<ComponentDto> component) {
this.settings = settings;
this.component = component;

this.propertySetKeys = definitions.stream()
.filter(definition -> definition.type().equals(PROPERTY_SET))
.map(PropertyDefinition::key)
.collect(Collectors.toSet());
}

void build() {
processDefinitions();
processPropertyDtos(true);
if (component != null) {
processPropertyDtos(false);
}
ValuesWsResponse build() {
processSettings();
settingsBuilderByKey.values().forEach(Settings.Setting.Builder::build);
return valuesWsBuilder.build();
}

private void processDefinitions() {
definitionsByKey.values().stream()
.filter(defaultProperty -> !isNullOrEmpty(defaultProperty.defaultValue()))
.forEach(this::processDefaultValue);
}

private void processDefaultValue(PropertyDefinition definition) {
Settings.Setting.Builder settingBuilder = valuesWsBuilder.addSettingsBuilder()
.setKey(definition.key())
.setInherited(false)
.setDefault(true);
setValue(settingBuilder, definition.defaultValue());
settingsBuilderByKey.put(definition.key(), settingBuilder);
}

private void processPropertyDtos(boolean loadGlobal) {
List<PropertyDto> properties = loadProperties(dbSession, loadGlobal, keys);
PropertySetValues propertySetValues = new PropertySetValues(properties, loadGlobal);

properties.forEach(property -> {
String key = property.getKey();
Settings.Setting.Builder valueBuilder = getOrCreateValueBuilder(key);
valueBuilder.setInherited(component != null && property.getResourceId() == null);
valueBuilder.setDefault(false);

PropertyDefinition definition = definitionsByKey.get(key);
if (definition != null && definition.type().equals(PROPERTY_SET)) {
Settings.FieldsValues.Builder builder = Settings.FieldsValues.newBuilder();
for (Map<String, String> propertySetMap : propertySetValues.get(key)) {
builder.addFieldsValuesBuilder().putAllValue(propertySetMap);
}
valueBuilder.setFieldsValues(builder);
} else {
setValue(valueBuilder, property.getValue());
}
private void processSettings() {
settings.forEach(setting -> {
Settings.Setting.Builder valueBuilder = getOrCreateValueBuilder(setting.getKey());
valueBuilder.setDefault(setting.isDefault());
setInherited(setting, valueBuilder);
setValue(setting, valueBuilder);
});
}

@@ -188,108 +164,33 @@ public class ValuesAction implements SettingsWsAction {
return valueBuilder;
}

private void setValue(Settings.Setting.Builder valueBuilder, String value) {
PropertyDefinition definition = definitionsByKey.get(valueBuilder.getKey());
if (definition != null && definition.multiValues()) {
private void setValue(Setting setting, Settings.Setting.Builder valueBuilder) {
PropertyDefinition definition = setting.getDefinition();
String value = setting.getValue();
if (definition == null) {
valueBuilder.setValue(value);
return;
}
if (definition.type().equals(PROPERTY_SET)) {
Settings.FieldsValues.Builder builder = Settings.FieldsValues.newBuilder();
for (Map<String, String> propertySetMap : setting.getPropertySets()) {
builder.addFieldsValuesBuilder().putAllValue(propertySetMap);
}
valueBuilder.setFieldsValues(builder);
} else if (definition.multiValues()) {
valueBuilder.setValues(Settings.Values.newBuilder().addAllValues(COMMA_SPLITTER.split(value)));
} else {
valueBuilder.setValue(value);
}
}

private List<PropertyDto> loadProperties(DbSession dbSession, boolean loadGlobal, Set<String> keys) {
if (loadGlobal) {
return dbClient.propertiesDao().selectGlobalPropertiesByKeys(dbSession, keys);
}
return dbClient.propertiesDao().selectComponentPropertiesByKeys(dbSession, keys, component.getId());
}

private class PropertySetValues {
private final Map<String, PropertyKeyWithFieldAndSetId> propertyKeyWithFieldAndSetIds = new HashMap<>();
private final Map<String, PropertySetValue> propertySetValuesByPropertyKey = new HashMap<>();

PropertySetValues(List<PropertyDto> properties, boolean loadGlobal) {
properties.stream()
.filter(propertyDto -> propertySetKeys.contains(propertyDto.getKey()))
.forEach(propertyDto -> definitionsByKey.get(propertyDto.getKey()).fields()
.forEach(field -> COMMA_SPLITTER.splitToList(propertyDto.getValue())
.forEach(value -> add(propertyDto.getKey(), field.key(), value))));

loadProperties(dbSession, loadGlobal, propertyKeyWithFieldAndSetIds.keySet())
.forEach(propertySetDto -> {
PropertyKeyWithFieldAndSetId propertyKeyWithFieldAndSetIdKey = propertyKeyWithFieldAndSetIds.get(propertySetDto.getKey());
PropertySetValue propertySetValue = getOrCreatePropertySetValue(propertyKeyWithFieldAndSetIdKey.getPropertyKey());
propertySetValue.add(propertyKeyWithFieldAndSetIdKey.getSetId(), propertyKeyWithFieldAndSetIdKey.getFieldKey(), propertySetDto.getValue());
});
}

private void add(String propertyKey, String fieldKey, String value) {
String propertySetKey = generatePropertySetKey(propertyKey, value, fieldKey);
propertyKeyWithFieldAndSetIds.put(propertySetKey, new PropertyKeyWithFieldAndSetId(propertyKey, fieldKey, value));
}

private PropertySetValue getOrCreatePropertySetValue(String propertyKey) {
PropertySetValue propertySetValue = propertySetValuesByPropertyKey.get(propertyKey);
if (propertySetValue == null) {
propertySetValue = new PropertySetValue();
propertySetValuesByPropertyKey.put(propertyKey, propertySetValue);
}
return propertySetValue;
}

List<Map<String, String>> get(String propertyKey) {
return propertySetValuesByPropertyKey.get(propertyKey).get();
}

private String generatePropertySetKey(String propertyKey, String id, String fieldKey) {
return propertyKey + "." + id + "." + fieldKey;
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 List<PropertyDefinition> getDefinitions(Set<String> keys) {
return propertyDefinitions.getAll().stream()
.filter(def -> keys.contains(def.key()))
.collect(Collectors.toList());
}

private static class PropertyKeyWithFieldAndSetId {
private final String propertyKey;
private final String fieldKey;
private final String setId;

PropertyKeyWithFieldAndSetId(String propertyKey, String fieldKey, String setId) {
this.propertyKey = propertyKey;
this.fieldKey = fieldKey;
this.setId = setId;
}

public String getPropertyKey() {
return propertyKey;
}

public String getFieldKey() {
return fieldKey;
}

public String getSetId() {
return setId;
}
}

private static class PropertySetValue {
ImmutableTable.Builder<String, String, String> tableBuilder = new ImmutableTable.Builder<>();

public void add(String setId, String fieldKey, String value) {
tableBuilder.put(setId, fieldKey, value);
}

public List<Map<String, String>> get() {
ImmutableTable<String, String, String> table = tableBuilder.build();
return table.rowKeySet().stream()
.map(table::row)
.collect(Collectors.toList());
}
}

}

+ 208
- 0
server/sonar-server/src/test/java/org/sonar/server/settings/ws/SettingsFinderTest.java Ver fichero

@@ -0,0 +1,208 @@
/*
* SonarQube
* Copyright (C) 2009-2016 SonarSource SA
* mailto:contact AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

package org.sonar.server.settings.ws;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Multimap;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.config.PropertyDefinition;
import org.sonar.api.config.PropertyDefinitions;
import org.sonar.api.config.PropertyFieldDefinition;
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 static com.google.common.collect.Sets.newHashSet;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.guava.api.Assertions.assertThat;
import static org.sonar.api.PropertyType.PROPERTY_SET;
import static org.sonar.db.component.ComponentTesting.newModuleDto;
import static org.sonar.db.component.ComponentTesting.newProjectDto;
import static org.sonar.db.property.PropertyTesting.newComponentPropertyDto;
import static org.sonar.db.property.PropertyTesting.newGlobalPropertyDto;

public class SettingsFinderTest {

@Rule
public DbTester db = DbTester.create(System2.INSTANCE);

DbClient dbClient = db.getDbClient();
DbSession dbSession = db.getSession();
ComponentDbTester componentDb = new ComponentDbTester(db);
PropertyDefinitions propertyDefinitions = new PropertyDefinitions();

SettingsFinder underTest = new SettingsFinder(dbClient, propertyDefinitions);

@Test
public void return_global_settings() throws Exception {
PropertyDefinition definition = PropertyDefinition.builder("foo").build();
addDefinitions(definition);
insertProperties(newGlobalPropertyDto().setKey("foo").setValue("one"));

List<Setting> settings = underTest.loadGlobalSettings(dbSession, newHashSet("foo"));
assertThat(settings).hasSize(1);
assertSetting(settings.get(0), "foo", "one", null, true);

assertThat(underTest.loadGlobalSettings(dbSession, newHashSet("unknown"))).isEmpty();
}

@Test
public void return_global_setting_even_if_no_definition() throws Exception {
insertProperties(newGlobalPropertyDto().setKey("foo").setValue("one"));

List<Setting> settings = underTest.loadGlobalSettings(dbSession, newHashSet("foo"));
assertThat(settings).hasSize(1);
assertSetting(settings.get(0), "foo", "one", null, false);
}

@Test
public void return_global_settings_with_property_set() throws Exception {
addDefinitions(PropertyDefinition.builder("set1")
.type(PROPERTY_SET)
.fields(asList(
PropertyFieldDefinition.build("key").name("Key").build(),
PropertyFieldDefinition.build("size").name("Size").build()))
.build(),
PropertyDefinition.builder("another")
.type(PROPERTY_SET)
.fields(singletonList(PropertyFieldDefinition.build("key").name("Key").build()))
.build());
insertProperties(
newGlobalPropertyDto().setKey("set1").setValue("1,2"),
newGlobalPropertyDto().setKey("set1.1.key").setValue("key1"),
newGlobalPropertyDto().setKey("set1.1.size").setValue("size1"),
newGlobalPropertyDto().setKey("set1.2.key").setValue("key2"),
newGlobalPropertyDto().setKey("set2").setValue("1"),
newGlobalPropertyDto().setKey("another.1.key").setValue("key1"));

List<Setting> settings = underTest.loadGlobalSettings(dbSession, newHashSet("set1"));
assertThat(settings).hasSize(1);
assertSetting(settings.get(0), "set1", "1,2", null, true, ImmutableMap.of("key", "key1", "size", "size1"), ImmutableMap.of("key", "key2"));
}

@Test
public void return_component_settings() throws Exception {
ComponentDto project = componentDb.insertComponent(newProjectDto());
addDefinitions(PropertyDefinition.builder("property").defaultValue("default").build());
insertProperties(newComponentPropertyDto(project).setKey("property").setValue("one"));

Multimap<String, Setting> result = underTest.loadComponentSettings(dbSession, newHashSet("property"), project);
assertThat(result.values()).hasSize(1);
List<Setting> settings = new ArrayList<>(result.get(project.uuid()));
assertThat(settings).hasSize(1);
assertSetting(settings.get(0), "property", "one", project.getId(), true);

assertThat(underTest.loadComponentSettings(dbSession, newHashSet("unknown"), project)).isEmpty();
}

@Test
public void return_component_setting_even_if_no_definition() throws Exception {
ComponentDto project = componentDb.insertComponent(newProjectDto());
insertProperties(newComponentPropertyDto(project).setKey("property").setValue("one"));

Multimap<String, Setting> settings = underTest.loadComponentSettings(dbSession, newHashSet("property"), project);
assertThat(settings.values()).hasSize(1);
assertSetting(settings.get(project.uuid()).iterator().next(), "property", "one", project.getId(), false);
}

@Test
public void return_component_settings_with_property_set() throws Exception {
ComponentDto project = componentDb.insertComponent(newProjectDto());
addDefinitions(PropertyDefinition.builder("set1")
.type(PROPERTY_SET)
.fields(asList(
PropertyFieldDefinition.build("key").name("Key").build(),
PropertyFieldDefinition.build("size").name("Size").build()))
.build(),
PropertyDefinition.builder("another")
.type(PROPERTY_SET)
.fields(singletonList(PropertyFieldDefinition.build("key").name("Key").build()))
.build());
insertProperties(
newComponentPropertyDto(project).setKey("set1").setValue("1,2"),
newComponentPropertyDto(project).setKey("set1.1.key").setValue("key1"),
newComponentPropertyDto(project).setKey("set1.1.size").setValue("size1"),
newComponentPropertyDto(project).setKey("set1.2.key").setValue("key2"),
newComponentPropertyDto(project).setKey("set2").setValue("1"),
newComponentPropertyDto(project).setKey("another.1.key").setValue("key1"));

Multimap<String, Setting> settings = underTest.loadComponentSettings(dbSession, newHashSet("set1"), project);
assertThat(settings).hasSize(1);
assertSetting(settings.get(project.uuid()).iterator().next(), "set1", "1,2", project.getId(), true, ImmutableMap.of("key", "key1", "size", "size1"), ImmutableMap.of("key", "key2"));
}

@Test
public void return_module_settings() throws Exception {
ComponentDto project = componentDb.insertComponent(newProjectDto());
ComponentDto module = componentDb.insertComponent(newModuleDto(project));
ComponentDto subModule = componentDb.insertComponent(newModuleDto(module));
ComponentDto anotherProject = componentDb.insertComponent(newProjectDto());

insertProperties(
newComponentPropertyDto(project).setKey("property").setValue("one"),
newComponentPropertyDto(module).setKey("property").setValue("two"),
newComponentPropertyDto(subModule).setKey("property2").setValue("three"),
newComponentPropertyDto(anotherProject).setKey("property").setValue("another one"));

Multimap<String, Setting> result = underTest.loadComponentSettings(dbSession, newHashSet("property", "property2"), subModule);
assertThat(result).hasSize(3);
assertThat(result.keySet()).containsExactly(project.uuid(), module.uuid(), subModule.uuid());

assertSetting(result.get(subModule.uuid()).iterator().next(), "property2", "three", subModule.getId(), false);
assertSetting(result.get(module.uuid()).iterator().next(), "property", "two", module.getId(), false);
assertSetting(result.get(project.uuid()).iterator().next(), "property", "one", project.getId(), false);
}

private void assertSetting(Setting setting, String expectedKey, String expectedValue, @Nullable Long expectedComponentId, boolean hasPropertyDefinition,
Map<String, String>... propertySets) {
assertThat(setting.getKey()).isEqualTo(expectedKey);
assertThat(setting.getValue()).isEqualTo(expectedValue);
assertThat(setting.getComponentId()).isEqualTo(expectedComponentId);
if (hasPropertyDefinition) {
assertThat(setting.getDefinition()).isEqualTo(propertyDefinitions.get(expectedKey));
} else {
assertThat(setting.getDefinition()).isNull();
}
assertThat(setting.getPropertySets()).containsOnly(propertySets);
}

private void insertProperties(PropertyDto... properties) {
for (PropertyDto propertyDto : properties) {
dbClient.propertiesDao().insertProperty(dbSession, propertyDto);
}
dbSession.commit();
}

private void addDefinitions(PropertyDefinition... definitions) {
propertyDefinitions.addComponents(asList(definitions));
}
}

+ 1
- 1
server/sonar-server/src/test/java/org/sonar/server/settings/ws/SettingsWsModuleTest.java Ver fichero

@@ -29,6 +29,6 @@ public class SettingsWsModuleTest {
public void verify_count_of_added_components() {
ComponentContainer container = new ComponentContainer();
new SettingsWsModule().configure(container);
assertThat(container.size()).isEqualTo(5 + 2);
assertThat(container.size()).isEqualTo(6 + 2);
}
}

+ 58
- 25
server/sonar-server/src/test/java/org/sonar/server/settings/ws/ValuesActionTest.java Ver fichero

@@ -56,6 +56,7 @@ 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;
import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
import static org.sonar.db.component.ComponentTesting.newModuleDto;
import static org.sonar.db.component.ComponentTesting.newProjectDto;
import static org.sonar.db.property.PropertyTesting.newComponentPropertyDto;
import static org.sonar.db.property.PropertyTesting.newGlobalPropertyDto;
@@ -79,10 +80,11 @@ public class ValuesActionTest {
ComponentDbTester componentDb = new ComponentDbTester(db);
SettingsWsComponentParameters settingsWsComponentParameters = new SettingsWsComponentParameters(new ComponentFinder(dbClient), userSession);
PropertyDefinitions propertyDefinitions = new PropertyDefinitions();
SettingsFinder settingsFinder = new SettingsFinder(dbClient, propertyDefinitions);

ComponentDto project;

WsActionTester ws = new WsActionTester(new ValuesAction(dbClient, settingsWsComponentParameters, propertyDefinitions));
WsActionTester ws = new WsActionTester(new ValuesAction(dbClient, settingsWsComponentParameters, propertyDefinitions, settingsFinder));

@Before
public void setUp() throws Exception {
@@ -208,12 +210,7 @@ public class ValuesActionTest {

ValuesWsResponse result = newRequestForGlobalProperties("foo");
assertThat(result.getSettingsList()).hasSize(1);

Settings.Setting value = result.getSettings(0);
assertThat(value.getKey()).isEqualTo("foo");
assertThat(value.getValue()).isEqualTo("default");
assertThat(value.getDefault()).isTrue();
assertThat(value.getInherited()).isFalse();
assertSetting(result.getSettings(0), "foo", "default", true, false);
}

@Test
@@ -226,12 +223,7 @@ public class ValuesActionTest {

ValuesWsResponse result = newRequestForGlobalProperties("property");
assertThat(result.getSettingsList()).hasSize(1);

Settings.Setting globalPropertyValue = result.getSettings(0);
assertThat(globalPropertyValue.getKey()).isEqualTo("property");
assertThat(globalPropertyValue.getValue()).isEqualTo("one");
assertThat(globalPropertyValue.getDefault()).isFalse();
assertThat(globalPropertyValue.getInherited()).isFalse();
assertSetting(result.getSettings(0), "property", "one", false, false);
}

@Test
@@ -245,12 +237,7 @@ public class ValuesActionTest {

ValuesWsResponse result = newRequestForProjectProperties("property");
assertThat(result.getSettingsList()).hasSize(1);

Settings.Setting globalPropertyValue = result.getSettings(0);
assertThat(globalPropertyValue.getKey()).isEqualTo("property");
assertThat(globalPropertyValue.getValue()).isEqualTo("two");
assertThat(globalPropertyValue.getDefault()).isFalse();
assertThat(globalPropertyValue.getInherited()).isFalse();
assertSetting(result.getSettings(0), "property", "two", false, false);
}

@Test
@@ -262,12 +249,7 @@ public class ValuesActionTest {

ValuesWsResponse result = newRequestForProjectProperties("property");
assertThat(result.getSettingsList()).hasSize(1);

Settings.Setting globalPropertyValue = result.getSettings(0);
assertThat(globalPropertyValue.getKey()).isEqualTo("property");
assertThat(globalPropertyValue.getValue()).isEqualTo("one");
assertThat(globalPropertyValue.getDefault()).isFalse();
assertThat(globalPropertyValue.getInherited()).isTrue();
assertSetting(result.getSettings(0), "property", "one", false, true);
}

@Test
@@ -306,6 +288,46 @@ public class ValuesActionTest {
assertThat(result.getSettingsList()).isEmpty();
}

@Test
public void return_module_values() throws Exception {
setUserAsSystemAdmin();
ComponentDto module = componentDb.insertComponent(newModuleDto(project));

propertyDefinitions.addComponent(PropertyDefinition.builder("property").defaultValue("default").build());
insertProperties(
newGlobalPropertyDto().setKey("property").setValue("one"),
// The property is overriding global value
newComponentPropertyDto(module).setKey("property").setValue("two"));

ValuesWsResponse result = newRequestForComponentProperties(module, "property");
assertThat(result.getSettingsList()).hasSize(1);
assertSetting(result.getSettings(0), "property", "two", false, false);
}

@Test
public void return_inherited_values_on_sub_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(
newGlobalPropertyDto().setKey("globalProperty").setValue("global"),
newComponentPropertyDto(project).setKey("projectProperty").setValue("project"),
newComponentPropertyDto(module).setKey("moduleProperty").setValue("module"));

ValuesWsResponse result = newRequestForComponentProperties(subModule, "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);
}

@Test
public void test_example_json_response() {
setUserAsSystemAdmin();
@@ -376,6 +398,10 @@ public class ValuesActionTest {
assertThat(action.params()).hasSize(3);
}

private ValuesWsResponse newRequestForComponentProperties(ComponentDto componentDto, String... keys) {
return newRequest(componentDto.uuid(), null, keys);
}

private ValuesWsResponse newRequestForProjectProperties(String... keys) {
return newRequest(project.uuid(), null, keys);
}
@@ -416,4 +442,11 @@ public class ValuesActionTest {
dbSession.commit();
}

private void assertSetting(Settings.Setting setting, String expectedKey, String expectedValue, boolean expectedDefault, boolean expectedInherited) {
assertThat(setting.getKey()).isEqualTo(expectedKey);
assertThat(setting.getValue()).isEqualTo(expectedValue);
assertThat(setting.getDefault()).isEqualTo(expectedDefault);
assertThat(setting.getInherited()).isEqualTo(expectedInherited);
}

}

+ 7
- 2
sonar-db/src/main/java/org/sonar/db/property/PropertiesDao.java Ver fichero

@@ -168,12 +168,17 @@ public class PropertiesDao implements Dao {
return selectByKeys(session, keys, null);
}

public List<PropertyDto> selectComponentPropertiesByKeys(DbSession session, Set<String> keys, long componentId) {
public List<PropertyDto> selectPropertiesByKeysAndComponentId(DbSession session, Set<String> keys, long componentId) {
return selectByKeys(session, keys, componentId);
}

public List<PropertyDto> selectPropertiesByKeysAndComponentIds(DbSession session, Set<String> keys, Set<Long> componentIds) {
return executeLargeInputs(keys, partitionKeys -> executeLargeInputs(componentIds,
partitionComponentIds -> session.getMapper(PropertiesMapper.class).selectByKeysAndComponentIds(partitionKeys, partitionComponentIds)));
}

private List<PropertyDto> selectByKeys(DbSession session, Set<String> keys, @Nullable Long componentId) {
return executeLargeInputs(keys, propertyKeys -> session.getMapper(PropertiesMapper.class).selectByKeys(propertyKeys, componentId));
return executeLargeInputs(keys, partitionKeys -> session.getMapper(PropertiesMapper.class).selectByKeys(partitionKeys, componentId));
}

public void insertProperty(DbSession session, PropertyDto property) {

+ 2
- 0
sonar-db/src/main/java/org/sonar/db/property/PropertiesMapper.java Ver fichero

@@ -41,6 +41,8 @@ public interface PropertiesMapper {

List<PropertyDto> selectByKeys(@Param("keys") List<String> keys, @Nullable @Param("componentId") Long componentId);

List<PropertyDto> selectByKeysAndComponentIds(@Param("keys") List<String> keys, @Param("componentIds") List<Long> componentIds);

List<PropertyDto> selectByQuery(@Param("query") PropertyQuery query);

List<PropertyDto> selectDescendantModuleProperties(@Param("moduleUuid") String moduleUuid, @Param(value = "scope") String scope,

+ 16
- 0
sonar-db/src/main/resources/org/sonar/db/property/PropertiesMapper.xml Ver fichero

@@ -99,6 +99,22 @@
</where>
</select>

<select id="selectByKeysAndComponentIds" parameterType="map" resultType="Property">
SELECT p.id as id, p.prop_key as "key", p.text_value as value, p.resource_id as resourceId, p.user_id as userId
FROM properties p
<where>
AND p.prop_key in
<foreach collection="keys" open="(" close=")" item="key" separator=",">
#{key}
</foreach>
AND p.resource_id in
<foreach collection="componentIds" open="(" close=")" item="componentId" separator=",">
#{componentId}
</foreach>
AND p.user_id is null
</where>
</select>

<select id="selectByQuery" parameterType="map" resultType="Property">
select p.id as id, p.prop_key as "key", p.text_value as value, p.resource_id as resourceId, p.user_id as userId
from properties p

+ 42
- 5
sonar-db/src/test/java/org/sonar/db/property/PropertiesDaoTest.java Ver fichero

@@ -21,6 +21,7 @@ package org.sonar.db.property;

import com.google.common.collect.ImmutableMap;
import java.util.List;
import org.assertj.core.groups.Tuple;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
@@ -242,12 +243,48 @@ public class PropertiesDaoTest {
newUserPropertyDto(user).setKey(key),
newComponentPropertyDto(project).setKey(anotherKey));

assertThat(dao.selectComponentPropertiesByKeys(session, newHashSet(key), project.getId())).extracting("key").containsOnly(key);
assertThat(dao.selectComponentPropertiesByKeys(session, newHashSet(key, anotherKey), project.getId())).extracting("key").containsOnly(key, anotherKey);
assertThat(dao.selectComponentPropertiesByKeys(session, newHashSet(key, anotherKey, "unknown"), project.getId())).extracting("key").containsOnly(key, anotherKey);
assertThat(dao.selectPropertiesByKeysAndComponentId(session, newHashSet(key), project.getId())).extracting("key").containsOnly(key);
assertThat(dao.selectPropertiesByKeysAndComponentId(session, newHashSet(key, anotherKey), project.getId())).extracting("key").containsOnly(key, anotherKey);
assertThat(dao.selectPropertiesByKeysAndComponentId(session, newHashSet(key, anotherKey, "unknown"), project.getId())).extracting("key").containsOnly(key, anotherKey);

assertThat(dao.selectComponentPropertiesByKeys(session, newHashSet("unknown"), project.getId())).isEmpty();
assertThat(dao.selectComponentPropertiesByKeys(session, newHashSet(key), 123456789L)).isEmpty();
assertThat(dao.selectPropertiesByKeysAndComponentId(session, newHashSet("unknown"), project.getId())).isEmpty();
assertThat(dao.selectPropertiesByKeysAndComponentId(session, newHashSet(key), 123456789L)).isEmpty();
}

@Test
public void select_properties_by_keys_and_component_ids() throws Exception {
ComponentDto project = ComponentTesting.newProjectDto();
dbClient.componentDao().insert(session, project);
ComponentDto project2 = ComponentTesting.newProjectDto();
dbClient.componentDao().insert(session, project2);

UserDto user = UserTesting.newUserDto();
dbClient.userDao().insert(session, user);

String key = "key";
String anotherKey = "anotherKey";
insertProperties(
newGlobalPropertyDto().setKey(key),
newComponentPropertyDto(project).setKey(key),
newComponentPropertyDto(project2).setKey(key),
newComponentPropertyDto(project2).setKey(anotherKey),
newUserPropertyDto(user).setKey(key));

assertThat(dao.selectPropertiesByKeysAndComponentIds(session, newHashSet(key), newHashSet(project.getId())))
.extracting("key", "resourceId").containsOnly(Tuple.tuple(key, project.getId()));
assertThat(dao.selectPropertiesByKeysAndComponentIds(session, newHashSet(key), newHashSet(project.getId(), project2.getId())))
.extracting("key", "resourceId").containsOnly(
Tuple.tuple(key, project.getId()),
Tuple.tuple(key, project2.getId()));
assertThat(dao.selectPropertiesByKeysAndComponentIds(session, newHashSet(key, anotherKey), newHashSet(project.getId(), project2.getId())))
.extracting("key", "resourceId").containsOnly(
Tuple.tuple(key, project.getId()),
Tuple.tuple(key, project2.getId()),
Tuple.tuple(anotherKey, project2.getId()));

assertThat(dao.selectPropertiesByKeysAndComponentIds(session, newHashSet("unknown"), newHashSet(project.getId()))).isEmpty();
assertThat(dao.selectPropertiesByKeysAndComponentIds(session, newHashSet("key"), newHashSet(123456789L))).isEmpty();
assertThat(dao.selectPropertiesByKeysAndComponentIds(session, newHashSet("unknown"), newHashSet(123456789L))).isEmpty();
}

@Test

Cargando…
Cancelar
Guardar