public class PropertiesBackup implements Backupable {
+ private static final String PERMISSION_PROPERTIES_PREFIX = "sonar.permission.template";
+
private final PersistentSettings persistentSettings;
public PropertiesBackup(PersistentSettings persistentSettings) {
List<Property> xmlProperties = Lists.newArrayList();
for (PropertyDto property : persistentSettings.getGlobalProperties()) {
- // "sonar.core.id" must never be restored, it is unique for a server and it created once at the 1rst server startup
- if (!CoreProperties.SERVER_ID.equals(property.getKey())) {
+ if (shouldBeExported(property.getKey())) {
xmlProperties.add(new Property(property.getKey(), property.getValue()));
}
}
public void importXml(SonarConfig sonarConfig) {
LoggerFactory.getLogger(getClass()).info("Restore properties");
- // "sonar.core.id" property should not be cleared, because it is the unique key used to identify the server
- // and it is used by the batch to verify that it connects to the same DB as the remote server (see SONAR-3126).
- String serverId = persistentSettings.getString(CoreProperties.SERVER_ID);
- String serverStartTime = persistentSettings.getString(CoreProperties.SERVER_STARTTIME);
-
Map<String, String> properties = Maps.newHashMap();
+
if (sonarConfig.getProperties() != null && !sonarConfig.getProperties().isEmpty()) {
for (Property xmlProperty : sonarConfig.getProperties()) {
properties.put(xmlProperty.getKey(), xmlProperty.getValue());
}
}
- properties.put(CoreProperties.SERVER_ID, serverId);
- properties.put(CoreProperties.SERVER_STARTTIME, serverStartTime);
+
+ for (PropertyDto property : persistentSettings.getGlobalProperties()) {
+ if (shouldNotBeErased(property.getKey())) {
+ properties.put(property.getKey(), property.getValue());
+ }
+ }
+
persistentSettings.deleteProperties();
persistentSettings.saveProperties(properties);
}
public void configure(XStream xStream) {
xStream.alias("property", Property.class);
}
+
+ private boolean shouldBeExported(String propertyKey) {
+ // "sonar.core.id" must never be restored, it is unique for a server and it created once at the 1rst server startup
+ // default permissions properties should not be exported as they reference permission_templates entries in the DB
+ return !CoreProperties.SERVER_ID.equals(propertyKey) && !propertyKey.startsWith(PERMISSION_PROPERTIES_PREFIX);
+ }
+
+ private boolean shouldNotBeErased(String propertyKey) {
+ // "sonar.core.id" property should not be cleared, because it is the unique key used to identify the server
+ // and it is used by the batch to verify that it connects to the same DB as the remote server (see SONAR-3126).
+ // default permissions properties should not be erased as they reference permission_templates entries in the DB
+ return CoreProperties.SERVER_ID.equals(propertyKey) || CoreProperties.SERVER_STARTTIME.equals(propertyKey)
+ || propertyKey.startsWith(PERMISSION_PROPERTIES_PREFIX);
+ }
}
*/
package org.sonar.server.configuration;
-import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
-import org.hamcrest.collection.IsMapContaining;
+import org.hamcrest.Description;
import org.junit.Before;
import org.junit.Test;
+import org.mockito.ArgumentMatcher;
import org.sonar.api.CoreProperties;
import org.sonar.api.database.configuration.Property;
import org.sonar.core.properties.PropertyDto;
-import org.sonar.jpa.test.AbstractDbUnitTestCase;
import org.sonar.server.platform.PersistentSettings;
import java.util.Arrays;
import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
import static org.fest.assertions.Assertions.assertThat;
import static org.mockito.Matchers.argThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.*;
-public class PropertiesBackupTest extends AbstractDbUnitTestCase {
+public class PropertiesBackupTest {
private PersistentSettings persistentSettings;
private PropertiesBackup backup;
@Test
public void shouldExportProperties() {
- when(persistentSettings.getGlobalProperties()).thenReturn(Lists.newArrayList(new PropertyDto().setKey("key1").setValue("value1"), new PropertyDto().setKey("key2").setValue("value2")));
+ when(persistentSettings.getGlobalProperties())
+ .thenReturn(Lists.newArrayList(new PropertyDto().setKey("key1").setValue("value1"), new PropertyDto().setKey("key2").setValue("value2")));
SonarConfig config = new SonarConfig();
backup.exportXml(config);
@Test
public void shouldNotExportServerId() {
- when(persistentSettings.getGlobalProperties()).thenReturn(Lists.newArrayList(new PropertyDto().setKey(CoreProperties.SERVER_ID).setValue("111"), new PropertyDto().setKey("key").setValue("value")));
+ when(persistentSettings.getGlobalProperties())
+ .thenReturn(Lists.newArrayList(new PropertyDto().setKey(CoreProperties.SERVER_ID).setValue("111"), new PropertyDto().setKey("key").setValue("value")));
SonarConfig config = new SonarConfig();
backup.exportXml(config);
backup.importXml(config);
- verify(persistentSettings).saveProperties(argThat(IsMapContaining.hasEntry("key1", "value1")));
+ Map<String, String> expectedProperties = new HashMap<String, String>();
+ expectedProperties.put("key1", "value1");
+ verify(persistentSettings).saveProperties(argThat(IsMap.containing(expectedProperties)));
}
@Test
public void shouldNotImportServerId() {
// initial server id
- when(persistentSettings.getString(CoreProperties.SERVER_ID)).thenReturn("111");
+ when(persistentSettings.getGlobalProperties()).thenReturn(Lists.newArrayList(
+ new PropertyDto().setKey(CoreProperties.SERVER_ID).setValue("111")));
Collection<Property> newProperties = Arrays.asList(new Property(CoreProperties.SERVER_ID, "999"));
SonarConfig config = new SonarConfig();
config.setProperties(newProperties);
backup.importXml(config);
- verify(persistentSettings).saveProperties(argThat(IsMapContaining.hasEntry(CoreProperties.SERVER_ID, "111")));
+ Map<String, String> expectedProperties = new HashMap<String, String>();
+ expectedProperties.put(CoreProperties.SERVER_ID, "111");
+ verify(persistentSettings).saveProperties(argThat(IsMap.containing(expectedProperties)));
+ }
+
+ @Test
+ public void shouldNotImportPermissionProperties() throws Exception {
+ when(persistentSettings.getGlobalProperties()).thenReturn(Lists.newArrayList(
+ new PropertyDto().setKey("sonar.permission.template.default").setValue("default_template"),
+ new PropertyDto().setKey("sonar.permission.template.TRK.default").setValue("default_template_for_projects"),
+ new PropertyDto().setKey("erasable_key").setValue("erasable_value")));
+
+ Collection<Property> newProperties = Arrays.asList(
+ new Property("sonar.permission.template.default", "another_default"),
+ new Property("key_to_import", "value_to_import"),
+ new Property("erasable_key", "new_value"));
+ SonarConfig config = new SonarConfig();
+ config.setProperties(newProperties);
+ backup.importXml(config);
+
+ Map<String, String> expectedProperties = new HashMap<String, String>();
+ expectedProperties.put("key_to_import", "value_to_import");
+ expectedProperties.put("erasable_key", "new_value");
+ expectedProperties.put("sonar.permission.template.default", "default_template");
+ expectedProperties.put("sonar.permission.template.TRK.default", "default_template_for_projects");
+ verify(persistentSettings).saveProperties(argThat(IsMap.containing(expectedProperties)));
+ }
+
+ @Test
+ public void shouldNotExportPermissionProperties() throws Exception {
+ when(persistentSettings.getGlobalProperties()).thenReturn(Lists.newArrayList(
+ new PropertyDto().setKey("sonar.permission.template.default").setValue("default_template"),
+ new PropertyDto().setKey("sonar.permission.template.TRK.default").setValue("default_template_for_projects"),
+ new PropertyDto().setKey("key").setValue("value")));
+
+ SonarConfig config = new SonarConfig();
+ backup.exportXml(config);
+
+ assertThat(config.getProperties()).containsOnly(new Property("key", "value"));
+ }
+
+ private static class IsMap extends ArgumentMatcher<Map<String, String>> {
+
+ private final Map<String, String> referenceMap;
+
+ private IsMap(Map<String, String> referenceMap) {
+ this.referenceMap = referenceMap;
+ }
+
+ static IsMap containing(Map<String, String> keyValuePairs) {
+ return new IsMap(keyValuePairs);
+ }
+
+ @Override
+ public boolean matches(Object argument) {
+ if(argument != null && argument instanceof Map) {
+ Map<String, String> argAsMap = (Map<String, String>) argument;
+ for (String key : argAsMap.keySet()) {
+ if(!referenceMap.containsKey(key) || !referenceMap.get(key).equals(argAsMap.get(key))) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ if(referenceMap != null) {
+ description.appendText(referenceMap.toString());
+ }
+ }
}
}