this.homeDirectory = new File(sqHomeDir, "elasticsearch");
this.dataDirectory = buildDataDir(props, sqHomeDir);
this.confDirectory = buildConfDir(props);
- this.logDirectory = buildLogPath(props, sqHomeDir);
+ this.logDirectory = buildLogPath(props);
}
private static File buildDataDir(Props props, File sqHomeDir) {
return new File(sqHomeDir, "data/es");
}
- private static File buildLogPath(Props props, File sqHomeDir) {
- String logPath = props.value(ProcessProperties.PATH_LOGS);
- if (StringUtils.isNotEmpty(logPath)) {
- return new File(logPath);
- }
- return new File(sqHomeDir, "log");
+ private static File buildLogPath(Props props) {
+ return props.nonNullValueAsFile(ProcessProperties.PATH_LOGS);
}
private static File buildConfDir(Props props) {
--- /dev/null
+/*
+ * 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.process.command;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Properties;
+import org.apache.commons.io.FileUtils;
+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.ProcessProperties;
+import org.sonar.process.Props;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.entry;
+
+public class CommandFactoryImplTest {
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ private File homeDir;
+ private File tempDir;
+ private File logsDir;
+
+ @Before
+ public void setUp() throws Exception {
+ homeDir = temp.newFolder();
+ tempDir = temp.newFolder();
+ logsDir = temp.newFolder();
+ }
+
+ @Test
+ public void createEsCommand_throws_ISE_if_es_binary_is_not_found() throws Exception {
+ expectedException.expect(IllegalStateException.class);
+ expectedException.expectMessage("Cannot find elasticsearch binary");
+
+ newFactory(new Properties()).createEsCommand();
+ }
+
+ @Test
+ public void createEsCommand_returns_command_for_default_settings() throws Exception {
+ prepareEsFileSystem();
+
+ Properties props = new Properties();
+ props.setProperty("sonar.search.host", "localhost");
+
+ EsCommand esCommand = newFactory(props).createEsCommand();
+
+ assertThat(esCommand.getClusterName()).isEqualTo("sonarqube");
+ assertThat(esCommand.getHost()).isNotEmpty();
+ assertThat(esCommand.getPort()).isEqualTo(9001);
+ assertThat(esCommand.getEsJvmOptions().getAll())
+ // enforced values
+ .contains("-XX:+UseConcMarkSweepGC", "-server", "-Dfile.encoding=UTF-8")
+ // default settings
+ .contains("-Xms512m", "-Xmx512m", "-XX:+HeapDumpOnOutOfMemoryError");
+ File esConfDir = new File(tempDir, "conf/es");
+ assertThat(esCommand.getEsOptions()).containsOnly("-Epath.conf=" + esConfDir.getAbsolutePath());
+ assertThat(esCommand.getEnvVariables())
+ .contains(entry("ES_JVM_OPTIONS", new File(esConfDir, "jvm.options").getAbsolutePath()))
+ .containsKey("JAVA_HOME");
+ assertThat(esCommand.getEsYmlSettings()).isNotNull();
+
+ assertThat(esCommand.getLog4j2Properties())
+ .contains(entry("appender.file_es.fileName", new File(logsDir, "es.log").getAbsolutePath()));
+ }
+
+ @Test
+ public void createEsCommand_returns_command_for_overridden_settings() throws Exception {
+ prepareEsFileSystem();
+
+ Properties props = new Properties();
+ props.setProperty("sonar.search.host", "localhost");
+ props.setProperty("sonar.cluster.name", "foo");
+ props.setProperty("sonar.search.port", "1234");
+ props.setProperty("sonar.search.javaOpts", "-Xms10G -Xmx10G");
+
+ EsCommand command = newFactory(props).createEsCommand();
+
+ assertThat(command.getClusterName()).isEqualTo("foo");
+ assertThat(command.getPort()).isEqualTo(1234);
+ assertThat(command.getEsJvmOptions().getAll())
+ // enforced values
+ .contains("-XX:+UseConcMarkSweepGC", "-server", "-Dfile.encoding=UTF-8")
+ // user settings
+ .contains("-Xms10G", "-Xmx10G")
+ // default values disabled
+ .doesNotContain("-XX:+HeapDumpOnOutOfMemoryError");
+ }
+
+ @Test
+ public void createWebCommand_returns_command_for_default_settings() throws Exception {
+ JavaCommand command = newFactory(new Properties()).createWebCommand(true);
+
+ assertThat(command.getClassName()).isEqualTo("org.sonar.server.app.WebServer");
+ assertThat(command.getWorkDir().getAbsolutePath()).isEqualTo(homeDir.getAbsolutePath());
+ assertThat(command.getClasspath())
+ .containsExactlyInAnyOrder("./lib/common/*", "./lib/server/*");
+ assertThat(command.getJvmOptions().getAll())
+ // enforced values
+ .contains("-Djava.awt.headless=true", "-Dfile.encoding=UTF-8")
+ // default settings
+ .contains("-Djava.io.tmpdir=" + tempDir.getAbsolutePath(), "-Dfile.encoding=UTF-8")
+ .contains("-Xmx512m", "-Xms128m", "-XX:+HeapDumpOnOutOfMemoryError");
+ assertThat(command.getProcessId()).isEqualTo(ProcessId.WEB_SERVER);
+ assertThat(command.getEnvVariables())
+ .containsKey("JAVA_HOME");
+ assertThat(command.getArguments())
+ // default settings
+ .contains(entry("sonar.web.javaOpts", "-Xmx512m -Xms128m -XX:+HeapDumpOnOutOfMemoryError"))
+ .contains(entry("sonar.cluster.enabled", "false"));
+ }
+
+ @Test
+ public void createWebCommand_configures_command_with_overridden_settings() throws Exception {
+ Properties props = new Properties();
+ props.setProperty("sonar.web.port", "1234");
+ props.setProperty("sonar.web.javaOpts", "-Xmx10G");
+ JavaCommand command = newFactory(props).createWebCommand(true);
+
+ assertThat(command.getJvmOptions().getAll())
+ // enforced values
+ .contains("-Djava.awt.headless=true", "-Dfile.encoding=UTF-8")
+ // default settings
+ .contains("-Djava.io.tmpdir=" + tempDir.getAbsolutePath(), "-Dfile.encoding=UTF-8")
+ // overridden values
+ .contains("-Xmx10G")
+ .doesNotContain("-Xms128m", "-XX:+HeapDumpOnOutOfMemoryError");
+ assertThat(command.getArguments())
+ // default settings
+ .contains(entry("sonar.web.javaOpts", "-Xmx10G"))
+ .contains(entry("sonar.cluster.enabled", "false"));
+ }
+
+ @Test
+ public void createWebCommand_adds_configured_jdbc_driver_to_classpath() throws Exception {
+ Properties props = new Properties();
+ File driverFile = temp.newFile();
+ props.setProperty("sonar.jdbc.driverPath", driverFile.getAbsolutePath());
+
+ JavaCommand command = newFactory(props).createWebCommand(true);
+
+ assertThat(command.getClasspath())
+ .containsExactlyInAnyOrder("./lib/common/*", "./lib/server/*", driverFile.getAbsolutePath());
+ }
+
+ private void prepareEsFileSystem() throws IOException {
+ FileUtils.touch(new File(homeDir, "elasticsearch/bin/elasticsearch"));
+ FileUtils.touch(new File(homeDir, "elasticsearch/bin/elasticsearch.bat"));
+ }
+
+ private CommandFactory newFactory(Properties userProps) throws IOException {
+ Properties p = new Properties();
+ p.setProperty("sonar.path.home", homeDir.getAbsolutePath());
+ p.setProperty("sonar.path.temp", tempDir.getAbsolutePath());
+ p.setProperty("sonar.path.logs", logsDir.getAbsolutePath());
+ p.putAll(userProps);
+
+ Props props = new Props(p);
+ ProcessProperties.completeDefaults(props);
+ return new CommandFactoryImpl(props, tempDir);
+ }
+}
Props props = new Props(new Properties());
props.set(ProcessProperties.PATH_HOME, sqHomeDir.getAbsolutePath());
props.set(ProcessProperties.PATH_TEMP, temp.newFolder().getAbsolutePath());
+ props.set(ProcessProperties.PATH_LOGS, temp.newFolder().getAbsolutePath());
EsFileSystem underTest = new EsFileSystem(props);
Props props = new Props(new Properties());
props.set(ProcessProperties.PATH_HOME, sqHomeDir.getAbsolutePath());
props.set(ProcessProperties.PATH_TEMP, temp.newFolder().getAbsolutePath());
+ props.set(ProcessProperties.PATH_LOGS, temp.newFolder().getAbsolutePath());
EsFileSystem underTest = new EsFileSystem(props);
Props props = new Props(new Properties());
props.set(ProcessProperties.PATH_HOME, sqHomeDir.getAbsolutePath());
props.set(ProcessProperties.PATH_TEMP, tempDir.getAbsolutePath());
+ props.set(ProcessProperties.PATH_LOGS, temp.newFolder().getAbsolutePath());
props.set(ProcessProperties.PATH_DATA, dataDir.getAbsolutePath());
}
@Test
- public void getLogDirectory_is_log_subdirectory_of_sq_home_directory_by_default() throws IOException {
+ public void getLogDirectory_is_configured_with_non_nullable_PATH_LOG_variable() throws IOException {
File sqHomeDir = temp.newFolder();
- Props props = new Props(new Properties());
- props.set(ProcessProperties.PATH_HOME, sqHomeDir.getAbsolutePath());
- props.set(ProcessProperties.PATH_TEMP, temp.newFolder().getAbsolutePath());
-
- EsFileSystem underTest = new EsFileSystem(props);
-
- assertThat(underTest.getLogDirectory()).isEqualTo(new File(sqHomeDir, "log"));
- }
-
- @Test
- public void override_log_dir() throws Exception {
- File sqHomeDir = temp.newFolder();
- File tempDir = temp.newFolder();
File logDir = temp.newFolder();
Props props = new Props(new Properties());
props.set(ProcessProperties.PATH_HOME, sqHomeDir.getAbsolutePath());
- props.set(ProcessProperties.PATH_TEMP, tempDir.getAbsolutePath());
-
+ props.set(ProcessProperties.PATH_TEMP, temp.newFolder().getAbsolutePath());
props.set(ProcessProperties.PATH_LOGS, logDir.getAbsolutePath());
EsFileSystem underTest = new EsFileSystem(props);
- assertThat(underTest.getDataDirectory()).isEqualTo(new File(sqHomeDir, "data/es"));
+ assertThat(underTest.getLogDirectory()).isEqualTo(logDir);
}
@Test
Props props = new Props(new Properties());
props.set(ProcessProperties.PATH_HOME, temp.newFolder().getAbsolutePath());
props.set(ProcessProperties.PATH_TEMP, tempDir.getAbsolutePath());
+ props.set(ProcessProperties.PATH_LOGS, temp.newFolder().getAbsolutePath());
EsFileSystem underTest = new EsFileSystem(props);
Props props = new Props(new Properties());
props.set(ProcessProperties.PATH_HOME, sqHomeDir.getAbsolutePath());
props.set(ProcessProperties.PATH_TEMP, temp.newFolder().getAbsolutePath());
+ props.set(ProcessProperties.PATH_LOGS, temp.newFolder().getAbsolutePath());
EsFileSystem underTest = new EsFileSystem(props);
Props props = new Props(new Properties());
props.set(ProcessProperties.PATH_HOME, temp.newFolder().getAbsolutePath());
props.set(ProcessProperties.PATH_TEMP, tempDir.getAbsolutePath());
+ props.set(ProcessProperties.PATH_LOGS, temp.newFolder().getAbsolutePath());
EsFileSystem underTest = new EsFileSystem(props);
Props props = new Props(new Properties());
props.set(ProcessProperties.PATH_HOME, temp.newFolder().getAbsolutePath());
props.set(ProcessProperties.PATH_TEMP, tempDir.getAbsolutePath());
+ props.set(ProcessProperties.PATH_LOGS, temp.newFolder().getAbsolutePath());
EsFileSystem underTest = new EsFileSystem(props);
Props props = new Props(new Properties());
props.set(ProcessProperties.PATH_HOME, temp.newFolder().getAbsolutePath());
props.set(ProcessProperties.PATH_TEMP, tempDir.getAbsolutePath());
+ props.set(ProcessProperties.PATH_LOGS, temp.newFolder().getAbsolutePath());
EsFileSystem underTest = new EsFileSystem(props);
props.set(ProcessProperties.SEARCH_HOST, "127.0.0.1");
props.set(ProcessProperties.PATH_HOME, homeDir.getAbsolutePath());
props.set(ProcessProperties.PATH_TEMP, temp.newFolder().getAbsolutePath());
+ props.set(ProcessProperties.PATH_LOGS, temp.newFolder().getAbsolutePath());
props.set(ProcessProperties.CLUSTER_NAME, "sonarqube");
EsSettings esSettings = new EsSettings(props, new EsFileSystem(props));
props.set(ProcessProperties.SEARCH_HOST, "127.0.0.1");
props.set(ProcessProperties.PATH_HOME, homeDir.getAbsolutePath());
props.set(ProcessProperties.PATH_TEMP, temp.newFolder().getAbsolutePath());
+ props.set(ProcessProperties.PATH_LOGS, temp.newFolder().getAbsolutePath());
props.set(ProcessProperties.CLUSTER_NAME, "sonarqube-1");
props.set(ProcessProperties.CLUSTER_ENABLED, "true");
props.set(ProcessProperties.CLUSTER_NODE_NAME, "node-1");
props.set(ProcessProperties.SEARCH_HOST, "127.0.0.1");
props.set(ProcessProperties.PATH_HOME, homeDir.getAbsolutePath());
props.set(ProcessProperties.PATH_TEMP, temp.newFolder().getAbsolutePath());
+ props.set(ProcessProperties.PATH_LOGS, temp.newFolder().getAbsolutePath());
EsSettings esSettings = new EsSettings(props, new EsFileSystem(props));
Map<String, String> generated = esSettings.build();
assertThat(generated.get("node.name")).startsWith("sonarqube-");
props.set(ProcessProperties.SEARCH_HOST, "127.0.0.1");
props.set(ProcessProperties.PATH_HOME, homeDir.getAbsolutePath());
props.set(ProcessProperties.PATH_TEMP, temp.newFolder().getAbsolutePath());
+ props.set(ProcessProperties.PATH_LOGS, temp.newFolder().getAbsolutePath());
EsSettings esSettings = new EsSettings(props, new EsFileSystem(props));
Map<String, String> generated = esSettings.build();
assertThat(generated.get("node.name")).isEqualTo("sonarqube");
public class TelemetryDaemon implements Startable {
private static final String THREAD_NAME_PREFIX = "sq-telemetry-service-";
private static final int SEVEN_DAYS = 7 * 24 * 60 * 60 * 1_000;
- static final String I_PROP_LAST_PING = "telemetry.lastPing";
- static final String I_PROP_OPT_OUT = "telemetry.optOut";
+ private static final String I_PROP_LAST_PING = "telemetry.lastPing";
+ private static final String I_PROP_OPT_OUT = "telemetry.optOut";
private static final Logger LOG = Loggers.get(TelemetryDaemon.class);
private final TelemetryDataLoader dataLoader;
import com.google.common.collect.ImmutableMap;
import java.io.IOException;
-import java.util.Arrays;
import java.util.List;
import java.util.Map;
+import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.server.user.index.UserIndexDefinition;
import org.sonar.updatecenter.common.Version;
+import static java.util.Arrays.asList;
import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.sonar.api.utils.DateUtils.parseDate;
-import static org.sonar.core.config.TelemetryProperties.PROP_ENABLE;
-import static org.sonar.core.config.TelemetryProperties.PROP_FREQUENCY;
-import static org.sonar.server.telemetry.TelemetryDaemon.I_PROP_LAST_PING;
import static org.sonar.test.JsonAssert.assertJson;
public class TelemetryDaemonTest {
settings.asConfig(), internalProperties, system2);
}
+
+ @After
+ public void tearDown() throws Exception {
+ underTest.stop();
+ }
+
@Test
public void send_telemetry_data() throws IOException {
- settings.setProperty(PROP_FREQUENCY, "1");
+ settings.setProperty("sonar.telemetry.frequencyInSeconds", "1");
String id = "AU-TpxcB-iU5OvuD2FL7";
String version = "7.5.4";
server.setId(id);
server.setVersion(version);
- List<PluginInfo> plugins = Arrays.asList(newPlugin("java", "4.12.0.11033"), newPlugin("scmgit", "1.2"), new PluginInfo("other"));
+ List<PluginInfo> plugins = asList(newPlugin("java", "4.12.0.11033"), newPlugin("scmgit", "1.2"), new PluginInfo("other"));
when(pluginRepository.getPluginInfos()).thenReturn(plugins);
es.putDocuments(UserIndexDefinition.INDEX_TYPE_USER,
new UserDoc().setLogin(randomAlphanumeric(30)).setActive(true),
new UserDoc().setLogin(randomAlphanumeric(30)).setActive(false));
es.putDocuments(ProjectMeasuresIndexDefinition.INDEX_TYPE_PROJECT_MEASURES,
new ProjectMeasuresDoc().setId(randomAlphanumeric(20))
- .setMeasures(Arrays.asList(newMeasure("lines", 200), newMeasure("ncloc", 100), newMeasure("coverage", 80)))
- .setLanguages(Arrays.asList("java", "js"))
+ .setMeasures(asList(newMeasure("lines", 200), newMeasure("ncloc", 100), newMeasure("coverage", 80)))
+ .setLanguages(asList("java", "js"))
.setNclocLanguageDistributionFromMap(ImmutableMap.of("java", 200, "js", 50)),
new ProjectMeasuresDoc().setId(randomAlphanumeric(20))
- .setMeasures(Arrays.asList(newMeasure("lines", 300), newMeasure("ncloc", 200), newMeasure("coverage", 80)))
- .setLanguages(Arrays.asList("java", "kotlin"))
+ .setMeasures(asList(newMeasure("lines", 300), newMeasure("ncloc", 200), newMeasure("coverage", 80)))
+ .setLanguages(asList("java", "kotlin"))
.setNclocLanguageDistributionFromMap(ImmutableMap.of("java", 300, "kotlin", 2500)));
underTest.start();
@Test
public void send_data_via_client_at_startup_after_initial_delay() throws IOException {
- settings.setProperty(PROP_FREQUENCY, "1");
+ settings.setProperty("sonar.telemetry.frequencyInSeconds", "1");
underTest.start();
verify(client, timeout(2_000).atLeastOnce()).upload(anyString());
long now = system2.now();
long sixDaysAgo = now - (ONE_DAY * 6L);
long sevenDaysAgo = now - (ONE_DAY * 7L);
- internalProperties.write(I_PROP_LAST_PING, String.valueOf(sixDaysAgo));
- settings.setProperty(PROP_FREQUENCY, "1");
+ internalProperties.write("telemetry.lastPing", String.valueOf(sixDaysAgo));
+ settings.setProperty("sonar.telemetry.frequencyInSeconds", "1");
underTest.start();
verify(client, timeout(2_000).never()).upload(anyString());
- internalProperties.write(I_PROP_LAST_PING, String.valueOf(sevenDaysAgo));
+ internalProperties.write("telemetry.lastPing", String.valueOf(sevenDaysAgo));
verify(client, timeout(2_000).atLeastOnce()).upload(anyString());
}
@Test
public void send_server_id_and_version() throws IOException {
- settings.setProperty(PROP_FREQUENCY, "1");
+ settings.setProperty("sonar.telemetry.frequencyInSeconds", "1");
String id = randomAlphanumeric(40);
String version = randomAlphanumeric(10);
server.setId(id);
@Test
public void do_not_send_data_if_last_ping_earlier_than_one_week_ago() throws IOException {
- settings.setProperty(PROP_FREQUENCY, "1");
+ settings.setProperty("sonar.telemetry.frequencyInSeconds", "1");
long now = system2.now();
long sixDaysAgo = now - (ONE_DAY * 6L);
- internalProperties.write(I_PROP_LAST_PING, String.valueOf(sixDaysAgo));
+ internalProperties.write("telemetry.lastPing", String.valueOf(sixDaysAgo));
underTest.start();
verify(client, timeout(2_000).never()).upload(anyString());
@Test
public void send_data_if_last_ping_is_one_week_ago() throws IOException {
- settings.setProperty(PROP_FREQUENCY, "1");
+ settings.setProperty("sonar.telemetry.frequencyInSeconds", "1");
long today = parseDate("2017-08-01").getTime();
system2.setNow(today + 15 * ONE_HOUR);
long sevenDaysAgo = today - (ONE_DAY * 7L);
- internalProperties.write(I_PROP_LAST_PING, String.valueOf(sevenDaysAgo));
+ internalProperties.write("telemetry.lastPing", String.valueOf(sevenDaysAgo));
underTest.start();
verify(client, timeout(2_000).atLeastOnce()).upload(anyString());
- assertThat(internalProperties.read(I_PROP_LAST_PING).get()).isEqualTo(String.valueOf(today));
+ assertThat(internalProperties.read("telemetry.lastPing").get()).isEqualTo(String.valueOf(today));
}
@Test
public void opt_out_sent_once() throws IOException {
- settings.setProperty(PROP_FREQUENCY, "1");
- settings.setProperty(PROP_ENABLE, "false");
+ settings.setProperty("sonar.telemetry.frequencyInSeconds", "1");
+ settings.setProperty("sonar.telemetry.enable", "false");
underTest.start();
underTest.start();