@@ -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()); | |||
} | |||
} |
@@ -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()); | |||
} | |||
} |
@@ -29,6 +29,7 @@ public class SettingsWsModule extends Module { | |||
SetAction.class, | |||
SettingsWsComponentParameters.class, | |||
ListDefinitionsAction.class, | |||
ValuesAction.class); | |||
ValuesAction.class, | |||
SettingsFinder.class); | |||
} | |||
} |
@@ -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()); | |||
} | |||
} | |||
} |
@@ -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)); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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) { |
@@ -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, |
@@ -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 |
@@ -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 |