You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

CommandFactoryImplTest.java 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2018 SonarSource SA
  4. * mailto:info AT sonarsource DOT com
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. package org.sonar.application.command;
  21. import ch.qos.logback.classic.spi.ILoggingEvent;
  22. import java.io.File;
  23. import java.io.IOException;
  24. import java.util.Properties;
  25. import org.apache.commons.io.FileUtils;
  26. import org.junit.After;
  27. import org.junit.Before;
  28. import org.junit.Rule;
  29. import org.junit.Test;
  30. import org.junit.rules.ExpectedException;
  31. import org.junit.rules.TemporaryFolder;
  32. import org.mockito.Mockito;
  33. import org.sonar.application.es.EsInstallation;
  34. import org.sonar.process.ProcessId;
  35. import org.sonar.process.ProcessProperties;
  36. import org.sonar.process.Props;
  37. import org.sonar.process.System2;
  38. import org.sonar.application.logging.ListAppender;
  39. import static org.assertj.core.api.Assertions.assertThat;
  40. import static org.assertj.core.api.Assertions.entry;
  41. import static org.mockito.Matchers.anyString;
  42. import static org.mockito.Mockito.when;
  43. public class CommandFactoryImplTest {
  44. @Rule
  45. public ExpectedException expectedException = ExpectedException.none();
  46. @Rule
  47. public TemporaryFolder temp = new TemporaryFolder();
  48. private File homeDir;
  49. private File tempDir;
  50. private File logsDir;
  51. private ListAppender listAppender;
  52. @Before
  53. public void setUp() throws Exception {
  54. homeDir = temp.newFolder();
  55. tempDir = temp.newFolder();
  56. logsDir = temp.newFolder();
  57. }
  58. @After
  59. public void tearDown() {
  60. if (listAppender != null) {
  61. ListAppender.detachMemoryAppenderToLoggerOf(CommandFactoryImpl.class, listAppender);
  62. }
  63. }
  64. @Test
  65. public void constructor_logs_no_warning_if_env_variable_JAVA_TOOL_OPTIONS_is_not_set() {
  66. System2 system2 = Mockito.mock(System2.class);
  67. when(system2.getenv(anyString())).thenReturn(null);
  68. attachMemoryAppenderToLoggerOf(CommandFactoryImpl.class);
  69. new CommandFactoryImpl(new Props(new Properties()), tempDir, system2);
  70. assertThat(listAppender.getLogs()).isEmpty();
  71. }
  72. @Test
  73. public void constructor_logs_warning_if_env_variable_JAVA_TOOL_OPTIONS_is_set() {
  74. System2 system2 = Mockito.mock(System2.class);
  75. when(system2.getenv("JAVA_TOOL_OPTIONS")).thenReturn("sds");
  76. attachMemoryAppenderToLoggerOf(CommandFactoryImpl.class);
  77. new CommandFactoryImpl(new Props(new Properties()), tempDir, system2);
  78. assertThat(listAppender.getLogs())
  79. .extracting(ILoggingEvent::getMessage)
  80. .containsOnly(
  81. "JAVA_TOOL_OPTIONS is defined but will be ignored. " +
  82. "Use properties sonar.*.javaOpts and/or sonar.*.javaAdditionalOpts in sonar.properties to change SQ JVM processes options");
  83. }
  84. @Test
  85. public void createEsCommand_throws_ISE_if_es_binary_is_not_found() {
  86. expectedException.expect(IllegalStateException.class);
  87. expectedException.expectMessage("Cannot find elasticsearch binary");
  88. newFactory(new Properties()).createEsCommand();
  89. }
  90. @Test
  91. public void createEsCommand_for_unix_returns_command_for_default_settings() throws Exception {
  92. System2 system2 = Mockito.mock(System2.class);
  93. when(system2.isOsWindows()).thenReturn(false);
  94. prepareEsFileSystem();
  95. Properties props = new Properties();
  96. props.setProperty("sonar.search.host", "localhost");
  97. AbstractCommand esCommand = newFactory(props, system2).createEsCommand();
  98. EsInstallation esConfig = esCommand.getEsInstallation();
  99. assertThat(esCommand).isInstanceOf(EsScriptCommand.class);
  100. assertThat(esConfig.getClusterName()).isEqualTo("sonarqube");
  101. assertThat(esConfig.getHost()).isNotEmpty();
  102. assertThat(esConfig.getPort()).isEqualTo(9001);
  103. assertThat(esConfig.getEsJvmOptions().getAll())
  104. // enforced values
  105. .contains("-XX:+UseConcMarkSweepGC", "-server", "-Dfile.encoding=UTF-8")
  106. // default settings
  107. .contains("-Xms512m", "-Xmx512m", "-XX:+HeapDumpOnOutOfMemoryError");
  108. File esConfDir = new File(tempDir, "conf/es");
  109. assertThat(esCommand.getEnvVariables())
  110. .contains(entry("ES_JVM_OPTIONS", new File(esConfDir, "jvm.options").getAbsolutePath()))
  111. .containsKey("JAVA_HOME");
  112. assertThat(esConfig.getEsYmlSettings()).isNotNull();
  113. assertThat(esConfig.getLog4j2Properties())
  114. .contains(entry("appender.file_es.fileName", new File(logsDir, "es.log").getAbsolutePath()));
  115. assertThat(esCommand.getSuppressedEnvVariables()).containsOnly("JAVA_TOOL_OPTIONS");
  116. }
  117. @Test
  118. public void createEsCommand_for_windows_returns_command_for_default_settings() throws Exception {
  119. System2 system2 = Mockito.mock(System2.class);
  120. when(system2.isOsWindows()).thenReturn(true);
  121. prepareEsFileSystem();
  122. Properties props = new Properties();
  123. props.setProperty("sonar.search.host", "localhost");
  124. AbstractCommand esCommand = newFactory(props, system2).createEsCommand();
  125. EsInstallation esConfig = esCommand.getEsInstallation();
  126. assertThat(esCommand).isInstanceOf(JavaCommand.class);
  127. assertThat(esConfig.getClusterName()).isEqualTo("sonarqube");
  128. assertThat(esConfig.getHost()).isNotEmpty();
  129. assertThat(esConfig.getPort()).isEqualTo(9001);
  130. assertThat(esConfig.getEsJvmOptions().getAll())
  131. // enforced values
  132. .contains("-XX:+UseConcMarkSweepGC", "-server", "-Dfile.encoding=UTF-8")
  133. // default settings
  134. .contains("-Xms512m", "-Xmx512m", "-XX:+HeapDumpOnOutOfMemoryError");
  135. File esConfDir = new File(tempDir, "conf/es");
  136. assertThat(esCommand.getEnvVariables())
  137. .contains(entry("ES_JVM_OPTIONS", new File(esConfDir, "jvm.options").getAbsolutePath()))
  138. .containsKey("JAVA_HOME");
  139. assertThat(esConfig.getEsYmlSettings()).isNotNull();
  140. assertThat(esConfig.getLog4j2Properties())
  141. .contains(entry("appender.file_es.fileName", new File(logsDir, "es.log").getAbsolutePath()));
  142. assertThat(esCommand.getSuppressedEnvVariables()).containsOnly("JAVA_TOOL_OPTIONS");
  143. }
  144. @Test
  145. public void createEsCommand_returns_command_for_overridden_settings() throws Exception {
  146. prepareEsFileSystem();
  147. Properties props = new Properties();
  148. props.setProperty("sonar.search.host", "localhost");
  149. props.setProperty("sonar.cluster.name", "foo");
  150. props.setProperty("sonar.search.port", "1234");
  151. props.setProperty("sonar.search.javaOpts", "-Xms10G -Xmx10G");
  152. AbstractCommand esCommand = newFactory(props).createEsCommand();
  153. EsInstallation esConfig = esCommand.getEsInstallation();
  154. assertThat(esConfig.getClusterName()).isEqualTo("foo");
  155. assertThat(esConfig.getPort()).isEqualTo(1234);
  156. assertThat(esConfig.getEsJvmOptions().getAll())
  157. // enforced values
  158. .contains("-XX:+UseConcMarkSweepGC", "-server", "-Dfile.encoding=UTF-8")
  159. // user settings
  160. .contains("-Xms10G", "-Xmx10G")
  161. // default values disabled
  162. .doesNotContain("-XX:+HeapDumpOnOutOfMemoryError");
  163. }
  164. @Test
  165. public void createWebCommand_returns_command_for_default_settings() {
  166. JavaCommand command = newFactory(new Properties()).createWebCommand(true);
  167. assertThat(command.getClassName()).isEqualTo("org.sonar.server.app.WebServer");
  168. assertThat(command.getWorkDir().getAbsolutePath()).isEqualTo(homeDir.getAbsolutePath());
  169. assertThat(command.getClasspath())
  170. .containsExactly("./lib/common/*");
  171. assertThat(command.getJvmOptions().getAll())
  172. // enforced values
  173. .contains("-Djava.awt.headless=true", "-Dfile.encoding=UTF-8")
  174. // default settings
  175. .contains("-Djava.io.tmpdir=" + tempDir.getAbsolutePath(), "-Dfile.encoding=UTF-8")
  176. .contains("-Xmx512m", "-Xms128m", "-XX:+HeapDumpOnOutOfMemoryError");
  177. assertThat(command.getProcessId()).isEqualTo(ProcessId.WEB_SERVER);
  178. assertThat(command.getEnvVariables())
  179. .isNotEmpty();
  180. assertThat(command.getArguments())
  181. // default settings
  182. .contains(entry("sonar.web.javaOpts", "-Xmx512m -Xms128m -XX:+HeapDumpOnOutOfMemoryError"))
  183. .contains(entry("sonar.cluster.enabled", "false"));
  184. assertThat(command.getSuppressedEnvVariables()).containsOnly("JAVA_TOOL_OPTIONS");
  185. }
  186. @Test
  187. public void createCeCommand_returns_command_for_default_settings() {
  188. JavaCommand command = newFactory(new Properties()).createCeCommand();
  189. assertThat(command.getClassName()).isEqualTo("org.sonar.ce.app.CeServer");
  190. assertThat(command.getWorkDir().getAbsolutePath()).isEqualTo(homeDir.getAbsolutePath());
  191. assertThat(command.getClasspath())
  192. .containsExactly("./lib/common/*");
  193. assertThat(command.getJvmOptions().getAll())
  194. // enforced values
  195. .contains("-Djava.awt.headless=true", "-Dfile.encoding=UTF-8")
  196. // default settings
  197. .contains("-Djava.io.tmpdir=" + tempDir.getAbsolutePath(), "-Dfile.encoding=UTF-8")
  198. .contains("-Xmx512m", "-Xms128m", "-XX:+HeapDumpOnOutOfMemoryError");
  199. assertThat(command.getProcessId()).isEqualTo(ProcessId.COMPUTE_ENGINE);
  200. assertThat(command.getEnvVariables())
  201. .isNotEmpty();
  202. assertThat(command.getArguments())
  203. // default settings
  204. .contains(entry("sonar.web.javaOpts", "-Xmx512m -Xms128m -XX:+HeapDumpOnOutOfMemoryError"))
  205. .contains(entry("sonar.cluster.enabled", "false"));
  206. assertThat(command.getSuppressedEnvVariables()).containsOnly("JAVA_TOOL_OPTIONS");
  207. }
  208. @Test
  209. public void createWebCommand_configures_command_with_overridden_settings() {
  210. Properties props = new Properties();
  211. props.setProperty("sonar.web.port", "1234");
  212. props.setProperty("sonar.web.javaOpts", "-Xmx10G");
  213. JavaCommand command = newFactory(props).createWebCommand(true);
  214. assertThat(command.getJvmOptions().getAll())
  215. // enforced values
  216. .contains("-Djava.awt.headless=true", "-Dfile.encoding=UTF-8")
  217. // default settings
  218. .contains("-Djava.io.tmpdir=" + tempDir.getAbsolutePath(), "-Dfile.encoding=UTF-8")
  219. // overridden values
  220. .contains("-Xmx10G")
  221. .doesNotContain("-Xms128m", "-XX:+HeapDumpOnOutOfMemoryError");
  222. assertThat(command.getArguments())
  223. // default settings
  224. .contains(entry("sonar.web.javaOpts", "-Xmx10G"))
  225. .contains(entry("sonar.cluster.enabled", "false"));
  226. assertThat(command.getSuppressedEnvVariables()).containsOnly("JAVA_TOOL_OPTIONS");
  227. }
  228. @Test
  229. public void createWebCommand_adds_configured_jdbc_driver_to_classpath() throws Exception {
  230. Properties props = new Properties();
  231. File driverFile = temp.newFile();
  232. props.setProperty("sonar.jdbc.driverPath", driverFile.getAbsolutePath());
  233. JavaCommand command = newFactory(props).createWebCommand(true);
  234. assertThat(command.getClasspath())
  235. .containsExactlyInAnyOrder("./lib/common/*", driverFile.getAbsolutePath());
  236. }
  237. private void prepareEsFileSystem() throws IOException {
  238. FileUtils.touch(new File(homeDir, "elasticsearch/bin/elasticsearch"));
  239. FileUtils.touch(new File(homeDir, "elasticsearch/bin/elasticsearch.bat"));
  240. }
  241. private CommandFactoryImpl newFactory(Properties userProps) {
  242. return newFactory(userProps, System2.INSTANCE);
  243. }
  244. private CommandFactoryImpl newFactory(Properties userProps, System2 system2) {
  245. Properties p = new Properties();
  246. p.setProperty("sonar.path.home", homeDir.getAbsolutePath());
  247. p.setProperty("sonar.path.temp", tempDir.getAbsolutePath());
  248. p.setProperty("sonar.path.logs", logsDir.getAbsolutePath());
  249. p.putAll(userProps);
  250. Props props = new Props(p);
  251. ProcessProperties.completeDefaults(props);
  252. return new CommandFactoryImpl(props, tempDir, system2);
  253. }
  254. private <T> void attachMemoryAppenderToLoggerOf(Class<T> loggerClass) {
  255. this.listAppender = ListAppender.attachMemoryAppenderToLoggerOf(loggerClass);
  256. }
  257. }