diff options
author | Jenkins CI <ci@sonarsource.com> | 2014-09-25 23:43:35 +0200 |
---|---|---|
committer | Jenkins CI <ci@sonarsource.com> | 2014-09-25 23:43:35 +0200 |
commit | b685462248789067942332c9bc584c21544756ff (patch) | |
tree | 777ae9e54e582066e48afc1fbbcd1256ab935520 | |
parent | 48d48e90931782cc1e94768a83ada71275476ceb (diff) | |
parent | ea1ac3789b9128e394284d82dfeaeab32dd441d8 (diff) | |
download | sonarqube-b685462248789067942332c9bc584c21544756ff.tar.gz sonarqube-b685462248789067942332c9bc584c21544756ff.zip |
Automatic merge from branch-4.5
* origin/branch-4.5:
SONAR-4898 add missing tests
SONAR-4898 add missing tests
Use correct temp dir for Ruby on Rails app
Fail server startup if can not connect to DB
16 files changed, 243 insertions, 92 deletions
diff --git a/server/sonar-process/pom.xml b/server/sonar-process/pom.xml index 25916e9ae41..387e5ecc519 100644 --- a/server/sonar-process/pom.xml +++ b/server/sonar-process/pom.xml @@ -41,13 +41,8 @@ </dependency> <dependency> - <groupId>junit</groupId> - <artifactId>junit</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.easytesting</groupId> - <artifactId>fest-assert</artifactId> + <groupId>org.codehaus.sonar</groupId> + <artifactId>sonar-testing-harness</artifactId> <scope>test</scope> </dependency> <dependency> @@ -56,11 +51,6 @@ <scope>test</scope> </dependency> <dependency> - <groupId>org.hamcrest</groupId> - <artifactId>hamcrest-all</artifactId> - <scope>test</scope> - </dependency> - <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <scope>test</scope> diff --git a/server/sonar-process/src/main/java/org/sonar/process/ProcessCommands.java b/server/sonar-process/src/main/java/org/sonar/process/ProcessCommands.java index d79f0f92899..1c7af0c004e 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/ProcessCommands.java +++ b/server/sonar-process/src/main/java/org/sonar/process/ProcessCommands.java @@ -52,6 +52,7 @@ public class ProcessCommands { this.stopFile = new File(directory, processKey + ".stop"); } + // visible for tests ProcessCommands(File readyFile, File stopFile) { this.readyFile = readyFile; this.stopFile = stopFile; diff --git a/server/sonar-process/src/main/java/org/sonar/process/StopWatcher.java b/server/sonar-process/src/main/java/org/sonar/process/StopWatcher.java index 2441a193748..4ba726a2d85 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/StopWatcher.java +++ b/server/sonar-process/src/main/java/org/sonar/process/StopWatcher.java @@ -21,16 +21,26 @@ package org.sonar.process; import org.slf4j.LoggerFactory; +/** + * This watchdog asks for graceful termination of process when the file + * <process_key>.stop is created in temp directory. + */ public class StopWatcher extends Thread { private final Stoppable stoppable; private final ProcessCommands commands; private boolean watching = true; + private final long delayMs; public StopWatcher(ProcessCommands commands, Stoppable stoppable) { + this(commands, stoppable, 500L); + } + + StopWatcher(ProcessCommands commands, Stoppable stoppable, long delayMs) { super("Stop Watcher"); this.commands = commands; this.stoppable = stoppable; + this.delayMs = delayMs; } @Override @@ -44,7 +54,7 @@ public class StopWatcher extends Thread { watching = false; } else { try { - Thread.sleep(500L); + Thread.sleep(delayMs); } catch (InterruptedException ignored) { watching = false; } diff --git a/server/sonar-process/src/test/java/org/sonar/process/ConfigurationUtilsTest.java b/server/sonar-process/src/test/java/org/sonar/process/ConfigurationUtilsTest.java index de928b93850..4aa072a6eb3 100644 --- a/server/sonar-process/src/test/java/org/sonar/process/ConfigurationUtilsTest.java +++ b/server/sonar-process/src/test/java/org/sonar/process/ConfigurationUtilsTest.java @@ -24,6 +24,7 @@ import org.apache.commons.io.FileUtils; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; +import org.sonar.test.TestUtils; import java.io.File; import java.util.Map; @@ -92,4 +93,9 @@ public class ConfigurationUtilsTest { assertThat(e).hasMessage("Could not read properties from file: " + propsFile.getAbsolutePath()); } } + + @Test + public void private_constructor() throws Exception { + TestUtils.assertPrivateConstructor(ConfigurationUtils.class); + } } diff --git a/server/sonar-process/src/test/java/org/sonar/process/LoopbackAddressTest.java b/server/sonar-process/src/test/java/org/sonar/process/LoopbackAddressTest.java index 6a8819c3a81..b612e24342d 100644 --- a/server/sonar-process/src/test/java/org/sonar/process/LoopbackAddressTest.java +++ b/server/sonar-process/src/test/java/org/sonar/process/LoopbackAddressTest.java @@ -21,6 +21,7 @@ package org.sonar.process; import com.google.common.collect.Iterators; import org.junit.Test; +import org.sonar.test.TestUtils; import java.net.NetworkInterface; import java.util.Collections; @@ -48,4 +49,9 @@ public class LoopbackAddressTest { assertThat(e).hasMessage("Impossible to get a IPv4 loopback address"); } } + + @Test + public void private_constructor() throws Exception { + TestUtils.assertPrivateConstructor(LoopbackAddress.class); + } } diff --git a/server/sonar-process/src/test/java/org/sonar/process/NetworkUtilsTest.java b/server/sonar-process/src/test/java/org/sonar/process/NetworkUtilsTest.java index 9eb41dbf6ac..0462f76707a 100644 --- a/server/sonar-process/src/test/java/org/sonar/process/NetworkUtilsTest.java +++ b/server/sonar-process/src/test/java/org/sonar/process/NetworkUtilsTest.java @@ -20,8 +20,7 @@ package org.sonar.process; import org.junit.Test; - -import java.net.ServerSocket; +import org.sonar.test.TestUtils; import static org.fest.assertions.Assertions.assertThat; @@ -38,23 +37,11 @@ public class NetworkUtilsTest { int port1 = NetworkUtils.freePort(); int port2 = NetworkUtils.freePort(); - assertThat(port1).isGreaterThan(1024); - assertThat(port2).isGreaterThan(1024); - assertThat(port1).isNotSameAs(port2); } @Test - public void find_multiple_free_non_adjacent_port() throws Exception { - int port1 = NetworkUtils.freePort(); - - ServerSocket socket = new ServerSocket(port1 + 1); - - int port2 = NetworkUtils.freePort(); - - assertThat(port1).isGreaterThan(1024); - assertThat(port2).isGreaterThan(1024); - - assertThat(port1).isNotSameAs(port2); + public void private_constructor() throws Exception { + TestUtils.assertPrivateConstructor(NetworkUtils.class); } } diff --git a/server/sonar-process/src/test/java/org/sonar/process/ProcessCommandsTest.java b/server/sonar-process/src/test/java/org/sonar/process/ProcessCommandsTest.java index e81a537e2ee..984fbed74f7 100644 --- a/server/sonar-process/src/test/java/org/sonar/process/ProcessCommandsTest.java +++ b/server/sonar-process/src/test/java/org/sonar/process/ProcessCommandsTest.java @@ -37,7 +37,20 @@ public class ProcessCommandsTest { public TemporaryFolder temp = new TemporaryFolder(); @Test - public void delete_files_on_monitor_startup() throws Exception { + public void fail_to_init_if_dir_does_not_exist() throws Exception { + File dir = temp.newFolder(); + FileUtils.deleteQuietly(dir); + + try { + new ProcessCommands(dir, "web"); + fail(); + } catch (IllegalArgumentException e) { + assertThat(e).hasMessage("Not a valid directory: " + dir.getAbsolutePath()); + } + } + + @Test + public void delete_files_on_prepare() throws Exception { File dir = temp.newFolder(); assertThat(dir).exists(); FileUtils.touch(new File(dir, "web.ready")); @@ -67,18 +80,32 @@ public class ProcessCommandsTest { @Test public void child_process_create_file_when_ready() throws Exception { - File readyFile = temp.newFile(); + File dir = temp.newFolder(); - ProcessCommands commands = new ProcessCommands(readyFile, temp.newFile()); + ProcessCommands commands = new ProcessCommands(dir, "web"); commands.prepare(); assertThat(commands.isReady()).isFalse(); - assertThat(readyFile).doesNotExist(); + assertThat(commands.getReadyFile()).doesNotExist(); commands.setReady(); assertThat(commands.isReady()).isTrue(); - assertThat(readyFile).exists(); + assertThat(commands.getReadyFile()).exists().isFile(); commands.endWatch(); - assertThat(readyFile).doesNotExist(); + assertThat(commands.getReadyFile()).doesNotExist(); + } + + @Test + public void ask_for_stop() throws Exception { + File dir = temp.newFolder(); + + ProcessCommands commands = new ProcessCommands(dir, "web"); + assertThat(commands.askedForStop()).isFalse(); + assertThat(commands.getStopFile()).doesNotExist(); + + commands.askForStop(); + assertThat(commands.askedForStop()).isTrue(); + assertThat(commands.getStopFile()).exists().isFile(); + assertThat(commands.getStopFile().getName()).isEqualTo("web.stop"); } } diff --git a/server/sonar-process/src/test/java/org/sonar/process/ProcessUtilsTest.java b/server/sonar-process/src/test/java/org/sonar/process/ProcessUtilsTest.java new file mode 100644 index 00000000000..ae1f53b2653 --- /dev/null +++ b/server/sonar-process/src/test/java/org/sonar/process/ProcessUtilsTest.java @@ -0,0 +1,31 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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; + +import org.junit.Test; +import org.sonar.test.TestUtils; + +public class ProcessUtilsTest { + + @Test + public void private_constructor() throws Exception { + TestUtils.assertPrivateConstructor(ProcessUtils.class); + } +} diff --git a/server/sonar-process/src/test/java/org/sonar/process/PropsTest.java b/server/sonar-process/src/test/java/org/sonar/process/PropsTest.java index 5d283b44f8f..25feeef39b8 100644 --- a/server/sonar-process/src/test/java/org/sonar/process/PropsTest.java +++ b/server/sonar-process/src/test/java/org/sonar/process/PropsTest.java @@ -19,8 +19,12 @@ */ package org.sonar.process; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import java.io.File; +import java.io.IOException; import java.util.Properties; import static org.fest.assertions.Assertions.assertThat; @@ -28,8 +32,11 @@ import static org.fest.assertions.Fail.fail; public class PropsTest { + @Rule + public TemporaryFolder temp = new TemporaryFolder(); + @Test - public void of() throws Exception { + public void value() throws Exception { Properties p = new Properties(); p.setProperty("foo", "bar"); Props props = new Props(p); @@ -38,10 +45,18 @@ public class PropsTest { assertThat(props.value("foo", "default value")).isEqualTo("bar"); assertThat(props.value("unknown")).isNull(); assertThat(props.value("unknown", "default value")).isEqualTo("default value"); + + assertThat(props.nonNullValue("foo")).isEqualTo("bar"); + try { + props.nonNullValue("other"); + fail(); + } catch (IllegalArgumentException e) { + assertThat(e).hasMessage("Missing property: other"); + } } @Test - public void intOf() throws Exception { + public void valueAsInt() throws Exception { Properties p = new Properties(); p.setProperty("foo", "33"); p.setProperty("blank", ""); @@ -56,7 +71,7 @@ public class PropsTest { } @Test - public void intOf_not_integer() throws Exception { + public void valueAsInt_not_integer() throws Exception { Properties p = new Properties(); p.setProperty("foo", "bar"); Props props = new Props(p); @@ -130,6 +145,21 @@ public class PropsTest { // do not decrypt assertThat(props.rawProperties().get("encrypted_prop")).isEqualTo("{aes}abcde"); assertThat(props.rawProperties().get("clear_prop")).isEqualTo("foo"); + } + @Test + public void nonNullValueAsFile() throws IOException { + File file = temp.newFile(); + Props props = new Props(new Properties()); + props.set("path", file.getAbsolutePath()); + + assertThat(props.nonNullValueAsFile("path")).isEqualTo(file); + + try { + props.nonNullValueAsFile("other_path"); + fail(); + } catch (IllegalArgumentException e) { + assertThat(e).hasMessage("Property other_path is not set"); + } } } diff --git a/server/sonar-process/src/test/java/org/sonar/process/StopWatcherTest.java b/server/sonar-process/src/test/java/org/sonar/process/StopWatcherTest.java new file mode 100644 index 00000000000..8a6545e5819 --- /dev/null +++ b/server/sonar-process/src/test/java/org/sonar/process/StopWatcherTest.java @@ -0,0 +1,59 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +import static org.mockito.Mockito.*; + +public class StopWatcherTest { + + @Rule + public TemporaryFolder temp = new TemporaryFolder(); + + @Test(timeout = 1000L) + public void stop_if_receive_command() throws Exception { + ProcessCommands commands = mock(ProcessCommands.class); + when(commands.askedForStop()).thenReturn(false).thenReturn(true); + Stoppable stoppable = mock(Stoppable.class); + + StopWatcher watcher = new StopWatcher(commands, stoppable, 10L); + watcher.start(); + watcher.join(); + + verify(stoppable).stopAsync(); + } + + @Test(timeout = 1000L) + public void stop_watching_on_interruption() throws Exception { + ProcessCommands commands = mock(ProcessCommands.class); + when(commands.askedForStop()).thenReturn(false); + Stoppable stoppable = mock(Stoppable.class); + + StopWatcher watcher = new StopWatcher(commands, stoppable, 1000L); + watcher.start(); + Thread.sleep(50L); + watcher.interrupt(); + + verify(stoppable, never()).stopAsync(); + } +} diff --git a/server/sonar-process/src/test/java/org/sonar/process/StopperThreadTest.java b/server/sonar-process/src/test/java/org/sonar/process/StopperThreadTest.java index e1eed0548aa..494457134a8 100644 --- a/server/sonar-process/src/test/java/org/sonar/process/StopperThreadTest.java +++ b/server/sonar-process/src/test/java/org/sonar/process/StopperThreadTest.java @@ -25,55 +25,47 @@ import org.junit.rules.TemporaryFolder; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; -import java.io.File; - -import static org.fest.assertions.Assertions.assertThat; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.*; public class StopperThreadTest { + @Rule public TemporaryFolder temp = new TemporaryFolder(); - @Test(timeout = 3000L) public void stop_in_a_timely_fashion() throws Exception { -// File dir = temp.newFile(); -// ProcessCommands commands = new ProcessCommands(dir, "foo"); -// assertThat(dir).exists(); -// Monitored monitored = mock(Monitored.class); -// -// // max stop timeout is 5 seconds, but test fails after 3 seconds -// // -> guarantees that stop is immediate -// StopperThread stopper = new StopperThread(monitored, commands, 5000L); -// stopper.start(); -// stopper.join(); -// -// verify(monitored).stop(); -// assertThat(dir).doesNotExist(); + ProcessCommands commands = mock(ProcessCommands.class); + Monitored monitored = mock(Monitored.class); + + // max stop timeout is 5 seconds, but test fails after 3 seconds + // -> guarantees that stop is immediate + StopperThread stopper = new StopperThread(monitored, commands, 5000L); + stopper.start(); + stopper.join(); + + verify(monitored).stop(); + verify(commands).endWatch(); } @Test(timeout = 3000L) public void stop_timeout() throws Exception { -// File file = temp.newFile(); -// ProcessCommands commands = new ProcessCommands(file); -// assertThat(file).exists(); -// Monitored monitored = mock(Monitored.class); -// doAnswer(new Answer() { -// @Override -// public Object answer(InvocationOnMock invocationOnMock) throws Throwable { -// Thread.sleep(10000L); -// return null; -// } -// }).when(monitored).stop(); -// -// // max stop timeout is 10 milliseconds -// StopperThread stopper = new StopperThread(monitored, commands, 10L); -// stopper.start(); -// stopper.join(); -// -// verify(monitored).stop(); -// assertThat(file).doesNotExist(); + ProcessCommands commands = mock(ProcessCommands.class); + Monitored monitored = mock(Monitored.class); + doAnswer(new Answer() { + @Override + public Object answer(InvocationOnMock invocationOnMock) throws Throwable { + Thread.sleep(10000L); + return null; + } + }).when(monitored).stop(); + + // max stop timeout is 50 milliseconds + StopperThread stopper = new StopperThread(monitored, commands, 50L); + stopper.start(); + stopper.join(); + + verify(monitored).stop(); + // even if stopper was interrupted, stop watching process + verify(commands).endWatch(); } } diff --git a/server/sonar-web/src/main/webapp/WEB-INF/config/environment.rb b/server/sonar-web/src/main/webapp/WEB-INF/config/environment.rb index 986137d1976..81f897e66a3 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/config/environment.rb +++ b/server/sonar-web/src/main/webapp/WEB-INF/config/environment.rb @@ -72,7 +72,7 @@ Rails::Initializer.run do |config| # The development mode (real-time edition of ruby code) can be enabled on an app by replacing the # following line by : # config.plugin_paths << '/absolute/path/to/myproject/src/main/resources/org/sonar/ror' - config.plugin_paths << "#{Java::OrgSonarServerUi::JRubyFacade.getInstance().getServerHome()}/temp/ror" + config.plugin_paths << "#{Java::JavaLang::System.getProperty("java.io.tmpdir")}/ror" # Force all environments to use the same logger level # (by default production uses :info, the others :debug) diff --git a/sonar-application/pom.xml b/sonar-application/pom.xml index 547bff09e2d..b054c0bd128 100644 --- a/sonar-application/pom.xml +++ b/sonar-application/pom.xml @@ -154,18 +154,8 @@ <!-- unit tests --> <dependency> - <groupId>junit</groupId> - <artifactId>junit</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.hamcrest</groupId> - <artifactId>hamcrest-all</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.easytesting</groupId> - <artifactId>fest-assert</artifactId> + <groupId>org.codehaus.sonar</groupId> + <artifactId>sonar-testing-harness</artifactId> <scope>test</scope> </dependency> <dependency> diff --git a/sonar-application/src/test/java/org/sonar/application/DefaultSettingsTest.java b/sonar-application/src/test/java/org/sonar/application/DefaultSettingsTest.java index 11bcb2f5631..49a66bc590c 100644 --- a/sonar-application/src/test/java/org/sonar/application/DefaultSettingsTest.java +++ b/sonar-application/src/test/java/org/sonar/application/DefaultSettingsTest.java @@ -21,6 +21,7 @@ package org.sonar.application; import org.junit.Test; import org.sonar.process.Props; +import org.sonar.test.TestUtils; import java.util.Properties; @@ -56,4 +57,9 @@ public class DefaultSettingsTest { DefaultSettings.init(props); assertThat(props.valueAsInt("sonar.search.port")).isGreaterThan(0); } + + @Test + public void private_constructor() throws Exception { + TestUtils.assertPrivateConstructor(DefaultSettings.class); + } } diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/DefaultDatabase.java b/sonar-core/src/main/java/org/sonar/core/persistence/DefaultDatabase.java index d8a0dadc24b..50e7a54790a 100644 --- a/sonar-core/src/main/java/org/sonar/core/persistence/DefaultDatabase.java +++ b/sonar-core/src/main/java/org/sonar/core/persistence/DefaultDatabase.java @@ -111,8 +111,8 @@ public class DefaultDatabase implements Database { try { LOG.debug("Testing JDBC connection"); connection = datasource.getConnection(); - } catch (Exception e) { - LOG.error("Can not connect to database. Please check connectivity and settings (see the properties prefixed by 'sonar.jdbc.').", e); + } catch (SQLException e) { + throw new IllegalStateException("Can not connect to database. Please check connectivity and settings (see the properties prefixed by 'sonar.jdbc.').", e); } finally { DbUtils.closeQuietly(connection); } diff --git a/sonar-testing-harness/src/main/java/org/sonar/test/TestUtils.java b/sonar-testing-harness/src/main/java/org/sonar/test/TestUtils.java index e537466d262..0a5d8fcaef0 100644 --- a/sonar-testing-harness/src/main/java/org/sonar/test/TestUtils.java +++ b/sonar-testing-harness/src/main/java/org/sonar/test/TestUtils.java @@ -23,8 +23,13 @@ import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; import java.io.File; +import java.lang.reflect.Constructor; +import java.lang.reflect.Modifier; import java.net.URL; +import static org.fest.assertions.Assertions.assertThat; +import static org.fest.assertions.Fail.fail; + /** * Utilities for unit tests * @@ -67,4 +72,15 @@ public final class TestUtils { resourcePath += path; return getResource(resourcePath); } + + public static void assertPrivateConstructor(Class clazz) { + try { + Constructor constructor = clazz.getDeclaredConstructor(); + assertThat(Modifier.isPrivate(constructor.getModifiers())).isTrue(); + constructor.setAccessible(true); + constructor.newInstance(); + } catch (Exception e) { + fail("Fail to instantiate " + clazz, e); + } + } } |