@@ -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> | |||
@@ -55,11 +50,6 @@ | |||
<artifactId>mockito-core</artifactId> | |||
<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> |
@@ -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; | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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"); | |||
} | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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); | |||
} | |||
} | |||
} |