diff --git a/pom.xml b/pom.xml index a5fc6365fc..c4279e4a38 100644 --- a/pom.xml +++ b/pom.xml @@ -46,6 +46,7 @@ spring-boot-integration-tests + spring-boot-cli-integration-tests diff --git a/spring-boot-cli-integration-tests/pom.xml b/spring-boot-cli-integration-tests/pom.xml new file mode 100644 index 0000000000..bc520793ff --- /dev/null +++ b/spring-boot-cli-integration-tests/pom.xml @@ -0,0 +1,51 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-parent + 0.5.0.BUILD-SNAPSHOT + ../spring-boot-parent + + spring-boot-cli-integration-tests + + ${basedir}/.. + + + + junit + junit + test + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + unpack + generate-resources + + unpack + + + + + ${project.groupId} + spring-boot-cli + ${project.version} + bin + zip + true + + + + + + + + + \ No newline at end of file diff --git a/spring-boot-cli-integration-tests/src/test/java/org/springframework/boot/cli/it/UsabilityTests.java b/spring-boot-cli-integration-tests/src/test/java/org/springframework/boot/cli/it/UsabilityTests.java new file mode 100644 index 0000000000..4387707acb --- /dev/null +++ b/spring-boot-cli-integration-tests/src/test/java/org/springframework/boot/cli/it/UsabilityTests.java @@ -0,0 +1,70 @@ +package org.springframework.boot.cli.it; + +import java.io.IOException; + +import org.junit.Test; +import org.springframework.boot.cli.it.infrastructure.Cli; +import org.springframework.boot.cli.it.infrastructure.CliInvocation; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * @author Andy Wilkinson + */ +public class UsabilityTests { + + private final Cli cli = new Cli(); + + @Test + public void hintProducesListOfValidCommands() throws IOException, + InterruptedException { + CliInvocation cli = this.cli.invoke("hint"); + + assertEquals(0, cli.await()); + assertEquals(0, cli.getErrorOutput().length()); + assertEquals(6, cli.getStandardOutputLines().size()); + } + + @Test + public void invokingWithNoArgumentsDisplaysHelp() throws IOException, + InterruptedException { + CliInvocation cli = this.cli.invoke(); + + assertEquals(1, cli.await()); // TODO Should this be 0? Probably not. + assertEquals(0, cli.getErrorOutput().length()); + assertTrue(cli.getStandardOutput().startsWith("usage:")); + } + + @Test + public void unrecognizedCommandsAreHandledGracefully() throws IOException, + InterruptedException { + CliInvocation cli = this.cli.invoke("not-a-real-command"); + + assertEquals(1, cli.await()); + assertTrue( + cli.getErrorOutput(), + cli.getErrorOutput().contains( + "'not-a-real-command' is not a valid command")); + assertEquals(0, cli.getStandardOutput().length()); + } + + @Test + public void version() throws IOException, InterruptedException { + CliInvocation cli = this.cli.invoke("version"); + + assertEquals(0, cli.await()); + assertEquals(0, cli.getErrorOutput().length()); + assertTrue(cli.getStandardOutput(), + cli.getStandardOutput().startsWith("Spring CLI v")); + } + + @Test + public void help() throws IOException, InterruptedException { + CliInvocation cli = this.cli.invoke("help"); + + assertEquals(1, cli.await()); // TODO Should this be 0? Perhaps. + assertEquals(0, cli.getErrorOutput().length()); + assertTrue(cli.getStandardOutput().startsWith("usage:")); + } +} diff --git a/spring-boot-cli-integration-tests/src/test/java/org/springframework/boot/cli/it/infrastructure/Cli.java b/spring-boot-cli-integration-tests/src/test/java/org/springframework/boot/cli/it/infrastructure/Cli.java new file mode 100644 index 0000000000..b9bc3b9a3a --- /dev/null +++ b/spring-boot-cli-integration-tests/src/test/java/org/springframework/boot/cli/it/infrastructure/Cli.java @@ -0,0 +1,48 @@ +package org.springframework.boot.cli.it.infrastructure; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @author Andy Wilkinson + */ +public final class Cli { + + public CliInvocation invoke(String... args) throws IOException { + return new CliInvocation(launchCli(args)); + } + + private Process launchCli(String... args) throws IOException { + List arguments = Arrays.asList(args); + + List command = new ArrayList(); + command.add(findLaunchScript().getAbsolutePath()); + command.addAll(arguments); + + return new ProcessBuilder(command).start(); + } + + private File findLaunchScript() { + File dependencyDirectory = new File("target/dependency"); + if (dependencyDirectory.isDirectory()) { + File[] files = dependencyDirectory.listFiles(); + if (files.length == 1) { + File binDirectory = new File(files[0], "bin"); + if (isWindows()) { + return new File(binDirectory, "spring.bat"); + } + else { + return new File(binDirectory, "spring"); + } + } + } + throw new IllegalStateException("Could not find CLI launch script"); + } + + private boolean isWindows() { + return File.separatorChar == '\\'; + } +} diff --git a/spring-boot-cli-integration-tests/src/test/java/org/springframework/boot/cli/it/infrastructure/CliInvocation.java b/spring-boot-cli-integration-tests/src/test/java/org/springframework/boot/cli/it/infrastructure/CliInvocation.java new file mode 100644 index 0000000000..c4580e0c6e --- /dev/null +++ b/spring-boot-cli-integration-tests/src/test/java/org/springframework/boot/cli/it/infrastructure/CliInvocation.java @@ -0,0 +1,84 @@ +package org.springframework.boot.cli.it.infrastructure; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Andy Wilkinson + */ +public final class CliInvocation { + + private final StringBuffer errorOutput = new StringBuffer(); + + private final StringBuffer standardOutput = new StringBuffer(); + + private final Process process; + + CliInvocation(Process process) { + this.process = process; + + new Thread(new StreamReadingRunnable(this.process.getErrorStream(), + this.errorOutput)).start(); + new Thread(new StreamReadingRunnable(this.process.getInputStream(), + this.standardOutput)).start(); + } + + public String getErrorOutput() { + return this.errorOutput.toString(); + } + + public String getStandardOutput() { + return this.standardOutput.toString(); + } + + public List getStandardOutputLines() { + BufferedReader reader = new BufferedReader(new StringReader( + this.standardOutput.toString())); + String line; + List lines = new ArrayList(); + try { + while ((line = reader.readLine()) != null) { + lines.add(line); + } + } + catch (IOException e) { + throw new RuntimeException("Failed to read standard output"); + } + return lines; + } + + public int await() throws InterruptedException { + return this.process.waitFor(); + } + + private final class StreamReadingRunnable implements Runnable { + + private final InputStream stream; + + private final StringBuffer output; + + private final byte[] buffer = new byte[4096]; + + private StreamReadingRunnable(InputStream stream, StringBuffer buffer) { + this.stream = stream; + this.output = buffer; + } + + public void run() { + int read; + try { + while ((read = this.stream.read(this.buffer)) > 0) { + this.output.append(new String(this.buffer, 0, read)); + } + } + catch (IOException e) { + // Allow thread to die + } + } + } + +}