ProcessFactoryImpl implements ProcessFactory { @Override public ChildProcess2Impl spawn(CommandLine commandLine) { List<String> arguments = commandLine.getArguments(); if (arguments.isEmpty()) { throw new IllegalArgumentException("No arguments specified - missing program to spawn"); } ProcessBuilder processBuilder = new ProcessBuilder(arguments); if (commandLine.getRedirectStderrToStdoutInsteadOfDiscard()) { processBuilder.redirectErrorStream(true); } else { processBuilder.redirectError(ProcessBuilder.Redirect.to(DEV_NULL)); } FileAttribute<Set<PosixFilePermission>> fileAttribute = PosixFilePermissions.asFileAttribute( PosixFilePermissions.fromString("rw-------")); Path outputFile = commandLine.getOutputFile() .map(file -> { uncheck(() -> Files.deleteIfExists(file)); uncheck(() -> Files.createFile(file, fileAttribute)); return file; }) .orElseGet(() -> { String temporaryFilePrefix = ProcessFactoryImpl.class.getSimpleName() + "-" + commandLine.programName() + "-"; return uncheck(() -> Files.createTempFile( temporaryFilePrefix, ".out", fileAttribute)); }); try { processBuilder.redirectOutput(outputFile.toFile()); ProcessApi2 process = processStarter.start(processBuilder); return new ChildProcess2Impl(commandLine, process, outputFile, timer); } catch (RuntimeException | Error throwable) { try { if (commandLine.getOutputFile().isEmpty()) Files.delete(outputFile); } catch (IOException ioException) { logger.log(Level.WARNING, "Failed to delete temporary file at " + outputFile, ioException); } throw throwable; } } ProcessFactoryImpl(ProcessStarter processStarter, Timer timer); @Override ChildProcess2Impl spawn(CommandLine commandLine);  }
@Test public void testSpawn() { CommandLine commandLine = mock(CommandLine.class); when(commandLine.getArguments()).thenReturn(List.of("program")); when(commandLine.getRedirectStderrToStdoutInsteadOfDiscard()).thenReturn(true); when(commandLine.programName()).thenReturn("program"); Path outputPath; try (ChildProcess2Impl child = processFactory.spawn(commandLine)) { outputPath = child.getOutputPath(); assertTrue(Files.exists(outputPath)); assertEquals("rw-------", new UnixPath(outputPath).getPermissions()); ArgumentCaptor<ProcessBuilder> processBuilderCaptor = ArgumentCaptor.forClass(ProcessBuilder.class); verify(starter).start(processBuilderCaptor.capture()); ProcessBuilder processBuilder = processBuilderCaptor.getValue(); assertTrue(processBuilder.redirectErrorStream()); ProcessBuilder.Redirect redirect = processBuilder.redirectOutput(); assertEquals(ProcessBuilder.Redirect.Type.WRITE, redirect.type()); assertEquals(outputPath.toFile(), redirect.file()); } assertFalse(Files.exists(outputPath)); }
@Test public void testSpawnWithPersistentOutputFile() { class TemporaryFile implements AutoCloseable { private final Path path; private TemporaryFile() { String outputFileName = ProcessFactoryImplTest.class.getSimpleName() + "-temporary-test-file.out"; FileAttribute<Set<PosixFilePermission>> fileAttribute = PosixFilePermissions.asFileAttribute( PosixFilePermissions.fromString("rw-------")); path = uncheck(() -> Files.createTempFile(outputFileName, ".out", fileAttribute)); } @Override public void close() { uncheck(() -> Files.deleteIfExists(path)); } } try (TemporaryFile outputPath = new TemporaryFile()) { CommandLine commandLine = mock(CommandLine.class); when(commandLine.getArguments()).thenReturn(List.of("program")); when(commandLine.programName()).thenReturn("program"); when(commandLine.getOutputFile()).thenReturn(Optional.of(outputPath.path)); try (ChildProcess2Impl child = processFactory.spawn(commandLine)) { assertEquals(outputPath.path, child.getOutputPath()); assertTrue(Files.exists(outputPath.path)); assertEquals("rw-------", new UnixPath(outputPath.path).getPermissions()); } assertTrue(Files.exists(outputPath.path)); } }