/* * Copyright 2017 ThoughtWorks, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.thoughtworks.go.util; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; import com.thoughtworks.go.util.command.CommandLine; import com.thoughtworks.go.util.command.CommandLineException; import com.thoughtworks.go.util.command.ConsoleResult; import com.thoughtworks.go.util.command.EnvironmentVariableContext; import com.thoughtworks.go.util.command.InMemoryStreamConsumer; import com.thoughtworks.go.util.command.ProcessOutputStreamConsumer; import org.apache.commons.io.FileUtils; import org.hamcrest.Description; import org.hamcrest.Matcher; import org.hamcrest.TypeSafeMatcher; import org.junit.After; import org.junit.Before; import org.junit.Test; import static com.thoughtworks.go.util.command.ProcessOutputStreamConsumer.inMemoryConsumer; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; public class ProcessWrapperTest { private File tempFolder; @Before public void setUp() throws Exception { tempFolder = FileUtil.createTempFolder(); assertThat(tempFolder.exists(), is(true)); } @After public void teardown() throws Exception { FileUtils.deleteQuietly(tempFolder); } @Test public void shouldReturnTrueWhenAProcessIsRunning(){ Process process = getMockedProcess(mock(OutputStream.class)); when(process.exitValue()).thenThrow(new IllegalThreadStateException()); ProcessWrapper processWrapper = new ProcessWrapper(process, "", "", inMemoryConsumer(), null, null); assertThat(processWrapper.isRunning(), is(true)); } @Test public void shouldReturnFalseWhenAProcessHasExited(){ Process process = getMockedProcess(mock(OutputStream.class)); when(process.exitValue()).thenReturn(1); ProcessWrapper processWrapper = new ProcessWrapper(process, "", "", inMemoryConsumer(), null, null); assertThat(processWrapper.isRunning(), is(false)); } @Test public void shouldTypeInputToConsole(){ OutputStream processInputStream = new ByteArrayOutputStream();// mock(OutputStream.class); Process process = getMockedProcess(processInputStream); ProcessWrapper processWrapper = new ProcessWrapper(process, "", "", inMemoryConsumer(), null, null); ArrayList<String> inputs = new ArrayList<>(); inputs.add("input1"); inputs.add("input2"); processWrapper.typeInputToConsole(inputs); String input = processInputStream.toString(); String[] parts = input.split("\\r?\\n"); assertThat(parts[0], is("input1")); assertThat(parts[1], is("input2")); } @Test public void shouldThrowExceptionWhenExecutableDoesNotExist() throws IOException { CommandLine line = CommandLine.createCommandLine("doesnotexist"); try { ProcessOutputStreamConsumer outputStreamConsumer = inMemoryConsumer(); line.execute(outputStreamConsumer, new EnvironmentVariableContext(), null); fail("Expected exception"); } catch (CommandLineException e) { assertThat(e.getMessage(), containsString("Make sure this command can execute manually.")); assertThat(e.getMessage(), containsString("doesnotexist")); assertThat(e.getResult(), notNullValue()); } } @Test public void shouldTryCommandWithTimeout() throws IOException { CommandLine line = CommandLine.createCommandLine("doesnotexist"); try { line.waitForSuccess(100); fail("Expected Exception"); } catch (Exception e) { assertThat(e.getMessage(), containsString("Timeout after 0.1 seconds waiting for command 'doesnotexist'")); } } @Test public void shouldCollectOutput() throws Exception { String output = "SYSOUT: Hello World!"; String error = "SYSERR: Some error happened!"; CommandLine line = CommandLine.createCommandLine("ruby").withArgs(script("echo"), output, error); ConsoleResult result = run(line); assertThat("Errors: " + result.errorAsString(), result.returnValue(), is(0)); assertThat(result.output(), contains(output)); assertThat(result.error(), contains(error)); } private String script(final String name) { return "../util/test-resources/executables/" + name + ".rb"; } @Test public void shouldAcceptInputString() throws Exception { String input = "SYSIN: Hello World!"; CommandLine line = CommandLine.createCommandLine("ruby").withArgs(script("echo-input")); ConsoleResult result = run(line, input); assertThat(result.output(), contains(input)); assertThat(result.error().size(), is(0)); } @Test public void shouldBeAbleToCompleteInput() throws Exception { String input1 = "SYSIN: Line 1!"; String input2 = "SYSIN: Line 2!"; CommandLine line = CommandLine.createCommandLine("ruby").withArgs(script("echo-all-input")); ConsoleResult result = run(line, input1, input2); assertThat(result.returnValue(), is(0)); assertThat(result.output(), contains("You said: " + input1)); assertThat(result.output(), contains("You said: " + input2)); assertThat(result.error().size(), is(0)); } @Test public void shouldReportReturnValueIfProcessFails() { CommandLine line = CommandLine.createCommandLine("ruby").withArgs(script("nonexistent-script")); ConsoleResult result = run(line); assertThat(result.returnValue(), is(1)); } @Test public void shouldSetGoServerVariablesIfTheyExist() { System.setProperty("GO_DEPENDENCY_LABEL_PIPELINE_NAME", "999"); CommandLine line = CommandLine.createCommandLine("ruby").withArgs(script("dump-environment")); ConsoleResult result = run(line); assertThat("Errors: " + result.errorAsString(), result.returnValue(), is(0)); assertThat(result.output(), contains("GO_DEPENDENCY_LABEL_PIPELINE_NAME=999")); } private ConsoleResult run(CommandLine line, String... inputs) { InMemoryStreamConsumer outputStreamConsumer = inMemoryConsumer(); EnvironmentVariableContext environmentVariableContext = new EnvironmentVariableContext(); environmentVariableContext.setProperty("GO_DEPENDENCY_LABEL_PIPELINE_NAME", "999", false); line.addInput(inputs); ProcessWrapper processWrapper = line.execute(outputStreamConsumer, environmentVariableContext, null); return new ConsoleResult(processWrapper.waitForExit(), outputStreamConsumer.getStdLines(), outputStreamConsumer.getErrLines(), line.getArguments(), new ArrayList<>()); } private Matcher<List<String>> contains(final String output) { return new TypeSafeMatcher<List<String>>() { public boolean matchesSafely(List<String> lines) { for (String line : lines) { if (line.contains(output)) { return true; } } return false; } public void describeTo(Description description) { description.appendText("to contain " + output); } }; } private Process getMockedProcess(OutputStream outputStream) { Process process = mock(Process.class); when(process.getErrorStream()).thenReturn(mock(InputStream.class)); when(process.getInputStream()).thenReturn(mock(InputStream.class)); when(process.getOutputStream()).thenReturn(outputStream); return process; } }