Attempt to fix hanging unit tests
This commit is contained in:
@@ -21,6 +21,8 @@ import java.nio.file.Paths;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.springframework.ide.vscode.boot.properties.util.FuzzyMap;
|
||||
import org.springframework.ide.vscode.util.ExternalCommand;
|
||||
import org.springframework.ide.vscode.util.ExternalProcess;
|
||||
|
||||
/**
|
||||
* Sanity test the boot properties index
|
||||
@@ -39,8 +41,8 @@ public class PropertiesIndexTest {
|
||||
Path testProjectPath = Paths.get(PropertiesIndexTest.class.getResource("/demo-1").toURI());
|
||||
if (!Files.exists(testProjectPath.resolve("classpath.txt"))) {
|
||||
testProjectPath.resolve("mvnw").toFile().setExecutable(true);
|
||||
int result = Runtime.getRuntime().exec("./mvnw clean package", null, testProjectPath.toFile()).waitFor();
|
||||
if (result != 0) {
|
||||
ExternalProcess process = new ExternalProcess(testProjectPath.toFile(), new ExternalCommand("./mvnw", "clean", "package"), true);
|
||||
if (process.getExitValue() != 0) {
|
||||
throw new RuntimeException("Failed to build test project");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2012, 2016 Pivotal Software, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal Software, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Encapsulates information about an 'external' command that can be run through the OS.
|
||||
* <p>
|
||||
* This is a simplistic implementation. A more sophisticate implementation should allow for
|
||||
* different OS's (commands may return different information depending on the OS).
|
||||
*
|
||||
* @author Kris De Volder
|
||||
*/
|
||||
public class ExternalCommand {
|
||||
|
||||
private final String[] command;
|
||||
|
||||
public ExternalCommand(String... command) {
|
||||
ArrayList<String> pieces = new ArrayList<String>(command.length);
|
||||
for (String piece : command) {
|
||||
if (piece!=null) {
|
||||
pieces.add(piece);
|
||||
}
|
||||
}
|
||||
this.command = pieces.toArray(new String[pieces.size()]);
|
||||
}
|
||||
|
||||
public String[] getProgramAndArgs() {
|
||||
return command;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
boolean first = true;
|
||||
for (String piece : command) {
|
||||
if (!first) {
|
||||
buf.append(" ");
|
||||
}
|
||||
buf.append(piece);
|
||||
first = false;
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Just before executing the command with a ProcessBuilder instance, this method is called,
|
||||
* giving the command a chance to apply some extra configuration (e.g. set some environment
|
||||
* parameters).
|
||||
*/
|
||||
public void configure(ProcessBuilder processBuilder) {
|
||||
//Default implementation does nothing. Subclasses may override.
|
||||
}
|
||||
|
||||
/**
|
||||
* A convenient way to execute commands suitable for use in tests. The output and
|
||||
* result of commands are logged to the console and if the command returns non
|
||||
* 0 exit value an exception is thrown.
|
||||
*/
|
||||
public void exec(File workdir) throws IOException, InterruptedException {
|
||||
System.out.println(">>> exec: "+this);
|
||||
ExternalProcess process = new ExternalProcess(workdir, this);
|
||||
System.out.println(process);
|
||||
// org.junit.Assert.assertEquals(0, process.getExitValue());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2012, 2016 Pivotal Software, Inc.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Pivotal Software, Inc. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.util;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
|
||||
|
||||
/**
|
||||
* Convenient wrapper around a {@link Process}. Simplifies the synchronous execution of external
|
||||
* commands by handling reading from out and error streams and either buffering the result output
|
||||
* for later retrieval, or forwarding the to output to designated streams.
|
||||
*
|
||||
* @author Kris De Volder
|
||||
*/
|
||||
public class ExternalProcess {
|
||||
|
||||
/**
|
||||
* A thread that keeps reading input from a Stream until the end is reached
|
||||
* or there's some error reading the Stream.
|
||||
*/
|
||||
public static class StreamGobler extends Thread {
|
||||
|
||||
private final OutputStream echo;
|
||||
private InputStream toRead; //Stream to read. This is nulled after all input has been consumed.
|
||||
|
||||
/**
|
||||
* Creates a StreamGobler that reads input from an input stream
|
||||
* and buffers up all input it has read for later retrieval via
|
||||
* the getOut() method.
|
||||
*/
|
||||
public StreamGobler(InputStream toRead) {
|
||||
this(toRead, new ByteArrayOutputStream());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a StreamGobler that reads input from an input stream
|
||||
* and writes it out to an outputstream.
|
||||
*/
|
||||
public StreamGobler(InputStream toRead, OutputStream forwardTo) {
|
||||
this.toRead = toRead;
|
||||
this.echo = forwardTo;
|
||||
start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
byte[] buf = new byte[256];
|
||||
while (toRead!=null) {
|
||||
try {
|
||||
int i = toRead.read(buf);
|
||||
if (i==-1) {
|
||||
//EOF
|
||||
toRead = null; //Done!
|
||||
} else {
|
||||
append(buf, i);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
toRead = null;
|
||||
ByteArrayOutputStream errMsg = new ByteArrayOutputStream();
|
||||
e.printStackTrace(new PrintStream(errMsg));
|
||||
append(errMsg.toByteArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void append(byte[] buf) {
|
||||
append(buf, buf.length);
|
||||
}
|
||||
|
||||
private void append(byte[] buf, int len) {
|
||||
if (echo!=null) {
|
||||
try {
|
||||
echo.write(buf, 0, len);
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getContents() throws InterruptedException {
|
||||
try {
|
||||
this.join();
|
||||
if (echo instanceof ByteArrayOutputStream) {
|
||||
return ((ByteArrayOutputStream)echo).toString();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} finally {
|
||||
toRead = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Process process;
|
||||
private StreamGobler err; // Standard error is to be read from here
|
||||
private StreamGobler out; // Standard out is to be read from here
|
||||
private int exitValue = -9999;
|
||||
private ExternalCommand cmd;
|
||||
|
||||
/**
|
||||
* Creates an external process and waits for it to terminate. The output and error streams
|
||||
* will be read and forwarded to System.out and System.err
|
||||
*/
|
||||
public ExternalProcess(File workingDir, ExternalCommand cmd) throws IOException, InterruptedException {
|
||||
this(workingDir, cmd, false);
|
||||
}
|
||||
|
||||
private void init(File workingDir, ExternalCommand cmd,
|
||||
OutputStream outStream, OutputStream errStream) throws IOException,
|
||||
InterruptedException {
|
||||
this.cmd = cmd;
|
||||
ProcessBuilder processBuilder = new ProcessBuilder(cmd.getProgramAndArgs());
|
||||
processBuilder.directory(workingDir);
|
||||
cmd.configure(processBuilder);
|
||||
process = processBuilder.start();
|
||||
err = new StreamGobler(process.getErrorStream(), errStream);
|
||||
out = new StreamGobler(process.getInputStream(), outStream);
|
||||
exitValue = process.waitFor();
|
||||
}
|
||||
|
||||
public ExternalProcess(File workingDir, ExternalCommand cmd, boolean captureStreams) throws IOException, InterruptedException {
|
||||
if (captureStreams) {
|
||||
init(workingDir, cmd, new ByteArrayOutputStream(), new ByteArrayOutputStream());
|
||||
} else {
|
||||
init(workingDir, cmd, System.out, System.err);
|
||||
}
|
||||
}
|
||||
|
||||
public String getOut() throws InterruptedException {
|
||||
return out.getContents();
|
||||
}
|
||||
|
||||
public String getErr() throws InterruptedException {
|
||||
return err.getContents();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuffer result = new StringBuffer();
|
||||
try {
|
||||
process.exitValue();
|
||||
result.append(">>>> ExternalProcess: ");
|
||||
result.append(cmd+"\n");
|
||||
result.append("exitValue = "+exitValue+"\n");
|
||||
String strOut = getOut();
|
||||
if (strOut!=null) {
|
||||
result.append("\n------- System.out -------\n");
|
||||
result.append(strOut);
|
||||
}
|
||||
String strErr = getErr();
|
||||
if (strErr!=null) {
|
||||
result.append("\n------- System.err -------\n");
|
||||
result.append(getOut());
|
||||
}
|
||||
result.append("<<<< ExternalProcess");
|
||||
return result.toString();
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
return result.toString();
|
||||
} catch (IllegalThreadStateException e) {
|
||||
return "ExternalProcess(RUNNING, "+cmd+")";
|
||||
}
|
||||
}
|
||||
|
||||
public int getExitValue() {
|
||||
return exitValue;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user