package com.spotify.spawn; import org.junit.Test; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import static java.lang.ProcessBuilder.Redirect.INHERIT; import static java.nio.file.StandardOpenOption.WRITE; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.assertThat; public class SubprocessesTest { public static class Foo { public static void main(final String... args) throws IOException { System.out.write("Foo!".getBytes("UTF-8")); System.out.flush(); } } @Test public void testSpawn() throws Exception { final ByteArrayOutputStream stdout = new ByteArrayOutputStream(); final Subprocess subprocess = Subprocesses.process() .main(Foo.class) .pipeStdout(stdout) .spawn(); subprocess.join(); final String output = stdout.toString("UTF-8"); assertThat(output, is("Foo!")); } public static class Parent { public static class Child { public static void main(final String... args) throws IOException { assertThat(args.length, is(1)); final String lockfilename = args[0]; final FileChannel lockfile = FileChannel.open(Paths.get(lockfilename), WRITE); System.err.println("locking " + lockfilename); System.err.flush(); lockfile.lock(); System.err.println("locked " + lockfilename); System.err.flush(); System.out.write(("locked " + lockfilename).getBytes("UTF-8")); System.out.flush(); while (true) { try { Thread.sleep(1000); } catch (InterruptedException ignore) { } } } } public static void main(final String... args) throws IOException { final Subprocess child = Subprocesses.process() .main(Child.class) .inheritIO() .args(args) .spawn(); while (true) { try { Thread.sleep(1000); } catch (InterruptedException ignore) { } } } } @Test public void verifySubprocessTerminatesWhenParentExits() throws Exception { final Path lockFilePath = Files.createTempFile("subprocesses", ".lock"); final FileChannel lockFile = FileChannel.open(lockFilePath, WRITE); final ByteArrayOutputStream stdout = new ByteArrayOutputStream(); final String lockFilename = lockFilePath.toAbsolutePath().toString(); final Subprocess parent = Subprocesses.process() .main(Parent.class) .args(lockFilename) .redirectStderr(INHERIT) .pipeStdout(stdout) .spawn(); // Wait for child to lock file while (true) { if (stdout.size() == 0) { Thread.sleep(100); continue; } final String out = stdout.toString("UTF-8"); assertThat(out, is("locked " + lockFilename)); break; } // Verify that we cannot take the lock while the child is alive assertThat(lockFile.tryLock(), is(nullValue())); // Kill the parent parent.kill(); // Verify that the child exits by taking the file lock while (true) { final FileLock lock = lockFile.tryLock(); if (lock != null) { break; } Thread.sleep(1000); } } }