aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sonar-application/src/main/java/org/sonar/application/App.java98
-rw-r--r--sonar-application/src/main/java/org/sonar/application/JavaCommandFactory.java32
-rw-r--r--sonar-application/src/main/java/org/sonar/application/JavaCommandFactoryImpl.java114
-rw-r--r--sonar-application/src/test/java/org/sonar/application/AppTest.java98
-rw-r--r--sonar-application/src/test/java/org/sonar/application/JavaCommandFactoryImplTest.java407
5 files changed, 592 insertions, 157 deletions
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 7271d593ad8..d6c3b843a85 100644
--- a/sonar-application/src/main/java/org/sonar/application/App.java
+++ b/sonar-application/src/main/java/org/sonar/application/App.java
@@ -27,7 +27,6 @@ import org.apache.commons.io.FilenameUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.process.Lifecycle;
-import org.sonar.process.ProcessId;
import org.sonar.process.ProcessProperties;
import org.sonar.process.Props;
import org.sonar.process.Stoppable;
@@ -36,29 +35,13 @@ import org.sonar.process.monitor.Monitor;
import static org.sonar.process.Lifecycle.State;
import static org.sonar.process.ProcessId.APP;
-import static org.sonar.process.ProcessProperties.HTTPS_PROXY_HOST;
-import static org.sonar.process.ProcessProperties.HTTPS_PROXY_PORT;
-import static org.sonar.process.ProcessProperties.HTTP_PROXY_HOST;
-import static org.sonar.process.ProcessProperties.HTTP_PROXY_PORT;
/**
* Entry-point of process that starts and monitors ElasticSearch, the Web Server and the Compute Engine.
*/
public class App implements Stoppable {
- /**
- * Properties about proxy that must be set as system properties
- */
- private static final String[] PROXY_PROPERTY_KEYS = new String[] {
- HTTP_PROXY_HOST,
- HTTP_PROXY_PORT,
- "http.nonProxyHosts",
- HTTPS_PROXY_HOST,
- HTTPS_PROXY_PORT,
- "http.auth.ntlm.domain",
- "socksProxyHost",
- "socksProxyPort"};
-
+ private final JavaCommandFactory javaCommandFactory;
private final Monitor monitor;
public App(AppFileSystem appFileSystem, boolean watchForHardStop) {
@@ -68,10 +51,12 @@ public class App implements Stoppable {
.setWatchForHardStop(watchForHardStop)
.setWaitForOperational()
.addListener(new AppLifecycleListener())
- .build());
+ .build(),
+ new JavaCommandFactoryImpl());
}
- App(Monitor monitor) {
+ App(Monitor monitor, JavaCommandFactory javaCommandFactory) {
+ this.javaCommandFactory = javaCommandFactory;
this.monitor = monitor;
}
@@ -80,19 +65,19 @@ public class App implements Stoppable {
monitor.awaitTermination();
}
- private static List<JavaCommand> createCommands(Props props) {
+ private List<JavaCommand> createCommands(Props props) {
File homeDir = props.nonNullValueAsFile(ProcessProperties.PATH_HOME);
List<JavaCommand> commands = new ArrayList<>(3);
if (isProcessEnabled(props, ProcessProperties.CLUSTER_SEARCH_DISABLED)) {
- commands.add(createESCommand(props, homeDir));
+ commands.add(javaCommandFactory.createESCommand(props, homeDir));
}
if (isProcessEnabled(props, ProcessProperties.CLUSTER_WEB_DISABLED)) {
- commands.add(createWebServerCommand(props, homeDir));
+ commands.add(javaCommandFactory.createWebCommand(props, homeDir));
}
if (isProcessEnabled(props, ProcessProperties.CLUSTER_CE_DISABLED)) {
- commands.add(createCeServerCommand(props, homeDir));
+ commands.add(javaCommandFactory.createCeCommand(props, homeDir));
}
return commands;
@@ -103,71 +88,6 @@ public class App implements Stoppable {
!props.valueAsBoolean(disabledPropertyKey);
}
- private static JavaCommand createESCommand(Props props, File homeDir) {
- return newJavaCommand(ProcessId.ELASTICSEARCH, props, homeDir)
- .addJavaOptions("-Djava.awt.headless=true")
- .addJavaOptions(props.nonNullValue(ProcessProperties.SEARCH_JAVA_OPTS))
- .addJavaOptions(props.nonNullValue(ProcessProperties.SEARCH_JAVA_ADDITIONAL_OPTS))
- .setClassName("org.sonar.search.SearchServer")
- .addClasspath("./lib/common/*")
- .addClasspath("./lib/search/*");
- }
-
- private static JavaCommand createWebServerCommand(Props props, File homeDir) {
- JavaCommand command = newJavaCommand(ProcessId.WEB_SERVER, props, homeDir)
- .addJavaOptions(ProcessProperties.WEB_ENFORCED_JVM_ARGS)
- .addJavaOptions(props.nonNullValue(ProcessProperties.WEB_JAVA_OPTS))
- .addJavaOptions(props.nonNullValue(ProcessProperties.WEB_JAVA_ADDITIONAL_OPTS))
- // required for logback tomcat valve
- .setEnvVariable(ProcessProperties.PATH_LOGS, props.nonNullValue(ProcessProperties.PATH_LOGS))
- .setClassName("org.sonar.server.app.WebServer")
- .addClasspath("./lib/common/*")
- .addClasspath("./lib/server/*");
- String driverPath = props.value(ProcessProperties.JDBC_DRIVER_PATH);
- if (driverPath != null) {
- command.addClasspath(driverPath);
- }
- return command;
- }
-
- private static JavaCommand createCeServerCommand(Props props, File homeDir) {
- JavaCommand command = newJavaCommand(ProcessId.COMPUTE_ENGINE, props, homeDir)
- .addJavaOptions(ProcessProperties.CE_ENFORCED_JVM_ARGS)
- .addJavaOptions(props.nonNullValue(ProcessProperties.CE_JAVA_OPTS))
- .addJavaOptions(props.nonNullValue(ProcessProperties.CE_JAVA_ADDITIONAL_OPTS))
- .setClassName("org.sonar.ce.app.CeServer")
- .addClasspath("./lib/common/*")
- .addClasspath("./lib/server/*")
- .addClasspath("./lib/ce/*");
- String driverPath = props.value(ProcessProperties.JDBC_DRIVER_PATH);
- if (driverPath != null) {
- command.addClasspath(driverPath);
- }
- return command;
- }
-
- private static JavaCommand newJavaCommand(ProcessId id, Props props, File homeDir) {
- JavaCommand command = new JavaCommand(id)
- .setWorkDir(homeDir)
- .setArguments(props.rawProperties());
-
- for (String key : PROXY_PROPERTY_KEYS) {
- if (props.contains(key)) {
- command.addJavaOption("-D" + key + "=" + props.value(key));
- }
- }
- // defaults of HTTPS are the same than HTTP defaults
- setSystemPropertyToDefaultIfNotSet(command, props, HTTPS_PROXY_HOST, HTTP_PROXY_HOST);
- setSystemPropertyToDefaultIfNotSet(command, props, HTTPS_PROXY_PORT, HTTP_PROXY_PORT);
- return command;
- }
-
- private static void setSystemPropertyToDefaultIfNotSet(JavaCommand command, Props props, String httpsProperty, String httpProperty) {
- if (!props.contains(httpsProperty) && props.contains(httpProperty)) {
- command.addJavaOption("-D" + httpsProperty + "=" + props.value(httpProperty));
- }
- }
-
static String starPath(File homeDir, String relativePath) {
File dir = new File(homeDir, relativePath);
return FilenameUtils.concat(dir.getAbsolutePath(), "*");
diff --git a/sonar-application/src/main/java/org/sonar/application/JavaCommandFactory.java b/sonar-application/src/main/java/org/sonar/application/JavaCommandFactory.java
new file mode 100644
index 00000000000..0071a3619d8
--- /dev/null
+++ b/sonar-application/src/main/java/org/sonar/application/JavaCommandFactory.java
@@ -0,0 +1,32 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info 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.application;
+
+import java.io.File;
+import org.sonar.process.Props;
+import org.sonar.process.monitor.JavaCommand;
+
+public interface JavaCommandFactory {
+ JavaCommand createESCommand(Props props, File homeDir);
+
+ JavaCommand createWebCommand(Props props, File homeDir);
+
+ JavaCommand createCeCommand(Props props, File homeDir);
+}
diff --git a/sonar-application/src/main/java/org/sonar/application/JavaCommandFactoryImpl.java b/sonar-application/src/main/java/org/sonar/application/JavaCommandFactoryImpl.java
new file mode 100644
index 00000000000..4f9ebd80ed8
--- /dev/null
+++ b/sonar-application/src/main/java/org/sonar/application/JavaCommandFactoryImpl.java
@@ -0,0 +1,114 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info 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.application;
+
+import java.io.File;
+import org.sonar.process.ProcessId;
+import org.sonar.process.ProcessProperties;
+import org.sonar.process.Props;
+import org.sonar.process.monitor.JavaCommand;
+
+import static org.sonar.process.ProcessProperties.HTTPS_PROXY_HOST;
+import static org.sonar.process.ProcessProperties.HTTPS_PROXY_PORT;
+import static org.sonar.process.ProcessProperties.HTTP_PROXY_HOST;
+import static org.sonar.process.ProcessProperties.HTTP_PROXY_PORT;
+
+public class JavaCommandFactoryImpl implements JavaCommandFactory {
+ /**
+ * Properties about proxy that must be set as system properties
+ */
+ private static final String[] PROXY_PROPERTY_KEYS = new String[] {
+ HTTP_PROXY_HOST,
+ HTTP_PROXY_PORT,
+ "http.nonProxyHosts",
+ HTTPS_PROXY_HOST,
+ HTTPS_PROXY_PORT,
+ "http.auth.ntlm.domain",
+ "socksProxyHost",
+ "socksProxyPort"};
+
+ @Override
+ public JavaCommand createESCommand(Props props, File workDir) {
+ return newJavaCommand(ProcessId.ELASTICSEARCH, props, workDir)
+ .addJavaOptions("-Djava.awt.headless=true")
+ .addJavaOptions(props.nonNullValue(ProcessProperties.SEARCH_JAVA_OPTS))
+ .addJavaOptions(props.nonNullValue(ProcessProperties.SEARCH_JAVA_ADDITIONAL_OPTS))
+ .setClassName("org.sonar.search.SearchServer")
+ .addClasspath("./lib/common/*")
+ .addClasspath("./lib/search/*");
+ }
+
+ @Override
+ public JavaCommand createWebCommand(Props props, File workDir) {
+ JavaCommand command = newJavaCommand(ProcessId.WEB_SERVER, props, workDir)
+ .addJavaOptions(ProcessProperties.WEB_ENFORCED_JVM_ARGS)
+ .addJavaOptions(props.nonNullValue(ProcessProperties.WEB_JAVA_OPTS))
+ .addJavaOptions(props.nonNullValue(ProcessProperties.WEB_JAVA_ADDITIONAL_OPTS))
+ // required for logback tomcat valve
+ .setEnvVariable(ProcessProperties.PATH_LOGS, props.nonNullValue(ProcessProperties.PATH_LOGS))
+ .setClassName("org.sonar.server.app.WebServer")
+ .addClasspath("./lib/common/*")
+ .addClasspath("./lib/server/*");
+ String driverPath = props.value(ProcessProperties.JDBC_DRIVER_PATH);
+ if (driverPath != null) {
+ command.addClasspath(driverPath);
+ }
+ return command;
+ }
+
+ @Override
+ public JavaCommand createCeCommand(Props props, File workDir) {
+ JavaCommand command = newJavaCommand(ProcessId.COMPUTE_ENGINE, props, workDir)
+ .addJavaOptions(ProcessProperties.CE_ENFORCED_JVM_ARGS)
+ .addJavaOptions(props.nonNullValue(ProcessProperties.CE_JAVA_OPTS))
+ .addJavaOptions(props.nonNullValue(ProcessProperties.CE_JAVA_ADDITIONAL_OPTS))
+ .setClassName("org.sonar.ce.app.CeServer")
+ .addClasspath("./lib/common/*")
+ .addClasspath("./lib/server/*")
+ .addClasspath("./lib/ce/*");
+ String driverPath = props.value(ProcessProperties.JDBC_DRIVER_PATH);
+ if (driverPath != null) {
+ command.addClasspath(driverPath);
+ }
+ return command;
+ }
+
+ private static JavaCommand newJavaCommand(ProcessId id, Props props, File workDir) {
+ JavaCommand command = new JavaCommand(id)
+ .setWorkDir(workDir)
+ .setArguments(props.rawProperties());
+
+ for (String key : PROXY_PROPERTY_KEYS) {
+ if (props.contains(key)) {
+ command.addJavaOption("-D" + key + "=" + props.value(key));
+ }
+ }
+ // defaults of HTTPS are the same than HTTP defaults
+ setSystemPropertyToDefaultIfNotSet(command, props, HTTPS_PROXY_HOST, HTTP_PROXY_HOST);
+ setSystemPropertyToDefaultIfNotSet(command, props, HTTPS_PROXY_PORT, HTTP_PROXY_PORT);
+ return command;
+ }
+
+ private static void setSystemPropertyToDefaultIfNotSet(JavaCommand command, Props props, String httpsProperty, String httpProperty) {
+ if (!props.contains(httpsProperty) && props.contains(httpProperty)) {
+ command.addJavaOption("-D" + httpsProperty + "=" + props.value(httpProperty));
+ }
+ }
+}
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 e335cbd9c9d..70bec0bb1d1 100644
--- a/sonar-application/src/test/java/org/sonar/application/AppTest.java
+++ b/sonar-application/src/test/java/org/sonar/application/AppTest.java
@@ -29,7 +29,6 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.mockito.ArgumentCaptor;
-import org.sonar.process.ProcessId;
import org.sonar.process.ProcessProperties;
import org.sonar.process.Props;
import org.sonar.process.monitor.JavaCommand;
@@ -44,6 +43,27 @@ public class AppTest {
@Rule
public TemporaryFolder temp = new TemporaryFolder();
+ private final JavaCommand esCommand = mock(JavaCommand.class);
+ private final JavaCommand webCommand = mock(JavaCommand.class);
+ private final JavaCommand ceCommand = mock(JavaCommand.class);
+ private final JavaCommandFactory javaCommandFactory = new JavaCommandFactory() {
+
+ @Override
+ public JavaCommand createESCommand(Props props, File homeDir) {
+ return AppTest.this.esCommand;
+ }
+
+ @Override
+ public JavaCommand createWebCommand(Props props, File homeDir) {
+ return AppTest.this.webCommand;
+ }
+
+ @Override
+ public JavaCommand createCeCommand(Props props, File homeDir) {
+ return AppTest.this.ceCommand;
+ }
+ };
+
@Test
public void starPath() throws IOException {
File homeDir = temp.newFolder();
@@ -57,11 +77,13 @@ public class AppTest {
public void start_all_processes_if_cluster_mode_is_disabled() throws Exception {
Props props = initDefaultProps();
Monitor monitor = mock(Monitor.class);
- App app = new App(monitor);
+ App app = new App(monitor, javaCommandFactory);
app.start(props);
+
ArgumentCaptor<Supplier<List<JavaCommand>>> argument = newJavaCommandArgumentCaptor();
verify(monitor).start(argument.capture());
- assertThat(argument.getValue().get()).extracting("processId").containsExactly(ProcessId.ELASTICSEARCH, ProcessId.WEB_SERVER, ProcessId.COMPUTE_ENGINE);
+ assertThat(argument.getValue().get())
+ .containsExactly(esCommand, webCommand, ceCommand);
app.stopAsync();
verify(monitor).stop();
@@ -76,7 +98,7 @@ public class AppTest {
List<JavaCommand> commands = start(props);
- assertThat(commands).extracting("processId").containsOnly(ProcessId.WEB_SERVER);
+ assertThat(commands).containsOnly(webCommand);
}
@Test
@@ -88,7 +110,7 @@ public class AppTest {
List<JavaCommand> commands = start(props);
- assertThat(commands).extracting("processId").containsOnly(ProcessId.COMPUTE_ENGINE);
+ assertThat(commands).contains(ceCommand);
}
@Test
@@ -100,68 +122,7 @@ public class AppTest {
List<JavaCommand> commands = start(props);
- assertThat(commands).extracting("processId").containsOnly(ProcessId.ELASTICSEARCH);
- }
-
- @Test
- public void add_custom_jdbc_driver_to_tomcat_classpath() throws Exception {
- Props props = initDefaultProps();
- props.set("sonar.jdbc.driverPath", "oracle/ojdbc6.jar");
-
- List<JavaCommand> commands = start(props);
-
- assertThat(commands.get(1).getClasspath()).contains("oracle/ojdbc6.jar");
- }
-
- @Test
- public void configure_http_and_https_proxies_on_all_processes() throws Exception {
- Props props = initDefaultProps();
- // These properties can be defined in conf/sonar.properties.
- // They must be propagated to JVM.
- props.set("http.proxyHost", "1.2.3.4");
- props.set("http.proxyPort", "80");
- props.set("https.proxyHost", "5.6.7.8");
- props.set("https.proxyPort", "443");
-
- List<JavaCommand> commands = start(props);
- assertThat(commands).isNotEmpty();
-
- for (JavaCommand command : commands) {
- assertThat(command.getJavaOptions()).contains("-Dhttp.proxyHost=1.2.3.4");
- assertThat(command.getJavaOptions()).contains("-Dhttp.proxyPort=80");
- assertThat(command.getJavaOptions()).contains("-Dhttps.proxyHost=5.6.7.8");
- assertThat(command.getJavaOptions()).contains("-Dhttps.proxyPort=443");
- }
- }
-
- @Test
- public void https_proxy_defaults_are_http_proxy_properties() throws Exception {
- Props props = initDefaultProps();
- props.set("http.proxyHost", "1.2.3.4");
- props.set("http.proxyPort", "80");
-
- List<JavaCommand> commands = start(props);
- assertThat(commands).isNotEmpty();
-
- for (JavaCommand command : commands) {
- assertThat(command.getJavaOptions()).contains("-Dhttp.proxyHost=1.2.3.4");
- assertThat(command.getJavaOptions()).contains("-Dhttp.proxyPort=80");
- assertThat(command.getJavaOptions()).contains("-Dhttps.proxyHost=1.2.3.4");
- assertThat(command.getJavaOptions()).contains("-Dhttps.proxyPort=80");
- }
- }
-
- @Test
- public void no_http_proxy_settings_by_default() throws Exception {
- List<JavaCommand> commands = start(initDefaultProps());
-
- assertThat(commands).isNotEmpty();
- for (JavaCommand command : commands) {
- assertThat(command.getJavaOptions()).doesNotContain("http.proxyHost");
- assertThat(command.getJavaOptions()).doesNotContain("https.proxyHost");
- assertThat(command.getJavaOptions()).doesNotContain("http.proxyPort");
- assertThat(command.getJavaOptions()).doesNotContain("https.proxyPort");
- }
+ assertThat(commands).containsOnly(esCommand);
}
private Props initDefaultProps() throws IOException {
@@ -175,7 +136,7 @@ public class AppTest {
private List<JavaCommand> start(Props props) throws Exception {
Monitor monitor = mock(Monitor.class);
- App app = new App(monitor);
+ App app = new App(monitor, javaCommandFactory);
app.start(props);
ArgumentCaptor<Supplier<List<JavaCommand>>> argument = newJavaCommandArgumentCaptor();
verify(monitor).start(argument.capture());
@@ -186,4 +147,5 @@ public class AppTest {
Class<Supplier<List<JavaCommand>>> listClass = (Class<Supplier<List<JavaCommand>>>) (Class) List.class;
return ArgumentCaptor.forClass(listClass);
}
+
}
diff --git a/sonar-application/src/test/java/org/sonar/application/JavaCommandFactoryImplTest.java b/sonar-application/src/test/java/org/sonar/application/JavaCommandFactoryImplTest.java
new file mode 100644
index 00000000000..fc3bb457846
--- /dev/null
+++ b/sonar-application/src/test/java/org/sonar/application/JavaCommandFactoryImplTest.java
@@ -0,0 +1,407 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info 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.application;
+
+import java.io.File;
+import java.util.Map;
+import java.util.Properties;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.process.ProcessId;
+import org.sonar.process.Props;
+import org.sonar.process.monitor.JavaCommand;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.entry;
+
+public class JavaCommandFactoryImplTest {
+ private static final String SEARCH_JAVA_OPTS = "sonar.search.javaOpts";
+ private static final String SEARCH_JAVA_ADDITIONAL_OPTS = "sonar.search.javaAdditionalOpts";
+ private static final String WEB_JAVA_OPTS = "sonar.web.javaOpts";
+ private static final String WEB_JAVA_ADDITIONAL_OPTS = "sonar.web.javaAdditionalOpts";
+ private static final String CE_JAVA_OPTS = "sonar.ce.javaOpts";
+ private static final String CE_JAVA_ADDITIONAL_OPTS = "sonar.ce.javaAdditionalOpts";
+ private static final String PATH_LOGS = "sonar.path.logs";
+ private static final String JDBC_DRIVER_PATH = "sonar.jdbc.driverPath";
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ private File homeDir;
+ private JavaCommandFactoryImpl underTest = new JavaCommandFactoryImpl();
+
+ @Before
+ public void setUp() throws Exception {
+ homeDir = temp.newFolder();
+ }
+
+ @Test
+ public void createEsCommand_fails_if_search_javaOpts_property_is_not_set() {
+ expectMissingPropertyIAE(SEARCH_JAVA_OPTS);
+
+ underTest.createESCommand(newProps(), homeDir);
+ }
+
+ @Test
+ public void createEsCommand_fails_if_search_javaAdditionalOpts_property_is_not_set() {
+ expectMissingPropertyIAE(SEARCH_JAVA_ADDITIONAL_OPTS);
+
+ underTest.createESCommand(newProps(SEARCH_JAVA_OPTS, "foo"), homeDir);
+ }
+
+ @Test
+ public void createEsCommand_sets_SearchServer_for_className() {
+ JavaCommand javaCommand = underTest.createESCommand(newPropsWithRequiredProperties(), homeDir);
+
+ assertThat(javaCommand.getClassName()).isEqualTo("org.sonar.search.SearchServer");
+ }
+
+ @Test
+ public void createESCommand_puts_common_and_search_lib_directories_in_classpath() {
+ JavaCommand javaCommand = underTest.createESCommand(newPropsWithRequiredProperties(), homeDir);
+
+ assertThat(javaCommand.getClasspath()).containsOnly("./lib/common/*", "./lib/search/*");
+ }
+
+ @Test
+ public void createESCommand_adds_headless_java_option() {
+ JavaCommand javaCommand = underTest.createESCommand(newPropsWithRequiredProperties(), homeDir);
+
+ assertThat(javaCommand.getJavaOptions()).contains("-Djava.awt.headless=true");
+ }
+
+ @Test
+ public void createESCommand_adds_search_javaOpts_and_javaAdditionalOpts_java_options() {
+ JavaCommand javaCommand = underTest.createESCommand(newPropsWithRequiredProperties(), homeDir);
+
+ assertThat(javaCommand.getJavaOptions()).contains(mockValueFor(SEARCH_JAVA_OPTS), mockValueFor(SEARCH_JAVA_ADDITIONAL_OPTS));
+ }
+
+ @Test
+ public void createESCommand_sets_ES_processId() {
+ JavaCommand javaCommand = underTest.createESCommand(newPropsWithRequiredProperties(), homeDir);
+
+ assertThat(javaCommand.getProcessId()).isSameAs(ProcessId.ELASTICSEARCH);
+ }
+
+ @Test
+ public void createESCommand_sets_workdir_to_argument() {
+ JavaCommand javaCommand = underTest.createESCommand(newPropsWithRequiredProperties(), homeDir);
+
+ assertThat(javaCommand.getWorkDir()).isSameAs(homeDir);
+ }
+
+ @Test
+ public void createESCommand_add_options_for_http_and_https_proxies_from_props() throws Exception {
+ addOptionsForHttpAndHttpsProxiesFromProps((props, fileDir) -> underTest.createESCommand(props, fileDir));
+ }
+
+ @Test
+ public void createESCommand_use_http_properties_from_props_as_defaults_for_https_properties() throws Exception {
+ userHttpPropertiesFromPropsAsDefaultForHttpsProperties((props, file) -> underTest.createESCommand(props, file));
+ }
+
+ @Test
+ public void createEsCommand_add_no_proxy_option_if_no_proxy_property_in_props() throws Exception {
+ noProxyOptionIfNoProxyPropertyInProps((props, file) -> underTest.createESCommand(props, file));
+ }
+
+ @Test
+ public void createEsCommand_passes_rawProperties_of_Props_argument_as_argument_of_javaCommand() {
+ passesRawPropertiesOfPropsAsArgumentsOfJavaCommand((props, fileDir) -> underTest.createESCommand(props, fileDir));
+ }
+
+ @Test
+ public void createWebCommand_fails_if_web_javaOpts_property_is_not_set() {
+ expectMissingPropertyIAE(WEB_JAVA_OPTS);
+
+ underTest.createWebCommand(newProps(), homeDir);
+ }
+
+ @Test
+ public void createWebCommand_fails_if_web_javaAdditionalOpts_property_is_not_set() {
+ expectMissingPropertyIAE(WEB_JAVA_ADDITIONAL_OPTS);
+
+ underTest.createWebCommand(newProps(WEB_JAVA_OPTS, "foo"), homeDir);
+ }
+
+ @Test
+ public void createWebCommand_fails_if_log_dir_path_property_is_not_set() {
+ expectMissingPropertyIAE(PATH_LOGS);
+
+ underTest.createWebCommand(newProps(WEB_JAVA_OPTS, "foo", WEB_JAVA_ADDITIONAL_OPTS, "bar"), homeDir);
+ }
+
+ @Test
+ public void createWebCommand_sets_SearchServer_for_className() {
+ JavaCommand javaCommand = underTest.createWebCommand(newPropsWithRequiredProperties(), homeDir);
+
+ assertThat(javaCommand.getClassName()).isEqualTo("org.sonar.server.app.WebServer");
+ }
+
+ @Test
+ public void createWebCommand_puts_common_and_server_lib_directories_in_classpath() {
+ JavaCommand javaCommand = underTest.createWebCommand(newPropsWithRequiredProperties(), homeDir);
+
+ assertThat(javaCommand.getClasspath()).containsOnly("./lib/common/*", "./lib/server/*");
+ }
+
+ @Test
+ public void createWebCommand_adds_jdbc_driver_to_classpath_if_property_is_set_in_props() {
+ JavaCommand javaCommand = underTest.createWebCommand(newPropsWithRequiredProperties(JDBC_DRIVER_PATH, "foo"), homeDir);
+
+ assertThat(javaCommand.getClasspath()).contains("foo");
+ }
+
+ @Test
+ public void createWebCommand_set_env_variable_for_path_to_log_dir() {
+ JavaCommand javaCommand = underTest.createWebCommand(newPropsWithRequiredProperties(), homeDir);
+
+ assertThat(javaCommand.getEnvVariables()).contains(entry("sonar.path.logs", mockValueFor(PATH_LOGS)));
+ }
+
+ @Test
+ public void createWebCommand_adds_search_javaOpts_and_javaAdditionalOpts_java_options() {
+ JavaCommand javaCommand = underTest.createWebCommand(newPropsWithRequiredProperties(), homeDir);
+
+ assertThat(javaCommand.getJavaOptions()).contains(mockValueFor(WEB_JAVA_OPTS), mockValueFor(WEB_JAVA_ADDITIONAL_OPTS));
+ }
+
+ @Test
+ public void createWebCommand_sets_headless_and_encoding_java_options() {
+ JavaCommand javaCommand = underTest.createWebCommand(newPropsWithRequiredProperties(), homeDir);
+
+ assertThat(javaCommand.getJavaOptions()).contains("-Djava.awt.headless=true", "-Dfile.encoding=UTF-8");
+ }
+
+ @Test
+ public void createWebCommand_sets_WEB_SERVER_processId() {
+ JavaCommand javaCommand = underTest.createWebCommand(newPropsWithRequiredProperties(), homeDir);
+
+ assertThat(javaCommand.getProcessId()).isSameAs(ProcessId.WEB_SERVER);
+ }
+
+ @Test
+ public void createWebCommand_sets_workdir_to_argument() {
+ JavaCommand javaCommand = underTest.createWebCommand(newPropsWithRequiredProperties(), homeDir);
+
+ assertThat(javaCommand.getWorkDir()).isSameAs(homeDir);
+ }
+
+ @Test
+ public void createWebCommand_add_options_fore_http_and_https_proxies_from_props() throws Exception {
+ addOptionsForHttpAndHttpsProxiesFromProps((props, fileDir) -> underTest.createWebCommand(props, fileDir));
+ }
+
+ @Test
+ public void createWebCommand_use_http_properties_from_props_as_defaults_for_https_properties() throws Exception {
+ userHttpPropertiesFromPropsAsDefaultForHttpsProperties((props, file) -> underTest.createWebCommand(props, file));
+ }
+
+ @Test
+ public void createWebCommand_add_no_proxy_option_if_no_proxy_property_in_props() throws Exception {
+ noProxyOptionIfNoProxyPropertyInProps((props, file) -> underTest.createWebCommand(props, file));
+ }
+
+ @Test
+ public void createWebCommand_passes_rawProperties_of_Props_argument_as_argument_of_javaCommand() {
+ passesRawPropertiesOfPropsAsArgumentsOfJavaCommand((props, fileDir) -> underTest.createWebCommand(props, fileDir));
+ }
+
+ @Test
+ public void createCeCommand_fails_if_web_javaOpts_property_is_not_set() {
+ expectMissingPropertyIAE(CE_JAVA_OPTS);
+
+ underTest.createCeCommand(newProps(), homeDir);
+ }
+
+ @Test
+ public void createCeCommand_fails_if_web_javaAdditionalOpts_property_is_not_set() {
+ expectMissingPropertyIAE(CE_JAVA_ADDITIONAL_OPTS);
+
+ underTest.createCeCommand(newProps(CE_JAVA_OPTS, "foo"), homeDir);
+ }
+
+ @Test
+ public void createCeCommand_sets_SearchServer_for_className() {
+ JavaCommand javaCommand = underTest.createCeCommand(newPropsWithRequiredProperties(), homeDir);
+
+ assertThat(javaCommand.getClassName()).isEqualTo("org.sonar.ce.app.CeServer");
+ }
+
+ @Test
+ public void createCeCommand_puts_common_server_and_ce_lib_directories_in_classpath() {
+ JavaCommand javaCommand = underTest.createCeCommand(newPropsWithRequiredProperties(), homeDir);
+
+ assertThat(javaCommand.getClasspath()).containsOnly("./lib/common/*", "./lib/server/*", "./lib/ce/*");
+ }
+
+ @Test
+ public void createCeCommand_adds_jdbc_driver_to_classpath_if_property_is_set_in_props() {
+ JavaCommand javaCommand = underTest.createCeCommand(newPropsWithRequiredProperties(JDBC_DRIVER_PATH, "foo"), homeDir);
+
+ assertThat(javaCommand.getClasspath()).contains("foo");
+ }
+
+ @Test
+ public void createCeCommand_sets_headless_and_encoding_java_options() {
+ JavaCommand javaCommand = underTest.createCeCommand(newPropsWithRequiredProperties(), homeDir);
+
+ assertThat(javaCommand.getJavaOptions()).contains("-Djava.awt.headless=true", "-Dfile.encoding=UTF-8");
+ }
+
+ @Test
+ public void createCeCommand_adds_search_javaOpts_and_javaAdditionalOpts_java_options() {
+ JavaCommand javaCommand = underTest.createCeCommand(newPropsWithRequiredProperties(), homeDir);
+
+ assertThat(javaCommand.getJavaOptions()).contains(mockValueFor(CE_JAVA_OPTS), mockValueFor(CE_JAVA_ADDITIONAL_OPTS));
+ }
+
+ @Test
+ public void createCeCommand_sets_workdir_to_argument() {
+ JavaCommand javaCommand = underTest.createCeCommand(newPropsWithRequiredProperties(), homeDir);
+
+ assertThat(javaCommand.getWorkDir()).isSameAs(homeDir);
+ }
+
+ @Test
+ public void createCeCommand_sets_COMPUTE_ENGINE_processId() {
+ JavaCommand javaCommand = underTest.createCeCommand(newPropsWithRequiredProperties(), homeDir);
+
+ assertThat(javaCommand.getProcessId()).isSameAs(ProcessId.COMPUTE_ENGINE);
+ }
+
+ @Test
+ public void createCeCommand_add_options_for_http_and_https_proxies_from_props() throws Exception {
+ addOptionsForHttpAndHttpsProxiesFromProps((props, fileDir) -> underTest.createCeCommand(props, fileDir));
+ }
+
+ @Test
+ public void createCeCommand_use_http_properties_from_props_as_defaults_for_https_properties() throws Exception {
+ userHttpPropertiesFromPropsAsDefaultForHttpsProperties((props, file) -> underTest.createCeCommand(props, file));
+ }
+
+ @Test
+ public void createCeCommand_passes_rawProperties_of_Props_argument_as_argument_of_javaCommand() {
+ passesRawPropertiesOfPropsAsArgumentsOfJavaCommand((props, fileDir) -> underTest.createCeCommand(props, fileDir));
+ }
+
+ private void addOptionsForHttpAndHttpsProxiesFromProps(BiFunction<Props, File, JavaCommand> callCreateMethod) {
+ Props props = newPropsWithRequiredProperties();
+
+ // These properties can be defined in conf/sonar.properties.
+ // They must be propagated to JVM.
+ props.set("http.proxyHost", "1.2.3.4");
+ props.set("http.proxyPort", "80");
+ props.set("https.proxyHost", "5.6.7.8");
+ props.set("https.proxyPort", "443");
+
+ JavaCommand command = callCreateMethod.apply(props, homeDir);
+ assertThat(command.getJavaOptions()).contains("-Dhttp.proxyHost=1.2.3.4");
+ assertThat(command.getJavaOptions()).contains("-Dhttp.proxyPort=80");
+ assertThat(command.getJavaOptions()).contains("-Dhttps.proxyHost=5.6.7.8");
+ assertThat(command.getJavaOptions()).contains("-Dhttps.proxyPort=443");
+ }
+
+ @Test
+ public void createCeCommand_add_no_proxy_option_if_no_proxy_property_in_props() throws Exception {
+ noProxyOptionIfNoProxyPropertyInProps((props, file) -> underTest.createCeCommand(props, file));
+ }
+
+ private void userHttpPropertiesFromPropsAsDefaultForHttpsProperties(BiFunction<Props, File, JavaCommand> callCreateMethod) {
+ Props props = newPropsWithRequiredProperties();
+ props.set("http.proxyHost", "1.2.3.4");
+ props.set("http.proxyPort", "80");
+
+ JavaCommand command = callCreateMethod.apply(props, homeDir);
+ assertThat(command.getJavaOptions()).contains("-Dhttp.proxyHost=1.2.3.4");
+ assertThat(command.getJavaOptions()).contains("-Dhttp.proxyPort=80");
+ assertThat(command.getJavaOptions()).contains("-Dhttps.proxyHost=1.2.3.4");
+ assertThat(command.getJavaOptions()).contains("-Dhttps.proxyPort=80");
+ }
+
+ private void passesRawPropertiesOfPropsAsArgumentsOfJavaCommand(BiFunction<Props, File, JavaCommand> callCreateMethod) {
+ Props props = newPropsWithRequiredProperties("cryptedProperty", "{AES}AAAAA");
+ JavaCommand javaCommand = callCreateMethod.apply(props, homeDir);
+
+ Map<String, String> rawProperties = (Map<String, String>) ((Map) props.rawProperties());
+ assertThat(javaCommand.getArguments()).containsAllEntriesOf(rawProperties);
+ }
+
+ private void noProxyOptionIfNoProxyPropertyInProps(BiFunction<Props, File, JavaCommand> callCreateMethod) {
+ JavaCommand command = callCreateMethod.apply(newPropsWithRequiredProperties(), homeDir);
+
+ assertThat(command.getJavaOptions()).doesNotContain("http.proxyHost");
+ assertThat(command.getJavaOptions()).doesNotContain("https.proxyHost");
+ assertThat(command.getJavaOptions()).doesNotContain("http.proxyPort");
+ assertThat(command.getJavaOptions()).doesNotContain("https.proxyPort");
+ }
+
+ private void expectMissingPropertyIAE(String property) {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Missing property: " + property);
+ }
+
+ private Props newPropsWithRequiredProperties(String... properties) {
+ return newProps(
+ (props) -> addProperties(props, properties),
+ SEARCH_JAVA_OPTS, mockValueFor(SEARCH_JAVA_OPTS),
+ SEARCH_JAVA_ADDITIONAL_OPTS, mockValueFor(SEARCH_JAVA_ADDITIONAL_OPTS),
+ WEB_JAVA_OPTS, mockValueFor(WEB_JAVA_OPTS),
+ WEB_JAVA_ADDITIONAL_OPTS, mockValueFor(WEB_JAVA_ADDITIONAL_OPTS),
+ PATH_LOGS, mockValueFor(PATH_LOGS),
+ CE_JAVA_OPTS, mockValueFor(CE_JAVA_OPTS),
+ CE_JAVA_ADDITIONAL_OPTS, mockValueFor(CE_JAVA_ADDITIONAL_OPTS));
+ }
+
+ private static String mockValueFor(String str) {
+ return str + "_value";
+ }
+
+ private Props newProps(String... properties) {
+ return newProps((props) -> {
+ }, properties);
+ }
+
+ private Props newProps(Consumer<Properties> extraConf, String... properties) {
+ Properties props = new Properties();
+ addProperties(props, properties);
+ extraConf.accept(props);
+ return new Props(props);
+ }
+
+ private void addProperties(Properties props, String[] properties) {
+ if (properties.length % 2 != 0) {
+ throw new IllegalArgumentException("Properties must all have key and value");
+ }
+ for (int i = 0; i < properties.length; i++) {
+ props.setProperty(properties[i], properties[i + 1]);
+ i++;
+ }
+ }
+
+}