package edu.mayo.bior.cli.func;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.BeforeClass;
import edu.mayo.bior.util.StreamConnector;
public abstract class BaseFunctionalTest {
private static final String ENV_VAR_BIOR_LITE_HOME = "BIOR_LITE_HOME";
// stores the $BIOR_LITE_HOME value
protected static String sHomePath;
// UNIX environment variables
private static Map<String, String> sEnvVars = new HashMap<String, String>();
@BeforeClass
public static void setup() throws FileNotFoundException {
// pass along current environment
sEnvVars.putAll(System.getenv());
sHomePath = getHomeFolder().getAbsolutePath();
// setup UNIX environment variables required by bior lite
sEnvVars.put(ENV_VAR_BIOR_LITE_HOME, sHomePath);
}
/**
* Gets array of environment variables in the format "var1=value1" that will
* be used in the script to be executed.
*
* @return
*/
private String[] getEnvironmentVariables() {
List<String> list = new ArrayList<String>();
for (String varName: sEnvVars.keySet()) {
String varValue = sEnvVars.get(varName);
list.add(varName+"="+varValue);
}
return (String[]) list.toArray(new String[0]);
}
/**
* Locates the unzipped distribution folder under target built by maven.
*
* @return
* @throws FileNotFoundException thrown if the folder is not found
*/
private static File getHomeFolder() throws FileNotFoundException {
File homeFolder = null;
// figure out $BIOR_LITE_HOME value
String envValue = System.getenv(ENV_VAR_BIOR_LITE_HOME);
if ((envValue != null) && (envValue.trim().length() > 0)) {
// use UNIX environment variable if available
homeFolder = new File(envValue);
System.out.println(
"WARNING: found $" + ENV_VAR_BIOR_LITE_HOME + " in your environment. "+
"Running functional test against: " + homeFolder.getAbsolutePath());
} else {
// auto-detect inside maven target folder
File targetFolder = new File("target");
for (File f: targetFolder.listFiles()) {
if (f.isDirectory() && (f.getName().startsWith("bior_pipeline"))) {
homeFolder = f;
}
}
}
if (homeFolder == null) {
String msg = "Error! Unable to locate target/bior_pipeline-<version> distribution folder\n"
+ "Try running:\n"
+ " cd bior_pipeline\n"
+ " mvn clean package\n"
+ " source setupEnv.sh";
System.err.println(msg);
throw new FileNotFoundException(msg);
}
return homeFolder;
}
/**
* Executes the specified shell script.
*
* @param scriptName
* Name of the shell script
* @param stdin
* Content typed to STDIN. Set to NULL if not used
* @param scriptArgs
* Zero or more arguments sent to the script
* @return CommandOutput bean.
* @throws IOException
* @throws InterruptedException
*/
protected CommandOutput executeScript(String scriptName, String stdin,
String... scriptArgs) throws IOException, InterruptedException {
List<String> cmdList = new ArrayList<String>();
// add command that will be invoked
cmdList.add(sHomePath + "/bin/" + scriptName);
// add command args
for (String arg : scriptArgs) {
cmdList.add(arg);
}
String[] cmdArray = cmdList.toArray(new String[0]);
Process p = Runtime.getRuntime().exec(cmdArray, getEnvironmentVariables());
// connect STDERR from script process and store in local memory
// STDERR [script process] ---> local byte array
ByteArrayOutputStream stderrData = new ByteArrayOutputStream();
StreamConnector stderrConnector = new StreamConnector(p.getErrorStream(), stderrData, 1024);
new Thread(stderrConnector).start();
// connect STDOUT from script process and store in local memory
// STDOUT [script process] ---> local byte array
ByteArrayOutputStream stdoutData = new ByteArrayOutputStream();
StreamConnector stdoutConnector = new StreamConnector(p.getInputStream(), stdoutData, 1024);
new Thread(stdoutConnector).start();
// feed STDIN into process if necessary
if (stdin != null) {
p.getOutputStream().write(stdin.getBytes());
p.getOutputStream().close();
}
// block until process ends
int exitCode = p.waitFor();
CommandOutput out = new CommandOutput();
out.stderr = stderrData.toString("UTF-8");
out.stdout = stdoutData.toString("UTF-8");
out.exit = exitCode;
return out;
}
/**
* Executes the specified shell script that may contain pipes.
* Ex: "cat myfile.vcf | bior_vcf_to_json | bior_drill -k -p CHROM"
*
* @param cmdWithPipes Command to run (may contain pipes)
* @return CommandOutput Output from command - contains ALL stderr lines, but only stdout from last pipe operation.
* @throws IOException
* @throws InterruptedException
*/
protected CommandOutput executeScriptWithPipes(String cmdWithPipes) throws IOException, InterruptedException {
// Split the command into the pipe-able pieces (ex: "cat junk.vcf | bior_vcf_to_json"
// will be broken up into two commands and run as two separate commands)
// NOTE: leading and trailing spaces around the pipe char will be removed
String[] cmds = cmdWithPipes.split(" +\\| +");
// Create the CommandOutput and set it's stderr to "" so we don't have a "null" in there
CommandOutput out = new CommandOutput();
out.stderr = "";
String stdin = null;
for(String cmd : cmds) {
// If the command is a bior command (begins with "bior_"), the prepend the path to the cmd
if(cmd.startsWith("bior_"))
cmd = sHomePath + "/bin/" + cmd;
Process p = Runtime.getRuntime().exec(cmd, getEnvironmentVariables());
// connect STDERR from script process and store in local memory
// STDERR [script process] ---> local byte array
ByteArrayOutputStream stderrData = new ByteArrayOutputStream();
StreamConnector stderrConnector = new StreamConnector(p.getErrorStream(), stderrData, 1024);
Thread stderrThread = new Thread(stderrConnector);
stderrThread.start();
// connect STDOUT from script process and store in local memory
// STDOUT [script process] ---> local byte array
ByteArrayOutputStream stdoutData = new ByteArrayOutputStream();
StreamConnector stdoutConnector = new StreamConnector(p.getInputStream(), stdoutData, 1024);
Thread stdoutThread = new Thread(stdoutConnector);
stdoutThread.start();
// feed STDIN into process if necessary
if (stdin != null) {
p.getOutputStream().write(stdin.getBytes());
p.getOutputStream().close();
}
// block until process ends
int exitCode = p.waitFor();
// wait for threads to finish
stdoutThread.join();
stderrThread.join();
String stderr = stderrData.toString("UTF-8");
String stdout = stdoutData.toString("UTF-8");
out.stderr += stderr;
out.stdout = stdout;
out.exit = exitCode;
if(exitCode != 0) {
return out;
}
// Set the stdin for the next pipe to the output from the previous one
stdin = out.stdout;
}
return out;
}
/**
* Loads contents of a file into a String object.
*
* @param f
* @return
* @throws IOException
*/
protected String loadFile(File f) throws IOException {
StringWriter sWtr = new StringWriter();
PrintWriter pWtr = new PrintWriter(sWtr);
BufferedReader br = new BufferedReader(new FileReader(f));
String line = br.readLine();
while (line != null) {
pWtr.println(line);
line = br.readLine();
}
pWtr.close();
return sWtr.toString();
}
/**
* Extracts any rows that begin with a '#' character
*
* @param s
* @return
* @throws IOException
*/
protected String getHeader(String s) throws IOException {
StringReader sRdr = new StringReader(s);
BufferedReader bRdr = new BufferedReader(sRdr);
StringWriter sWtr = new StringWriter();
PrintWriter pWtr = new PrintWriter(sWtr);
String line = bRdr.readLine();
while (line != null) {
if (line.startsWith("#")) {
pWtr.println(line);
}
line = bRdr.readLine();
}
pWtr.close();
return sWtr.toString();
}
}