From 27b2b56ab4dabb564ebb251c8b9e6c27b3e76606 Mon Sep 17 00:00:00 2001 From: =?utf8?q?S=C3=A9bastien=20Lesaint?= Date: Fri, 18 Mar 2016 14:44:26 +0100 Subject: [PATCH] SONAR-6732 CE and WebServer must share the same startedAt date --- .../ComputeEngineContainerImplTest.java | 13 ++- .../org/sonar/process/ProcessProperties.java | 1 + .../org/sonar/server/platform/ServerImpl.java | 12 ++- .../sonar/server/platform/ServerImplTest.java | 101 +++++++++++++----- .../org/sonar/server/tester/ServerTester.java | 2 + .../main/java/org/sonar/application/App.java | 2 + .../java/org/sonar/application/AppTest.java | 41 ++++--- 7 files changed, 124 insertions(+), 48 deletions(-) diff --git a/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java b/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java index 59f5ae4d1fc..b0075cd6677 100644 --- a/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java +++ b/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java @@ -21,6 +21,7 @@ package org.sonar.ce.container; import java.io.File; import java.io.IOException; +import java.util.Date; import java.util.Properties; import org.apache.commons.dbcp.BasicDataSource; import org.junit.Rule; @@ -30,10 +31,13 @@ import org.picocontainer.MutablePicoContainer; import org.sonar.api.database.DatabaseProperties; import org.sonar.api.utils.System2; import org.sonar.db.DbTester; -import org.sonar.process.ProcessProperties; import org.sonar.process.Props; import static org.assertj.core.api.Assertions.assertThat; +import static org.sonar.process.ProcessProperties.PATH_DATA; +import static org.sonar.process.ProcessProperties.PATH_HOME; +import static org.sonar.process.ProcessProperties.PATH_TEMP; +import static org.sonar.process.ProcessProperties.STARTED_AT; public class ComputeEngineContainerImplTest { private static final int CONTAINER_ITSELF = 1; @@ -57,9 +61,10 @@ public class ComputeEngineContainerImplTest { File homeDir = tempFolder.newFolder(); File dataDir = new File(homeDir, "data"); File tmpDir = new File(homeDir, "tmp"); - properties.setProperty(ProcessProperties.PATH_HOME, homeDir.getAbsolutePath()); - properties.setProperty(ProcessProperties.PATH_DATA, dataDir.getAbsolutePath()); - properties.setProperty(ProcessProperties.PATH_TEMP, tmpDir.getAbsolutePath()); + properties.setProperty(STARTED_AT, String.valueOf(new Date().getTime())); + properties.setProperty(PATH_HOME, homeDir.getAbsolutePath()); + properties.setProperty(PATH_DATA, dataDir.getAbsolutePath()); + properties.setProperty(PATH_TEMP, tmpDir.getAbsolutePath()); String url = ((BasicDataSource) dbTester.database().getDataSource()).getUrl(); properties.setProperty(DatabaseProperties.PROP_URL, url); properties.setProperty(DatabaseProperties.PROP_USER, "sonar"); diff --git a/server/sonar-process/src/main/java/org/sonar/process/ProcessProperties.java b/server/sonar-process/src/main/java/org/sonar/process/ProcessProperties.java index 82f6ac80d4a..b721895f88f 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/ProcessProperties.java +++ b/server/sonar-process/src/main/java/org/sonar/process/ProcessProperties.java @@ -27,6 +27,7 @@ import java.util.Map; * They are almost all the properties defined in conf/sonar.properties. */ public class ProcessProperties { + public static final String STARTED_AT = "sonar.core.startedAt"; public static final String CLUSTER_ACTIVATE = "sonar.cluster.activate"; public static final String CLUSTER_MASTER = "sonar.cluster.master"; diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/ServerImpl.java b/server/sonar-server/src/main/java/org/sonar/server/platform/ServerImpl.java index 3ec74f8c306..3bb1156c454 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/ServerImpl.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/ServerImpl.java @@ -43,16 +43,20 @@ import org.sonar.api.utils.log.Loggers; import org.sonar.process.ProcessProperties; import org.sonar.server.app.TomcatContexts; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; import static org.sonar.api.CoreProperties.SERVER_BASE_URL; import static org.sonar.api.CoreProperties.SERVER_BASE_URL_DEFAULT_VALUE; public final class ServerImpl extends Server implements Startable { + private static final String PROPERTY_SONAR_CORE_STARTED_AT = "sonar.core.startedAt"; + private static final Logger LOG = Loggers.get(ServerImpl.class); private final Settings settings; - private final Date startedAt; private final String buildProperties; private final String versionPath; + private Date startedAt; private String id; private String version; private String implementationBuild; @@ -66,7 +70,6 @@ public final class ServerImpl extends Server implements Startable { @VisibleForTesting ServerImpl(Settings settings, String buildProperties, String versionPath) { this.settings = settings; - this.startedAt = new Date(); this.buildProperties = buildProperties; this.versionPath = versionPath; } @@ -74,6 +77,9 @@ public final class ServerImpl extends Server implements Startable { @Override public void start() { try { + String startedAtString = settings.getString(PROPERTY_SONAR_CORE_STARTED_AT); + checkState(startedAtString != null, "property %s must be set", PROPERTY_SONAR_CORE_STARTED_AT); + startedAt = new Date(Long.valueOf(startedAtString)); id = new SimpleDateFormat("yyyyMMddHHmmss").format(startedAt); version = readVersion(versionPath); @@ -119,7 +125,7 @@ public final class ServerImpl extends Server implements Startable { @Override public Date getStartedAt() { - return startedAt; + return checkNotNull(startedAt, "start() method has not been called"); } @Override diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/ServerImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/ServerImplTest.java index 052a1fbd8e4..2ae0c0f1a21 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/ServerImplTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/platform/ServerImplTest.java @@ -20,6 +20,9 @@ package org.sonar.server.platform; import java.io.File; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; import org.hamcrest.core.Is; import org.junit.Before; import org.junit.Rule; @@ -37,48 +40,88 @@ public class ServerImplTest { @Rule public ExpectedException exception = ExpectedException.none(); - @Rule public TemporaryFolder sonarHome = new TemporaryFolder(); - Settings settings; + private Date someDate; + private Settings settings; - ServerImpl server; + ServerImpl underTest; @Before - public void setUp() { - settings = new Settings().setProperty(ProcessProperties.PATH_HOME, sonarHome.getRoot().getAbsolutePath()); + public void setUp() throws ParseException { + this.someDate = new SimpleDateFormat("ddMMyyyy").parse("24101236"); + this.settings = new Settings().setProperty(ProcessProperties.PATH_HOME, sonarHome.getRoot().getAbsolutePath()); + this.settings.setProperty(ProcessProperties.STARTED_AT, someDate.getTime()); new File(sonarHome.getRoot(), "web/deploy").mkdirs(); - server = new ServerImpl(settings, "/org/sonar/server/platform/ServerImplTest/build.properties", "/org/sonar/server/platform/ServerImplTest/version.txt"); + underTest = new ServerImpl(settings, "/org/sonar/server/platform/ServerImplTest/build.properties", "/org/sonar/server/platform/ServerImplTest/version.txt"); } @Test - public void always_return_the_same_values() { + public void getStartedAt_throws_NPE_if_start_has_not_been_called() { + exception.expect(NullPointerException.class); + exception.expectMessage("start() method has not been called"); + + underTest.getStartedAt(); + } + + @Test + public void getStartedAt_is_date_from_sonar_core_startedAt() throws ParseException { + underTest.start(); + + assertThat(underTest.getStartedAt()).isEqualTo(someDate); + } + + @Test + public void start_fails_with_NFE_if_date_from_sonar_core_startedAt_is_invalid() throws ParseException { + settings.setProperty(ProcessProperties.STARTED_AT, "aasasa"); + + ServerImpl server = new ServerImpl(settings, "/org/sonar/server/platform/ServerImplTest/build.properties", "/org/sonar/server/platform/ServerImplTest/version.txt"); + + exception.expect(NumberFormatException.class); + server.start(); + } + + @Test + public void start_fails_with_ISE_sonar_core_startedAt_is_not_set() throws ParseException { + settings.removeProperty(ProcessProperties.STARTED_AT); - assertThat(server.getId()).isNotNull(); - assertThat(server.getId()).isEqualTo(server.getId()); + ServerImpl server = new ServerImpl(settings, "/org/sonar/server/platform/ServerImplTest/build.properties", "/org/sonar/server/platform/ServerImplTest/version.txt"); - assertThat(server.getVersion()).isNotNull(); - assertThat(server.getVersion()).isEqualTo(server.getVersion()); + exception.expect(IllegalStateException.class); + exception.expectMessage("property sonar.core.startedAt must be set"); - assertThat(server.getStartedAt()).isNotNull(); - assertThat(server.getStartedAt()).isEqualTo(server.getStartedAt()); + server.start(); + } + + @Test + public void always_return_the_same_values() { + underTest.start(); + + assertThat(underTest.getId()).isNotNull(); + assertThat(underTest.getId()).isEqualTo(underTest.getId()); + + assertThat(underTest.getVersion()).isNotNull(); + assertThat(underTest.getVersion()).isEqualTo(underTest.getVersion()); + + assertThat(underTest.getStartedAt()).isNotNull(); + assertThat(underTest.getStartedAt()).isEqualTo(underTest.getStartedAt()); } @Test public void read_version_from_file() { - server.start(); + underTest.start(); - assertThat(server.getVersion()).isEqualTo("1.0"); + assertThat(underTest.getVersion()).isEqualTo("1.0"); } @Test public void read_implementation_build_from_manifest() { - server.start(); + underTest.start(); - assertThat(server.getImplementationBuild()).isEqualTo("0b9545a8b74aca473cb776275be4dc93a327c363"); + assertThat(underTest.getImplementationBuild()).isEqualTo("0b9545a8b74aca473cb776275be4dc93a327c363"); } @Test @@ -120,41 +163,41 @@ public class ServerImplTest { @Test public void use_default_context_path() { - server.start(); - assertThat(server.getContextPath()).isEqualTo(""); + underTest.start(); + assertThat(underTest.getContextPath()).isEqualTo(""); } @Test public void is_dev() throws Exception { settings.setProperty("sonar.web.dev", true); - server.start(); - assertThat(server.isDev()).isTrue(); + underTest.start(); + assertThat(underTest.isDev()).isTrue(); } @Test public void get_default_public_root_url() throws Exception { - server.start(); - assertThat(server.getPublicRootUrl()).isEqualTo("http://localhost:9000"); + underTest.start(); + assertThat(underTest.getPublicRootUrl()).isEqualTo("http://localhost:9000"); } @Test public void get_public_root_url() throws Exception { settings.setProperty("sonar.core.serverBaseURL", "http://mydomain.com"); - server.start(); - assertThat(server.getPublicRootUrl()).isEqualTo("http://mydomain.com"); + underTest.start(); + assertThat(underTest.getPublicRootUrl()).isEqualTo("http://mydomain.com"); } @Test public void is_secured_on_secured_server() throws Exception { settings.setProperty("sonar.core.serverBaseURL", "https://mydomain.com"); - server.start(); - assertThat(server.isSecured()).isTrue(); + underTest.start(); + assertThat(underTest.isSecured()).isTrue(); } @Test public void is_secured_on_not_secured_server() throws Exception { settings.setProperty("sonar.core.serverBaseURL", "http://mydomain.com"); - server.start(); - assertThat(server.isSecured()).isFalse(); + underTest.start(); + assertThat(underTest.isSecured()).isFalse(); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/tester/ServerTester.java b/server/sonar-server/src/test/java/org/sonar/server/tester/ServerTester.java index 22130902b31..d194d1a6863 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/tester/ServerTester.java +++ b/server/sonar-server/src/test/java/org/sonar/server/tester/ServerTester.java @@ -26,6 +26,7 @@ import java.io.File; import java.io.IOException; import java.net.URL; import java.util.Arrays; +import java.util.Date; import java.util.List; import java.util.Map; import java.util.Properties; @@ -102,6 +103,7 @@ public class ServerTester extends ExternalResource { Properties properties = new Properties(); properties.putAll(initialProps); esServerHolder = EsServerHolder.get(); + properties.setProperty(ProcessProperties.STARTED_AT, String.valueOf(new Date().getTime())); properties.setProperty(ProcessProperties.CLUSTER_NAME, esServerHolder.getClusterName()); properties.setProperty(ProcessProperties.CLUSTER_NODE_NAME, esServerHolder.getNodeName()); properties.setProperty(ProcessProperties.SEARCH_PORT, String.valueOf(esServerHolder.getPort())); diff --git a/sonar-application/src/main/java/org/sonar/application/App.java b/sonar-application/src/main/java/org/sonar/application/App.java index 7067d122d11..35e9f491694 100644 --- a/sonar-application/src/main/java/org/sonar/application/App.java +++ b/sonar-application/src/main/java/org/sonar/application/App.java @@ -21,6 +21,7 @@ package org.sonar.application; import java.io.File; import java.util.ArrayList; +import java.util.Date; import java.util.List; import java.util.Properties; import org.apache.commons.io.FilenameUtils; @@ -59,6 +60,7 @@ public class App implements Stoppable { private static List createCommands(Props props) { File homeDir = props.nonNullValueAsFile(ProcessProperties.PATH_HOME); + props.set(ProcessProperties.STARTED_AT, String.valueOf(new Date().getTime())); List commands = new ArrayList<>(3); commands.add(createESCommand(props, homeDir)); diff --git a/sonar-application/src/test/java/org/sonar/application/AppTest.java b/sonar-application/src/test/java/org/sonar/application/AppTest.java index 04f0da47559..70f694c97dc 100644 --- a/sonar-application/src/test/java/org/sonar/application/AppTest.java +++ b/sonar-application/src/test/java/org/sonar/application/AppTest.java @@ -19,6 +19,10 @@ */ package org.sonar.application; +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Properties; import org.apache.commons.io.FilenameUtils; import org.junit.Rule; import org.junit.Test; @@ -29,11 +33,6 @@ import org.sonar.process.Props; import org.sonar.process.monitor.JavaCommand; import org.sonar.process.monitor.Monitor; -import java.io.File; -import java.io.IOException; -import java.util.List; -import java.util.Properties; - import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -59,28 +58,42 @@ public class AppTest { Props props = initDefaultProps(); app.start(props); - Class> listClass = (Class>)(Class)List.class; - ArgumentCaptor> argument = ArgumentCaptor.forClass(listClass); + ArgumentCaptor> argument = newJavaCommandArgumentCaptor(); verify(monitor).start(argument.capture()); assertThat(argument.getValue()).extracting("key").containsExactly("search", "web", "ce"); } @Test - public void do_not_start_tomcat_if_elasticsearch_slave() throws Exception { + public void do_not_start_WebServer_nor_CE_if_elasticsearch_slave() throws Exception { Monitor monitor = mock(Monitor.class); App app = new App(monitor); Props props = initDefaultProps(); props.set("sonar.cluster.masterHost", "1.2.3.4"); app.start(props); - Class> listClass = (Class>)(Class)List.class; - ArgumentCaptor> argument = ArgumentCaptor.forClass(listClass); + ArgumentCaptor> argument = newJavaCommandArgumentCaptor(); verify(monitor).start(argument.capture()); assertThat(argument.getValue()).extracting("key").containsOnly("search"); } + @Test + public void all_JavaCommand_have_a_sonar_core_startedAt_property_argument() throws IOException { + Monitor monitor = mock(Monitor.class); + App app = new App(monitor); + Props props = initDefaultProps(); + app.start(props); + + ArgumentCaptor> argument = newJavaCommandArgumentCaptor(); + verify(monitor).start(argument.capture()); + + List javaCommands = argument.getValue(); + for (JavaCommand javaCommand : javaCommands) { + assertThat(javaCommand.getArguments()).containsKey(ProcessProperties.STARTED_AT); + } + } + @Test public void add_custom_jdbc_driver_to_tomcat_classpath() throws Exception { Monitor monitor = mock(Monitor.class); @@ -89,8 +102,7 @@ public class AppTest { props.set("sonar.jdbc.driverPath", "oracle/ojdbc6.jar"); app.start(props); - Class> listClass = (Class>)(Class)List.class; - ArgumentCaptor> argument = ArgumentCaptor.forClass(listClass); + ArgumentCaptor> argument = newJavaCommandArgumentCaptor(); verify(monitor).start(argument.capture()); assertThat(argument.getValue().get(1).getClasspath()).contains("oracle/ojdbc6.jar"); @@ -104,4 +116,9 @@ public class AppTest { props.set(ProcessProperties.PATH_LOGS, temp.newFolder().getAbsolutePath()); return props; } + + private ArgumentCaptor> newJavaCommandArgumentCaptor() { + Class> listClass = (Class>) (Class) List.class; + return ArgumentCaptor.forClass(listClass); + } } -- 2.39.5