Attempt to fix hanging unit tests

This commit is contained in:
BoykoAlex
2016-10-14 12:38:54 -04:00
parent b4594fc313
commit 62d3d82b48
3 changed files with 262 additions and 2 deletions

View File

@@ -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");
}
}

View File

@@ -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());
}
}

View File

@@ -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;
}
}