diff options
author | Jenkins CI <ci@sonarsource.com> | 2014-09-22 17:59:10 +0200 |
---|---|---|
committer | Jenkins CI <ci@sonarsource.com> | 2014-09-22 17:59:10 +0200 |
commit | 5506038e6bebe3c0be5d7d3c099c4e6f73e315be (patch) | |
tree | 5e554ea1f9467b8060cbe075ce61d1ae3b97b501 /server/sonar-process | |
parent | 8a7965dfbc7c967e199d5cf4f4c83ff8dd81a6c3 (diff) | |
parent | 92c30ccd4cd311dc602c0e1a08fc97c09970a4f6 (diff) | |
download | sonarqube-5506038e6bebe3c0be5d7d3c099c4e6f73e315be.tar.gz sonarqube-5506038e6bebe3c0be5d7d3c099c4e6f73e315be.zip |
Automatic merge from branch-4.5
* origin/branch-4.5:
SONAR-4898 file-based inter-process communication
SONAR-4898 add info log
Diffstat (limited to 'server/sonar-process')
9 files changed, 373 insertions, 224 deletions
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 new file mode 100644 index 00000000000..259af6b1eeb --- /dev/null +++ b/server/sonar-process/src/main/java/org/sonar/process/ProcessCommands.java @@ -0,0 +1,125 @@ +/* + * 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.apache.commons.io.FileUtils; + +import java.io.File; +import java.io.IOException; + +/** + * Process inter-communication to : + * <ul> + * <li>share status of child process</li> + * <li>stop child process</li> + * </ul> + * + * <p/> + * It relies on files shared by both processes. Following alternatives were considered but not selected : + * <ul> + * <li>JMX beans over RMI: network issues (mostly because of Java reverse-DNS) + requires to configure and open a new port</li> + * <li>simple socket protocol: same drawbacks are RMI connection</li> + * <li>java.lang.Process#destroy(): shutdown hooks are not executed on some OS (mostly MSWindows)</li> + * <li>execute OS-specific commands (for instance kill on *nix): OS-specific, so hell to support. Moreover how to get identify a process ?</li> + * </ul> + */ +public class ProcessCommands { + + private final File readyFile, stopFile; + + public ProcessCommands(File directory, String processKey) { + if (!directory.isDirectory() || !directory.exists()) { + throw new IllegalArgumentException("Not a valid directory: " + directory); + } + this.readyFile = new File(directory, processKey + ".ready"); + this.stopFile = new File(directory, processKey + ".stop"); + } + + ProcessCommands(File readyFile, File stopFile) { + this.readyFile = readyFile; + this.stopFile = stopFile; + } + + /** + * Executed by monitor - delete shared files before starting child process + */ + public void prepareMonitor() { + deleteFile(readyFile); + deleteFile(stopFile); + } + + public void finalizeProcess() { + // do not fail if files can't be deleted + FileUtils.deleteQuietly(readyFile); + FileUtils.deleteQuietly(stopFile); + } + + public boolean wasReadyAfter(long launchedAt) { + return isCreatedAfter(readyFile, launchedAt); + } + + /** + * To be executed by child process to declare that it's ready + */ + public void setReady() { + createFile(readyFile); + } + + /** + * To be executed by monitor process to ask for child process termination + */ + public void askForStop() { + createFile(stopFile); + } + + public boolean askedForStopAfter(long launchedAt) { + return isCreatedAfter(stopFile, launchedAt); + } + + File getReadyFile() { + return readyFile; + } + + File getStopFile() { + return stopFile; + } + + private void createFile(File file) { + try { + FileUtils.touch(file); + } catch (IOException e) { + throw new IllegalStateException(String.format("Fail to create file %s", file), e); + } + } + + private void deleteFile(File file) { + if (file.exists()) { + if (!file.delete()) { + throw new MessageException(String.format( + "Fail to delete file %s. Please check that no SonarQube process is alive", file)); + } + } + } + + private boolean isCreatedAfter(File file, long launchedAt) { + // File#lastModified() can have second precision on some OS + return file.exists() && file.lastModified() / 1000 >= launchedAt / 1000; + } +} diff --git a/server/sonar-process/src/main/java/org/sonar/process/ProcessEntryPoint.java b/server/sonar-process/src/main/java/org/sonar/process/ProcessEntryPoint.java index 78d3e280802..f4d6e7f90f7 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/ProcessEntryPoint.java +++ b/server/sonar-process/src/main/java/org/sonar/process/ProcessEntryPoint.java @@ -25,33 +25,42 @@ public class ProcessEntryPoint { public static final String PROPERTY_PROCESS_KEY = "process.key"; public static final String PROPERTY_TERMINATION_TIMEOUT = "process.terminationTimeout"; - public static final String PROPERTY_STATUS_PATH = "process.statusPath"; + public static final String PROPERTY_SHARED_PATH = "process.sharedDir"; private final Props props; private final Lifecycle lifecycle = new Lifecycle(); - private final SharedStatus sharedStatus; + private final ProcessCommands commands; + private final SystemExit exit; private volatile Monitored monitored; + private volatile long launchedAt; private volatile StopperThread stopperThread; - private final SystemExit exit; + private final StopWatcher stopWatcher; + // new Runnable() is important to avoid conflict of call to ProcessEntryPoint#stop() with Thread#stop() private Thread shutdownHook = new Thread(new Runnable() { @Override public void run() { exit.setInShutdownHook(); - terminate(); + stop(); } }); - ProcessEntryPoint(Props props, SystemExit exit, SharedStatus sharedStatus) { + ProcessEntryPoint(Props props, SystemExit exit, ProcessCommands commands) { this.props = props; this.exit = exit; - this.sharedStatus = sharedStatus; + this.commands = commands; + this.launchedAt = System.currentTimeMillis(); + this.stopWatcher = new StopWatcher(commands, this); } public Props getProps() { return props; } + public String getKey() { + return props.nonNullValue(PROPERTY_PROCESS_KEY); + } + /** * Launch process and waits until it's down */ @@ -62,7 +71,10 @@ public class ProcessEntryPoint { monitored = mp; try { + LoggerFactory.getLogger(getClass()).warn("Starting " + getKey()); Runtime.getRuntime().addShutdownHook(shutdownHook); + stopWatcher.start(); + monitored.start(); boolean ready = false; while (!ready) { @@ -70,16 +82,17 @@ public class ProcessEntryPoint { Thread.sleep(200L); } - sharedStatus.setReady(); + // notify monitor that process is ready + commands.setReady(); if (lifecycle.tryToMoveTo(Lifecycle.State.STARTED)) { monitored.awaitStop(); } } catch (Exception e) { - LoggerFactory.getLogger(getClass()).warn("Fail to start", e); + LoggerFactory.getLogger(getClass()).warn("Fail to start " + getKey(), e); } finally { - terminate(); + stop(); } } @@ -90,11 +103,8 @@ public class ProcessEntryPoint { /** * Blocks until stopped in a timely fashion (see {@link org.sonar.process.StopperThread}) */ - void terminate() { - if (lifecycle.tryToMoveTo(Lifecycle.State.STOPPING)) { - stopperThread = new StopperThread(monitored, sharedStatus, Long.parseLong(props.nonNullValue(PROPERTY_TERMINATION_TIMEOUT))); - stopperThread.start(); - } + void stop() { + stopAsync(); try { // stopperThread is not null for sure // join() does nothing if thread already finished @@ -106,6 +116,13 @@ public class ProcessEntryPoint { exit.exit(0); } + void stopAsync() { + if (lifecycle.tryToMoveTo(Lifecycle.State.STOPPING)) { + stopperThread = new StopperThread(monitored, commands, Long.parseLong(props.nonNullValue(PROPERTY_TERMINATION_TIMEOUT))); + stopperThread.start(); + } + } + Lifecycle.State getState() { return lifecycle.getState(); } @@ -114,8 +131,14 @@ public class ProcessEntryPoint { return shutdownHook; } + long getLaunchedAt() { + return launchedAt; + } + public static ProcessEntryPoint createForArguments(String[] args) { Props props = ConfigurationUtils.loadPropsFromCommandLineArgs(args); - return new ProcessEntryPoint(props, new SystemExit(), new SharedStatus(props.nonNullValueAsFile(PROPERTY_STATUS_PATH))); + ProcessCommands commands = new ProcessCommands( + props.nonNullValueAsFile(PROPERTY_SHARED_PATH), props.nonNullValue(PROPERTY_PROCESS_KEY)); + return new ProcessEntryPoint(props, new SystemExit(), commands); } } diff --git a/server/sonar-process/src/main/java/org/sonar/process/SharedStatus.java b/server/sonar-process/src/main/java/org/sonar/process/SharedStatus.java deleted file mode 100644 index bbc132044ca..00000000000 --- a/server/sonar-process/src/main/java/org/sonar/process/SharedStatus.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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.apache.commons.io.FileUtils; - -import java.io.File; -import java.io.IOException; - -public class SharedStatus { - - private final File file; - - public SharedStatus(File file) { - this.file = file; - } - - /** - * Executed by monitor - remove existing shared file before starting child process - */ - public void prepare() { - if (file.exists()) { - if (!file.delete()) { - throw new MessageException(String.format( - "Fail to delete file %s. Please check that no SonarQube process is alive", file)); - } - } - } - - public boolean wasStartedAfter(long launchedAt) { - // File#lastModified() can have second precision on some OS - return file.exists() && file.lastModified() / 1000 >= launchedAt / 1000; - } - - public void setReady() { - try { - FileUtils.touch(file); - } catch (IOException e) { - throw new IllegalStateException("Fail to create file " + file, e); - } - } - - public void setStopped() { - FileUtils.deleteQuietly(file); - } -} 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 new file mode 100644 index 00000000000..090b0052423 --- /dev/null +++ b/server/sonar-process/src/main/java/org/sonar/process/StopWatcher.java @@ -0,0 +1,57 @@ +/* + * 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.slf4j.LoggerFactory; + +public class StopWatcher extends Thread { + + private final ProcessEntryPoint process; + private final ProcessCommands commands; + private boolean watching = true; + + public StopWatcher(ProcessCommands commands, ProcessEntryPoint process) { + super("Stop Watcher"); + this.commands = commands; + this.process = process; + } + + @Override + public void run() { + while (watching) { + if (commands.askedForStopAfter(process.getLaunchedAt())) { + LoggerFactory.getLogger(getClass()).info("Stopping process"); + process.stopAsync(); + watching = false; + } else { + try { + Thread.sleep(500L); + } catch (InterruptedException ignored) { + watching = false; + } + } + + } + } + + void stopWatching() { + watching = false; + } +} diff --git a/server/sonar-process/src/main/java/org/sonar/process/StopperThread.java b/server/sonar-process/src/main/java/org/sonar/process/StopperThread.java index ae047363e08..317cd6f62c3 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/StopperThread.java +++ b/server/sonar-process/src/main/java/org/sonar/process/StopperThread.java @@ -33,13 +33,13 @@ class StopperThread extends Thread { private final Monitored monitored; private final long terminationTimeout; - private final SharedStatus sharedStatus; + private final ProcessCommands commands; - StopperThread(Monitored monitored, SharedStatus sharedStatus, long terminationTimeout) { + StopperThread(Monitored monitored, ProcessCommands commands, long terminationTimeout) { super("Stopper"); this.monitored = monitored; this.terminationTimeout = terminationTimeout; - this.sharedStatus = sharedStatus; + this.commands = commands; } @Override @@ -57,6 +57,6 @@ class StopperThread extends Thread { LoggerFactory.getLogger(getClass()).error(String.format("Can not stop in %dms", terminationTimeout), e); } executor.shutdownNow(); - sharedStatus.setStopped(); + commands.finalizeProcess(); } } 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 new file mode 100644 index 00000000000..49c8f024c69 --- /dev/null +++ b/server/sonar-process/src/test/java/org/sonar/process/ProcessCommandsTest.java @@ -0,0 +1,108 @@ +/* + * 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.apache.commons.io.FileUtils; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +import java.io.File; + +import static org.fest.assertions.Assertions.assertThat; +import static org.fest.assertions.Fail.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class ProcessCommandsTest { + + @Rule + public TemporaryFolder temp = new TemporaryFolder(); + + @Test + public void delete_files_on_monitor_startup() throws Exception { + File dir = temp.newFolder(); + assertThat(dir).exists(); + FileUtils.touch(new File(dir, "WEB.ready")); + FileUtils.touch(new File(dir, "WEB.stop")); + + ProcessCommands commands = new ProcessCommands(dir, "WEB"); + commands.prepareMonitor(); + + assertThat(commands.getReadyFile()).doesNotExist(); + assertThat(commands.getStopFile()).doesNotExist(); + } + + @Test + public void fail_to_prepare_if_file_is_locked() throws Exception { + File readyFile = mock(File.class); + when(readyFile.exists()).thenReturn(true); + when(readyFile.delete()).thenReturn(false); + + ProcessCommands commands = new ProcessCommands(readyFile, temp.newFile()); + try { + commands.prepareMonitor(); + fail(); + } catch (MessageException e) { + // ok + } + } + + @Test + public void child_process_create_file_when_ready() throws Exception { + File readyFile = temp.newFile(); + + ProcessCommands commands = new ProcessCommands(readyFile, temp.newFile()); + commands.prepareMonitor(); + assertThat(readyFile).doesNotExist(); + + commands.setReady(); + assertThat(readyFile).exists(); + + commands.finalizeProcess(); + assertThat(readyFile).doesNotExist(); + } + + @Test + public void was_ready_after_date() throws Exception { + File readyFile = mock(File.class); + ProcessCommands commands = new ProcessCommands(readyFile, temp.newFile()); + + // does not exist + when(readyFile.exists()).thenReturn(false); + when(readyFile.lastModified()).thenReturn(123456L); + assertThat(commands.wasReadyAfter(122000L)).isFalse(); + + // readyFile created before + when(readyFile.exists()).thenReturn(true); + when(readyFile.lastModified()).thenReturn(123456L); + assertThat(commands.wasReadyAfter(124000L)).isFalse(); + + // readyFile created after + when(readyFile.exists()).thenReturn(true); + when(readyFile.lastModified()).thenReturn(123456L); + assertThat(commands.wasReadyAfter(123123L)).isTrue(); + + // readyFile created after, but can be truncated to second on some OS + when(readyFile.exists()).thenReturn(true); + when(readyFile.lastModified()).thenReturn(123000L); + assertThat(commands.wasReadyAfter(123456L)).isTrue(); + } +} diff --git a/server/sonar-process/src/test/java/org/sonar/process/ProcessEntryPointTest.java b/server/sonar-process/src/test/java/org/sonar/process/ProcessEntryPointTest.java index 7e51a0d6ac9..c69ca04cd05 100644 --- a/server/sonar-process/src/test/java/org/sonar/process/ProcessEntryPointTest.java +++ b/server/sonar-process/src/test/java/org/sonar/process/ProcessEntryPointTest.java @@ -50,7 +50,7 @@ public class ProcessEntryPointTest { @Test public void load_properties_from_file() throws Exception { File propsFile = temp.newFile(); - FileUtils.write(propsFile, "sonar.foo=bar\nprocess.key=web\nprocess.statusPath=status.temp"); + FileUtils.write(propsFile, "sonar.foo=bar\nprocess.key=web\nprocess.sharedDir=" + temp.newFolder().getAbsolutePath()); ProcessEntryPoint entryPoint = ProcessEntryPoint.createForArguments(new String[] {propsFile.getAbsolutePath()}); assertThat(entryPoint.getProps().value("sonar.foo")).isEqualTo("bar"); @@ -60,7 +60,7 @@ public class ProcessEntryPointTest { @Test public void test_initial_state() throws Exception { Props props = new Props(new Properties()); - ProcessEntryPoint entryPoint = new ProcessEntryPoint(props, exit, mock(SharedStatus.class)); + ProcessEntryPoint entryPoint = new ProcessEntryPoint(props, exit, mock(ProcessCommands.class)); assertThat(entryPoint.getProps()).isSameAs(props); assertThat(entryPoint.isStarted()).isFalse(); @@ -72,7 +72,7 @@ public class ProcessEntryPointTest { Props props = new Props(new Properties()); props.set(ProcessEntryPoint.PROPERTY_PROCESS_KEY, "test"); props.set(ProcessEntryPoint.PROPERTY_TERMINATION_TIMEOUT, "30000"); - ProcessEntryPoint entryPoint = new ProcessEntryPoint(props, exit, mock(SharedStatus.class)); + ProcessEntryPoint entryPoint = new ProcessEntryPoint(props, exit, mock(ProcessCommands.class)); entryPoint.launch(new NoopProcess()); try { @@ -84,11 +84,11 @@ public class ProcessEntryPointTest { } @Test - public void launch_then_request_graceful_termination() throws Exception { + public void launch_then_request_graceful_stop() throws Exception { Props props = new Props(new Properties()); props.set(ProcessEntryPoint.PROPERTY_PROCESS_KEY, "test"); props.set(ProcessEntryPoint.PROPERTY_TERMINATION_TIMEOUT, "30000"); - final ProcessEntryPoint entryPoint = new ProcessEntryPoint(props, exit, mock(SharedStatus.class)); + final ProcessEntryPoint entryPoint = new ProcessEntryPoint(props, exit, mock(ProcessCommands.class)); final StandardProcess process = new StandardProcess(); Thread runner = new Thread() { @@ -104,9 +104,9 @@ public class ProcessEntryPointTest { Thread.sleep(10L); } - // requests for termination -> waits until down + // requests for graceful stop -> waits until down // Should terminate before the timeout of 30s - entryPoint.terminate(); + entryPoint.stop(); assertThat(process.getState()).isEqualTo(State.STOPPED); } @@ -116,7 +116,7 @@ public class ProcessEntryPointTest { Props props = new Props(new Properties()); props.set(ProcessEntryPoint.PROPERTY_PROCESS_KEY, "foo"); props.set(ProcessEntryPoint.PROPERTY_TERMINATION_TIMEOUT, "30000"); - final ProcessEntryPoint entryPoint = new ProcessEntryPoint(props, exit, mock(SharedStatus.class)); + final ProcessEntryPoint entryPoint = new ProcessEntryPoint(props, exit, mock(ProcessCommands.class)); final StandardProcess process = new StandardProcess(); Thread runner = new Thread() { @@ -144,7 +144,7 @@ public class ProcessEntryPointTest { Props props = new Props(new Properties()); props.set(ProcessEntryPoint.PROPERTY_PROCESS_KEY, "foo"); props.set(ProcessEntryPoint.PROPERTY_TERMINATION_TIMEOUT, "30000"); - final ProcessEntryPoint entryPoint = new ProcessEntryPoint(props, exit, mock(SharedStatus.class)); + final ProcessEntryPoint entryPoint = new ProcessEntryPoint(props, exit, mock(ProcessCommands.class)); final Monitored process = new StartupErrorProcess(); entryPoint.launch(process); diff --git a/server/sonar-process/src/test/java/org/sonar/process/SharedStatusTest.java b/server/sonar-process/src/test/java/org/sonar/process/SharedStatusTest.java deleted file mode 100644 index c6703a9c237..00000000000 --- a/server/sonar-process/src/test/java/org/sonar/process/SharedStatusTest.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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 java.io.File; - -import static org.fest.assertions.Assertions.assertThat; -import static org.fest.assertions.Fail.fail; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class SharedStatusTest { - - @Rule - public TemporaryFolder temp = new TemporaryFolder(); - - @Test - public void prepare() throws Exception { - File file = temp.newFile(); - assertThat(file).exists(); - - SharedStatus sharedStatus = new SharedStatus(file); - sharedStatus.prepare(); - assertThat(file).doesNotExist(); - } - - @Test - public void fail_to_prepare_if_file_is_locked() throws Exception { - File file = mock(File.class); - when(file.exists()).thenReturn(true); - when(file.delete()).thenReturn(false); - - SharedStatus sharedStatus = new SharedStatus(file); - try { - sharedStatus.prepare(); - fail(); - } catch (MessageException e) { - // ok - } - } - - @Test - public void create_file_when_ready_then_delete_when_stopped() throws Exception { - File file = new File(temp.newFolder(), "foo.txt"); - assertThat(file).doesNotExist(); - - SharedStatus sharedStatus = new SharedStatus(file); - sharedStatus.setReady(); - assertThat(file).exists(); - - sharedStatus.setStopped(); - assertThat(file).doesNotExist(); - } - - @Test - public void was_started_after() throws Exception { - File file = mock(File.class); - SharedStatus sharedStatus = new SharedStatus(file); - - // does not exist - when(file.exists()).thenReturn(false); - when(file.lastModified()).thenReturn(123456L); - assertThat(sharedStatus.wasStartedAfter(122000L)).isFalse(); - - // file created before - when(file.exists()).thenReturn(true); - when(file.lastModified()).thenReturn(123456L); - assertThat(sharedStatus.wasStartedAfter(124000L)).isFalse(); - - // file created after - when(file.exists()).thenReturn(true); - when(file.lastModified()).thenReturn(123456L); - assertThat(sharedStatus.wasStartedAfter(123123L)).isTrue(); - - // file created after, but can be truncated to second on some OS - when(file.exists()).thenReturn(true); - when(file.lastModified()).thenReturn(123000L); - assertThat(sharedStatus.wasStartedAfter(123456L)).isTrue(); - } -} 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 9e45fe7f080..e1eed0548aa 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 @@ -39,41 +39,41 @@ public class StopperThreadTest { @Test(timeout = 3000L) public void stop_in_a_timely_fashion() throws Exception { - File file = temp.newFile(); - SharedStatus sharedStatus = new SharedStatus(file); - assertThat(file).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, sharedStatus, 5000L); - stopper.start(); - stopper.join(); - - verify(monitored).stop(); - assertThat(file).doesNotExist(); +// 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(); } @Test(timeout = 3000L) public void stop_timeout() throws Exception { - File file = temp.newFile(); - SharedStatus sharedStatus = new SharedStatus(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, sharedStatus, 10L); - stopper.start(); - stopper.join(); - - verify(monitored).stop(); - assertThat(file).doesNotExist(); +// 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(); } } |