From 88773a3021dfff6c9563fd1e40c4ba730cdf5a0f Mon Sep 17 00:00:00 2001 From: Simon Brandhof Date: Tue, 9 Aug 2011 18:57:41 +0200 Subject: [PATCH] SONAR-2603 generate server key at startup --- .../org/sonar/plugins/core/CorePlugin.java | 5 + .../java/org/sonar/batch/ServerMetadata.java | 44 +++-- .../java/org/sonar/api/CoreProperties.java | 10 ++ .../java/org/sonar/api/platform/Server.java | 5 + .../org/sonar/server/platform/Platform.java | 2 +- .../org/sonar/server/platform/ServerImpl.java | 41 +++-- .../server/platform/ServerKeyGenerator.java | 162 ++++++++++++++++++ .../startup/ServerMetadataPersister.java | 23 ++- .../main/webapp/WEB-INF/app/models/server.rb | 1 + .../sonar/server/platform/ServerImplTest.java | 12 +- .../platform/ServerKeyGeneratorTest.java | 111 ++++++++++++ .../platform/ServerLifecycleNotifierTest.java | 4 + .../startup/ServerMetadataPersisterTest.java | 60 +++++-- .../testDeleteProperties-result.xml | 7 + .../testDeleteProperties.xml | 10 ++ .../testSaveProperties-result.xml | 3 +- .../testUpdateExistingProperties-result.xml | 2 +- .../testUpdateExistingProperties.xml | 1 + 18 files changed, 435 insertions(+), 68 deletions(-) create mode 100644 sonar-server/src/main/java/org/sonar/server/platform/ServerKeyGenerator.java create mode 100644 sonar-server/src/test/java/org/sonar/server/platform/ServerKeyGeneratorTest.java create mode 100644 sonar-server/src/test/resources/org/sonar/server/startup/ServerMetadataPersisterTest/testDeleteProperties-result.xml create mode 100644 sonar-server/src/test/resources/org/sonar/server/startup/ServerMetadataPersisterTest/testDeleteProperties.xml diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java index 97b8e06428c..13137d94a44 100644 --- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java +++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/CorePlugin.java @@ -44,6 +44,11 @@ import org.sonar.plugins.core.widgets.*; import java.util.List; @Properties({ + @Property( + key = CoreProperties.ORGANIZATION, + name = "Organization", + description = "Identify your installation. Required to generate the server key and to benefit from licensed plugins. Server must be restarted for the change to take effect.", + global = true), @Property( key = CoreProperties.CORE_COVERAGE_PLUGIN_PROPERTY, defaultValue = "cobertura", diff --git a/sonar-batch/src/main/java/org/sonar/batch/ServerMetadata.java b/sonar-batch/src/main/java/org/sonar/batch/ServerMetadata.java index b8accd4e6d1..6415c9e01e1 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/ServerMetadata.java +++ b/sonar-batch/src/main/java/org/sonar/batch/ServerMetadata.java @@ -31,43 +31,39 @@ import java.util.Date; public class ServerMetadata extends Server { - private String id; - private String version; - private String url; - private Date startTime; + private Configuration conf; public ServerMetadata(Configuration conf) { - id = conf.getString(CoreProperties.SERVER_ID); - version = conf.getString(CoreProperties.SERVER_VERSION); - url = getURL(conf); - String dateString = conf.getString(CoreProperties.SERVER_STARTTIME); - if (dateString!=null) { - try { - this.startTime = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").parse(dateString); - - } catch (ParseException e) { - LoggerFactory.getLogger(getClass()).error("The property " + CoreProperties.SERVER_STARTTIME + " is badly formatted.", e); - } - } - } - - public static String getURL(Configuration conf) { - return StringUtils.removeEnd(conf.getString("sonar.host.url", "http://localhost:9000"), "/"); + this.conf = conf; } public String getId() { - return id; + return conf.getString(CoreProperties.SERVER_ID); } public String getVersion() { - return version; + return conf.getString(CoreProperties.SERVER_VERSION); } public Date getStartedAt() { - return startTime; + String dateString = conf.getString(CoreProperties.SERVER_STARTTIME); + if (dateString != null) { + try { + return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").parse(dateString); + + } catch (ParseException e) { + LoggerFactory.getLogger(getClass()).error("The property " + CoreProperties.SERVER_STARTTIME + " is badly formatted.", e); + } + } + return null; } public String getURL() { - return url; + return StringUtils.removeEnd(conf.getString("sonar.host.url", "http://localhost:9000"), "/"); + } + + @Override + public String getKey() { + return conf.getString(CoreProperties.SERVER_KEY); } } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/CoreProperties.java b/sonar-plugin-api/src/main/java/org/sonar/api/CoreProperties.java index 8760081c433..0fc4a6c2d75 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/CoreProperties.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/CoreProperties.java @@ -180,4 +180,14 @@ public interface CoreProperties { String TIMEMACHINE_DEFAULT_PERIOD_3 = "30"; String TIMEMACHINE_DEFAULT_PERIOD_4 = ""; String TIMEMACHINE_DEFAULT_PERIOD_5 = ""; + + /** + * @since 2.11 + */ + String ORGANIZATION = "sonar.organization"; + + /** + * @since 2.11 + */ + String SERVER_KEY = "sonar.serverKey.secured"; } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/platform/Server.java b/sonar-plugin-api/src/main/java/org/sonar/api/platform/Server.java index 37d06ad35d6..f5043073dbb 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/platform/Server.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/platform/Server.java @@ -40,4 +40,9 @@ public abstract class Server implements BatchComponent, ServerComponent { * @since 2.4 */ public abstract String getURL(); + + /** + * @since 2.10 + */ + public abstract String getKey(); } diff --git a/sonar-server/src/main/java/org/sonar/server/platform/Platform.java b/sonar-server/src/main/java/org/sonar/server/platform/Platform.java index 2d8ef632fa9..6da88e0004a 100644 --- a/sonar-server/src/main/java/org/sonar/server/platform/Platform.java +++ b/sonar-server/src/main/java/org/sonar/server/platform/Platform.java @@ -138,7 +138,6 @@ public final class Platform { coreContainer = rootContainer.makeChildContainer(); coreContainer.as(Characteristics.CACHE).addComponent(PluginDeployer.class); coreContainer.as(Characteristics.CACHE).addComponent(ServerPluginRepository.class); - coreContainer.as(Characteristics.CACHE).addComponent(ServerImpl.class); coreContainer.as(Characteristics.CACHE).addComponent(DefaultServerFileSystem.class); coreContainer.as(Characteristics.CACHE).addComponent(ThreadLocalDatabaseSessionFactory.class); coreContainer.as(Characteristics.CACHE).addComponent(HttpDownloader.class); @@ -162,6 +161,7 @@ public final class Platform { ServerPluginRepository pluginRepository = servicesContainer.getComponent(ServerPluginRepository.class); pluginRepository.registerExtensions(servicesContainer); + servicesContainer.as(Characteristics.CACHE).addComponent(ServerImpl.class); servicesContainer.as(Characteristics.CACHE).addComponent(DefaultModelFinder.class); // depends on plugins servicesContainer.as(Characteristics.CACHE).addComponent(DefaultModelManager.class); servicesContainer.as(Characteristics.CACHE).addComponent(Plugins.class); diff --git a/sonar-server/src/main/java/org/sonar/server/platform/ServerImpl.java b/sonar-server/src/main/java/org/sonar/server/platform/ServerImpl.java index 5267fbcc8eb..acc0bdb5a69 100644 --- a/sonar-server/src/main/java/org/sonar/server/platform/ServerImpl.java +++ b/sonar-server/src/main/java/org/sonar/server/platform/ServerImpl.java @@ -19,8 +19,10 @@ */ package org.sonar.server.platform; +import org.apache.commons.configuration.Configuration; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; +import org.sonar.api.CoreProperties; import org.sonar.api.platform.Server; import java.io.IOException; @@ -31,28 +33,39 @@ import java.util.Properties; public final class ServerImpl extends Server { - private final String id; - private final String version; + private String id; + private String version; private final Date startedAt; + private String key; + private Configuration conf; - public ServerImpl() { + public ServerImpl(Configuration conf) { + this(conf, new Date()); + } + + ServerImpl(Configuration conf, Date startedAt) { + this.conf = conf; + this.startedAt = startedAt; + } + + public void start() { try { - this.startedAt = new Date(); - this.id = new SimpleDateFormat("yyyyMMddHHmmss").format(startedAt); - this.version = loadVersionFromManifest("/META-INF/maven/org.codehaus.sonar/sonar-plugin-api/pom.properties"); - if (StringUtils.isBlank(this.version)) { + id = new SimpleDateFormat("yyyyMMddHHmmss").format(startedAt); + key = initKey(conf); + version = loadVersionFromManifest("/META-INF/maven/org.codehaus.sonar/sonar-plugin-api/pom.properties"); + if (StringUtils.isBlank(version)) { throw new ServerStartException("Unknown Sonar version"); } } catch (IOException e) { - throw new ServerStartException("Can not load Sonar metadata", e); + throw new ServerStartException("Can not load metadata", e); } } - public ServerImpl(String id, String version, Date startedAt) { - this.id = id; - this.version = version; - this.startedAt = startedAt; + private String initKey(Configuration conf) { + String organization = conf.getString(CoreProperties.ORGANIZATION); + String previousKey = conf.getString(CoreProperties.SERVER_KEY); + return new ServerKeyGenerator().generate(organization, previousKey); } public String getId() { @@ -91,6 +104,10 @@ public final class ServerImpl extends Server { return null; } + public String getKey() { + return key; + } + @Override public boolean equals(Object o) { if (this == o) { diff --git a/sonar-server/src/main/java/org/sonar/server/platform/ServerKeyGenerator.java b/sonar-server/src/main/java/org/sonar/server/platform/ServerKeyGenerator.java new file mode 100644 index 00000000000..e57db95edae --- /dev/null +++ b/sonar-server/src/main/java/org/sonar/server/platform/ServerKeyGenerator.java @@ -0,0 +1,162 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2011 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.server.platform; + +import com.google.common.collect.Lists; +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.lang.StringUtils; +import org.slf4j.LoggerFactory; +import org.sonar.api.utils.Logs; + +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.Enumeration; +import java.util.List; + +public class ServerKeyGenerator { + + /** + * Increment this version each time the algorithm is changed. Do not exceed 9. + */ + static final String VERSION = "1"; + + private static final int CHECKSUM_SIZE = 9; + + public String generate(String organization) { + return generate(organization, null); + } + + public String generate(String organization, String previousKey) { + List serverKeys = generateForOrganization(organization); + String external = null; + String best = null; + for (ServerKey serverKey : serverKeys) { + if (StringUtils.equals(previousKey, serverKey.getKey())) { + best = serverKey.getKey(); + } + if (serverKey.isExternal()) { + // External addresses are prefered to internal addresses. + external = serverKey.getKey(); + } + } + if (best == null) { + if (external!=null) { + best = external; + } else if (!serverKeys.isEmpty()) { + best = serverKeys.get(0).getKey(); + } + } + log(previousKey, best); + return best; + } + + private void log(String previousKey, String newKey) { + if (StringUtils.isNotBlank(newKey) && StringUtils.isNotBlank(previousKey) && !previousKey.equals(newKey)) { + LoggerFactory.getLogger(getClass()).warn("Server key has changed. Licensed plugins may be disabled. " + + "Please check the organization name (Settings page) and the server IP addresses."); + } + if (StringUtils.isNotBlank(newKey)) { + Logs.INFO.info("Server key: " + newKey); + + } else if (StringUtils.isNotBlank(previousKey)) { + LoggerFactory.getLogger(getClass()).warn("Server key has been removed. Licensed plugins may be disabled. " + + "Please check the organization name (Settings page) and the server IP addresses."); + } + } + + List generateForOrganization(String organization) { + List keys = Lists.newArrayList(); + if (StringUtils.isNotBlank(organization)) { + try { + Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces(); + while (networkInterfaces.hasMoreElements()) { + NetworkInterface networkInterface = networkInterfaces.nextElement(); + Enumeration addresses = networkInterface.getInetAddresses(); + while (addresses.hasMoreElements()) { + ServerKey key = new ServerKey(organization, addresses.nextElement()); + if (key.isValid()) { + keys.add(key); + } + } + } + } catch (SocketException e) { + LoggerFactory.getLogger(getClass()).error("Fail to generate server key. Network interfaces can't be browsed.", e); + } + } + return keys; + } + + static class ServerKey { + private String organization; + private InetAddress address; + + ServerKey(String organization, InetAddress address) { + this.organization = organization; + this.address = address; + } + + boolean isExternal() { + return !address.isLoopbackAddress() && !address.isSiteLocalAddress() && !address.isLinkLocalAddress(); + } + + boolean isValid() { + // Loopback addresses are in the range 127/8. + // Link local addresses are in the range 169.254/16 (IPv4) or fe80::/10 (IPv6). They are "autoconfiguration" addresses. + // They can assigned pseudorandomly, so they don't guarantee to be the same between two server startups. + return !address.isLoopbackAddress() && !address.isLinkLocalAddress(); + } + + String getKey() { + String key = new StringBuilder().append(organization).append("-").append(address.getHostAddress()).toString(); + return VERSION + DigestUtils.shaHex(key.getBytes()).substring(0, CHECKSUM_SIZE); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ServerKey serverKey = (ServerKey) o; + if (!address.equals(serverKey.address)) { + return false; + } + if (!organization.equals(serverKey.organization)) { + return false; + } + return true; + } + + @Override + public int hashCode() { + int result = organization.hashCode(); + result = 31 * result + address.hashCode(); + return result; + } + + @Override + public String toString() { + return getKey(); + } + } +} diff --git a/sonar-server/src/main/java/org/sonar/server/startup/ServerMetadataPersister.java b/sonar-server/src/main/java/org/sonar/server/startup/ServerMetadataPersister.java index 6a6e4092c52..2cb351d5d99 100644 --- a/sonar-server/src/main/java/org/sonar/server/startup/ServerMetadataPersister.java +++ b/sonar-server/src/main/java/org/sonar/server/startup/ServerMetadataPersister.java @@ -39,19 +39,24 @@ public class ServerMetadataPersister { public void start() { setProperty(CoreProperties.SERVER_ID, server.getId()); setProperty(CoreProperties.SERVER_VERSION, server.getVersion()); - if (server.getStartedAt() != null) { - setProperty(CoreProperties.SERVER_STARTTIME, new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").format(server.getStartedAt())); - } + setProperty(CoreProperties.SERVER_KEY, server.getKey()); + setProperty(CoreProperties.SERVER_STARTTIME, new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").format(server.getStartedAt())); session.commit(); } private void setProperty(String key, String value) { Property prop = session.getSingleResult(Property.class, "key", key); - if (prop == null) { - prop = new Property(key, value); - } else { - prop.setValue(value); + + if (value == null && prop != null) { + session.removeWithoutFlush(prop); + + } else if (value != null) { + if (prop == null) { + prop = new Property(key, value); + } else { + prop.setValue(value); + } + session.saveWithoutFlush(prop); } - session.save(prop); } -} +} \ No newline at end of file diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/server.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/server.rb index f0baab37f59..6afbae60f56 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/models/server.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/models/server.rb @@ -59,6 +59,7 @@ class Server def sonar_info sonar_info=[] + add_property(sonar_info, 'Server Key') {org.sonar.server.platform.Platform.getServer().getKey()} add_property(sonar_info, 'Version') {org.sonar.server.platform.Platform.getServer().getVersion()} add_property(sonar_info, 'ID') {org.sonar.server.platform.Platform.getServer().getId()} add_property(sonar_info, 'Database') {"#{jdbc_metadata. getDatabaseProductName()} #{jdbc_metadata. getDatabaseProductVersion()}"} diff --git a/sonar-server/src/test/java/org/sonar/server/platform/ServerImplTest.java b/sonar-server/src/test/java/org/sonar/server/platform/ServerImplTest.java index 583772a50bb..faaf814c846 100644 --- a/sonar-server/src/test/java/org/sonar/server/platform/ServerImplTest.java +++ b/sonar-server/src/test/java/org/sonar/server/platform/ServerImplTest.java @@ -19,6 +19,7 @@ */ package org.sonar.server.platform; +import org.apache.commons.configuration.PropertiesConfiguration; import org.junit.Test; import java.io.IOException; @@ -30,7 +31,8 @@ public class ServerImplTest { @Test public void alwaysReturnTheSameValues() { - ServerImpl server = new ServerImpl(); + ServerImpl server = new ServerImpl(new PropertiesConfiguration()); + server.start(); assertNotNull(server.getId()); assertEquals(server.getId(), server.getId()); @@ -44,21 +46,21 @@ public class ServerImplTest { @Test public void getVersionFromFile() throws IOException { - assertEquals("1.0", new ServerImpl().loadVersionFromManifest("/org/sonar/server/platform/ServerImplTest/pom-with-version.properties")); + assertEquals("1.0", new ServerImpl(new PropertiesConfiguration()).loadVersionFromManifest("/org/sonar/server/platform/ServerImplTest/pom-with-version.properties")); } @Test public void testFileWithNoVersion() throws IOException { - assertEquals("", new ServerImpl().loadVersionFromManifest("/org/sonar/server/platform/ServerImplTest/pom-without-version.properties")); + assertEquals("", new ServerImpl(new PropertiesConfiguration()).loadVersionFromManifest("/org/sonar/server/platform/ServerImplTest/pom-without-version.properties")); } @Test public void testFileWithEmptyVersionParameter() throws IOException { - assertEquals("", new ServerImpl().loadVersionFromManifest("/org/sonar/server/platform/ServerImplTest/pom-with-empty-version.properties")); + assertEquals("", new ServerImpl(new PropertiesConfiguration()).loadVersionFromManifest("/org/sonar/server/platform/ServerImplTest/pom-with-empty-version.properties")); } @Test public void shouldNotFailIfFileNotFound() throws IOException { - assertEquals("", new ServerImpl().loadVersionFromManifest("/org/sonar/server/platform/ServerImplTest/unknown-file.properties")); + assertEquals("", new ServerImpl(new PropertiesConfiguration()).loadVersionFromManifest("/org/sonar/server/platform/ServerImplTest/unknown-file.properties")); } } diff --git a/sonar-server/src/test/java/org/sonar/server/platform/ServerKeyGeneratorTest.java b/sonar-server/src/test/java/org/sonar/server/platform/ServerKeyGeneratorTest.java new file mode 100644 index 00000000000..4041825edaa --- /dev/null +++ b/sonar-server/src/test/java/org/sonar/server/platform/ServerKeyGeneratorTest.java @@ -0,0 +1,111 @@ +/* + * Sonar, open source software quality management tool. + * Copyright (C) 2008-2011 SonarSource + * mailto:contact AT sonarsource DOT com + * + * Sonar 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. + * + * Sonar 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 Sonar; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package org.sonar.server.platform; + +import org.apache.commons.lang.StringUtils; +import org.hamcrest.core.Is; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +import static org.hamcrest.text.StringStartsWith.startsWith; +import static org.junit.Assert.*; + +public class ServerKeyGeneratorTest { + + private static InetAddress localhost; + + @BeforeClass + public static void init() throws UnknownHostException { + localhost = InetAddress.getLocalHost(); + } + + @Test + public void keyShouldHaveTenCharacters() { + ServerKeyGenerator.ServerKey key = new ServerKeyGenerator.ServerKey("SonarSource", localhost); + assertThat(key.getKey().length(), Is.is(10)); // first character is version + 9 characters for checksum + assertThat(StringUtils.isBlank(key.getKey()), Is.is(false)); + } + + @Test + public void keyShouldStartWithVersion() { + ServerKeyGenerator.ServerKey key = new ServerKeyGenerator.ServerKey("SonarSource", localhost); + assertThat(key.getKey(), startsWith(ServerKeyGenerator.VERSION)); + } + + @Test + public void loopbackAddressesShouldNotBeValid() throws UnknownHostException { + assertThat(new ServerKeyGenerator.ServerKey("SonarSource", InetAddress.getByName("127.0.0.1")).isValid(), Is.is(false)); + } + + @Test + public void testEqualsAndHashCode() { + ServerKeyGenerator.ServerKey key1 = new ServerKeyGenerator.ServerKey("Corp One", localhost); + ServerKeyGenerator.ServerKey key2 = new ServerKeyGenerator.ServerKey("Corp Two", localhost); + assertEquals(key1, key1); + assertEquals(key1.hashCode(), key1.hashCode()); + + assertThat(key1.equals(key2), Is.is(false)); + assertThat(key2.equals(key1), Is.is(false)); + + assertThat(key1.equals("string"), Is.is(false)); + } + + @Test + public void shouldGenerateKey() { + String key = new ServerKeyGenerator().generate("SonarSource"); + assertThat(StringUtils.isNotBlank(key), Is.is(true)); + } + + @Test + public void organizationShouldBeMandatory() { + assertNull(new ServerKeyGenerator().generate(null)); + assertNull(new ServerKeyGenerator().generate("")); + assertNull(new ServerKeyGenerator().generate(" ")); + } + + @Test + public void keyShouldBeUniquePerOrganization() { + ServerKeyGenerator generator = new ServerKeyGenerator(); + String k1 = generator.generate("Corp One"); + String k2 = generator.generate("Corp Two"); + assertThat(StringUtils.equals(k1, k2), Is.is(false)); + } + + @Test + public void keyShouldBeReproducible() { + ServerKeyGenerator generator = new ServerKeyGenerator(); + String k1 = generator.generate("SonarSource"); + String k2 = generator.generate("SonarSource"); + assertThat(StringUtils.equals(k1, k2), Is.is(true)); + } + + @Test + public void shouldNotKeepPreviousKeyIfNotValid() { + ServerKeyGenerator generator = new ServerKeyGenerator(); + String key = generator.generate("SonarSource", "unvalid"); + assertNotNull(key); + assertThat(StringUtils.equals(key, "unvalid"), Is.is(false)); + } + + +} diff --git a/sonar-server/src/test/java/org/sonar/server/platform/ServerLifecycleNotifierTest.java b/sonar-server/src/test/java/org/sonar/server/platform/ServerLifecycleNotifierTest.java index 0e980f3983d..851164b38de 100644 --- a/sonar-server/src/test/java/org/sonar/server/platform/ServerLifecycleNotifierTest.java +++ b/sonar-server/src/test/java/org/sonar/server/platform/ServerLifecycleNotifierTest.java @@ -99,4 +99,8 @@ class FakeServer extends Server { public String getURL() { return null; } + + public String getKey() { + return null; + } } diff --git a/sonar-server/src/test/java/org/sonar/server/startup/ServerMetadataPersisterTest.java b/sonar-server/src/test/java/org/sonar/server/startup/ServerMetadataPersisterTest.java index 81ed38316dd..51b0cf38baf 100644 --- a/sonar-server/src/test/java/org/sonar/server/startup/ServerMetadataPersisterTest.java +++ b/sonar-server/src/test/java/org/sonar/server/startup/ServerMetadataPersisterTest.java @@ -19,42 +19,72 @@ */ package org.sonar.server.startup; +import org.junit.After; +import org.junit.Before; import org.junit.Test; -import org.sonar.jpa.test.AbstractDbUnitTestCase; import org.sonar.api.platform.Server; -import org.sonar.server.platform.ServerImpl; +import org.sonar.jpa.test.AbstractDbUnitTestCase; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.TimeZone; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + public class ServerMetadataPersisterTest extends AbstractDbUnitTestCase { + private TimeZone initialTimeZone; + + @Before + public void fixTimeZone() { + initialTimeZone = TimeZone.getDefault(); + TimeZone.setDefault(TimeZone.getTimeZone("GMT")); + } + + @After + public void revertTimeZone() { + TimeZone.setDefault(initialTimeZone); + } + @Test public void testSaveProperties() throws ParseException { setupData("testSaveProperties"); - persist(); + persist(newServer()); checkTables("testSaveProperties", "properties"); } @Test public void testUpdateExistingProperties() throws ParseException { setupData("testUpdateExistingProperties"); - persist(); + persist(newServer()); checkTables("testUpdateExistingProperties", "properties"); } - private void persist() throws ParseException { - TimeZone initialZone = TimeZone.getDefault(); - try { - TimeZone.setDefault(TimeZone.getTimeZone("GMT")); - Date date = new SimpleDateFormat("yyyy-MM-dd HH:mm").parse("2010-05-18 17:59"); - Server server = new ServerImpl("123", "2.2", date); - ServerMetadataPersister persister = new ServerMetadataPersister(server, getSession()); - persister.start(); - } finally { - TimeZone.setDefault(initialZone); - } + @Test + public void testDeleteProperties() throws ParseException { + setupData("testDeleteProperties"); + Server server = mock(Server.class); + when(server.getStartedAt()).thenReturn(new SimpleDateFormat("yyyy-MM-dd HH:mm").parse("2010-05-18 17:59"));//this is a mandatory not-null property + persist(server); + checkTables("testDeleteProperties", "properties"); + } + + private void persist(Server server) { + ServerMetadataPersister persister = new ServerMetadataPersister(server, getSession()); + persister.start(); + } + + private Server newServer() throws ParseException { + Date date = new SimpleDateFormat("yyyy-MM-dd HH:mm").parse("2010-05-18 17:59"); + Server server = mock(Server.class); + when(server.getKey()).thenReturn("1abcdef"); + when(server.getId()).thenReturn("123"); + when(server.getVersion()).thenReturn("2.2"); + when(server.getStartedAt()).thenReturn(date); + + return server; + } } diff --git a/sonar-server/src/test/resources/org/sonar/server/startup/ServerMetadataPersisterTest/testDeleteProperties-result.xml b/sonar-server/src/test/resources/org/sonar/server/startup/ServerMetadataPersisterTest/testDeleteProperties-result.xml new file mode 100644 index 00000000000..0ade6f49fc9 --- /dev/null +++ b/sonar-server/src/test/resources/org/sonar/server/startup/ServerMetadataPersisterTest/testDeleteProperties-result.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/sonar-server/src/test/resources/org/sonar/server/startup/ServerMetadataPersisterTest/testDeleteProperties.xml b/sonar-server/src/test/resources/org/sonar/server/startup/ServerMetadataPersisterTest/testDeleteProperties.xml new file mode 100644 index 00000000000..8a3add2a585 --- /dev/null +++ b/sonar-server/src/test/resources/org/sonar/server/startup/ServerMetadataPersisterTest/testDeleteProperties.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/sonar-server/src/test/resources/org/sonar/server/startup/ServerMetadataPersisterTest/testSaveProperties-result.xml b/sonar-server/src/test/resources/org/sonar/server/startup/ServerMetadataPersisterTest/testSaveProperties-result.xml index ec292a1388d..8a3add2a585 100644 --- a/sonar-server/src/test/resources/org/sonar/server/startup/ServerMetadataPersisterTest/testSaveProperties-result.xml +++ b/sonar-server/src/test/resources/org/sonar/server/startup/ServerMetadataPersisterTest/testSaveProperties-result.xml @@ -4,6 +4,7 @@ - + + \ No newline at end of file diff --git a/sonar-server/src/test/resources/org/sonar/server/startup/ServerMetadataPersisterTest/testUpdateExistingProperties-result.xml b/sonar-server/src/test/resources/org/sonar/server/startup/ServerMetadataPersisterTest/testUpdateExistingProperties-result.xml index 365acc0ccd3..5d4648e011a 100644 --- a/sonar-server/src/test/resources/org/sonar/server/startup/ServerMetadataPersisterTest/testUpdateExistingProperties-result.xml +++ b/sonar-server/src/test/resources/org/sonar/server/startup/ServerMetadataPersisterTest/testUpdateExistingProperties-result.xml @@ -5,5 +5,5 @@ - + \ No newline at end of file diff --git a/sonar-server/src/test/resources/org/sonar/server/startup/ServerMetadataPersisterTest/testUpdateExistingProperties.xml b/sonar-server/src/test/resources/org/sonar/server/startup/ServerMetadataPersisterTest/testUpdateExistingProperties.xml index 824615a0cc5..bf4537c513d 100644 --- a/sonar-server/src/test/resources/org/sonar/server/startup/ServerMetadataPersisterTest/testUpdateExistingProperties.xml +++ b/sonar-server/src/test/resources/org/sonar/server/startup/ServerMetadataPersisterTest/testUpdateExistingProperties.xml @@ -5,5 +5,6 @@ + \ No newline at end of file -- 2.39.5