package org.marketcetera.util.exec;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.PrintStream;
import java.util.Locale;
import org.apache.commons.lang.ArrayUtils;
import org.apache.log4j.Level;
import org.junit.Before;
import org.junit.Test;
import org.marketcetera.util.except.I18NException;
import org.marketcetera.util.except.I18NInterruptedException;
import org.marketcetera.util.file.CloseableRegistry;
import org.marketcetera.util.log.ActiveLocale;
import org.marketcetera.util.log.I18NBoundMessage1P;
import org.marketcetera.util.misc.OperatingSystem;
import org.marketcetera.util.test.TestCaseBase;
import static org.junit.Assert.*;
import static org.marketcetera.util.test.RegExAssert.*;
/**
* @author tlerios@marketcetera.com
* @since 0.5.0
* @version $Id: ExecTest.java 16643 2013-07-26 18:42:51Z colin $
*/
/* $License$ */
public class ExecTest
extends TestCaseBase
{
private static final String TEST_CATEGORY=
InputThread.class.getName();
private static final String TEST_OUT=
"out";
private static final String TEST_ERR=
"err";
private static final int TEST_EXIT_CODE=
3;
private static final byte[] TEST_OUTPUT=
(TEST_OUT+TEST_ERR).getBytes();
private static final String TEST_NONEXISTENT_FILE=
DIR_ROOT+File.separator+"nonexistent";
private static final int SLEEP_DURATION=
1000;
// private static final String TEST_LOCATION=
// TEST_CATEGORY;
/*
* Independent process helpers.
*/
// Prints the test text to the standard output and error streams,
// and exits with the test exit code.
public static final class CommandStreams
{
public static void main
(String args[])
{
System.out.print(TEST_OUT);
System.err.print(TEST_ERR);
System.exit(TEST_EXIT_CODE);
}
}
// Prints the current user directory to the standard output stream.
public static final class CommandCwd
{
public static void main
(String args[])
{
System.out.print(System.getProperty("user.dir"));
}
}
// Sleeps for a long-ish duration.
public static final class CommandSleep
{
public static void main
(String args[])
throws Exception
{
for (int i=0;i<5;i++) {
// EXTREME TEST 1: some output is required.
System.err.println(i);
Thread.sleep(SLEEP_DURATION);
}
}
}
/*
* Java process execution in a child thread.
*/
private static final class ChildExec
extends Thread
{
private String mCommand;
private I18NException mException;
ChildExec
(String command)
{
mCommand=command;
}
I18NException getException()
{
return mException;
}
@Override
public void run() {
try {
ExecTest.run((File)null,Disposition.MEMORY,mCommand);
} catch (I18NException ex) {
mException=ex;
}
}
};
/*
* Process execution with the standard output and error streams
* redirected to byte arrays.
*/
private static final class Redirector
extends ExecResult
{
private byte[] mStdOut;
private byte[] mStdErr;
Redirector
(int exitCode,
byte[] stdOut,
byte[] stdErr,
byte[] memory)
{
super(exitCode,memory);
mStdOut=stdOut;
mStdErr=stdErr;
}
byte[] getStdOut()
{
return mStdOut;
}
byte[] getStdErr()
{
return mStdErr;
}
static Redirector get
(Disposition disposition)
throws Exception
{
PrintStream stdOutSave=System.out;
PrintStream stdErrSave=System.err;
ByteArrayOutputStream stdOutByteArray;
ByteArrayOutputStream stdErrByteArray;
ExecResult result;
CloseableRegistry r=new CloseableRegistry();
try {
stdOutByteArray=new ByteArrayOutputStream();
r.register(stdOutByteArray);
PrintStream stdOutNew=new PrintStream(stdOutByteArray);
r.register(stdOutNew);
stdErrByteArray=new ByteArrayOutputStream();
r.register(stdErrByteArray);
PrintStream stdErrNew=new PrintStream(stdErrByteArray);
r.register(stdErrNew);
System.setOut(stdOutNew);
System.setErr(stdErrNew);
result=ExecTest.run((File)null,disposition,"CommandStreams");
} finally {
System.setErr(stdErrSave);
System.setOut(stdOutSave);
r.close();
}
return new Redirector
(result.getExitCode(),stdOutByteArray.toByteArray(),
stdErrByteArray.toByteArray(),result.getOutput());
}
}
/*
* JVM execution in a separate process with stream redirection.
*/
private static String getJava()
{
if (OperatingSystem.LOCAL.isUnix()) {
return "java";
}
if (OperatingSystem.LOCAL.isWin32()) {
return "java.exe";
}
throw new AssertionError("Unknown platform");
}
private static ExecResult run
(File directory,
Disposition disposition,
String subclass)
throws I18NException
{
return Exec.run
(directory,disposition,getJava(),"-classpath",
new File(DIR_TEST_CLASSES).getAbsolutePath() + File.pathSeparator + System.getProperty("java.class.path"),
ExecTest.class.getName()+"$"+subclass);
}
private static ExecResult run
(String directory,
Disposition disposition,
String subclass)
throws I18NException
{
return Exec.run
(directory,disposition,getJava(),"-classpath",
new File(DIR_TEST_CLASSES).getAbsolutePath() + File.pathSeparator + System.getProperty("java.class.path"),
ExecTest.class.getName()+"$"+subclass);
}
@Before
public void setupExecTest()
{
ActiveLocale.setProcessLocale(Locale.ROOT);
setLevel(TEST_CATEGORY,Level.TRACE);
}
@Test
public void stdOutDisposition()
throws Exception
{
Redirector result=Redirector.get(Disposition.STDOUT);
assertEquals(TEST_EXIT_CODE,result.getExitCode());
assertArrayEquals(TEST_OUTPUT,result.getStdOut());
assertArrayEquals(ArrayUtils.EMPTY_BYTE_ARRAY,result.getStdErr());
assertNull(result.getOutput());
}
@Test
public void stdErrDisposition()
throws Exception
{
Redirector result=Redirector.get(Disposition.STDERR);
assertEquals(TEST_EXIT_CODE,result.getExitCode());
assertArrayEquals(ArrayUtils.EMPTY_BYTE_ARRAY,result.getStdOut());
assertArrayEquals(TEST_OUTPUT,result.getStdErr());
assertNull(result.getOutput());
}
@Test
public void memoryDisposition()
throws Exception
{
Redirector result=Redirector.get(Disposition.MEMORY);
assertEquals(TEST_EXIT_CODE,result.getExitCode());
assertArrayEquals(ArrayUtils.EMPTY_BYTE_ARRAY,result.getStdOut());
assertArrayEquals(ArrayUtils.EMPTY_BYTE_ARRAY,result.getStdErr());
assertArrayEquals(TEST_OUTPUT,result.getOutput());
}
@Test
public void defaultWorkingDirFile()
throws Exception
{
ExecResult result=run((File)null,Disposition.MEMORY,"CommandCwd");
assertMatches(".*\\"+File.separator+"util",
new String(result.getOutput()));
assertEquals(0,result.getExitCode());
}
@Test
public void defaultWorkingDirString()
throws Exception
{
ExecResult result=run((String)null,Disposition.MEMORY,"CommandCwd");
assertMatches(".*\\"+File.separator+"util",
new String(result.getOutput()));
assertEquals(0,result.getExitCode());
}
@Test
public void customWorkingDir()
throws Exception
{
ExecResult result=run(DIR_ROOT,Disposition.MEMORY,"CommandCwd");
assertEquals
((new File(DIR_ROOT)).getAbsolutePath(),
new String(result.getOutput()));
assertEquals(0,result.getExitCode());
}
@Test
public void nonexistentCommand()
{
try {
Exec.run((File)null,Disposition.MEMORY,TEST_NONEXISTENT_FILE);
fail();
} catch (I18NException ex) {
assertFalse(ex instanceof I18NInterruptedException);
assertEquals
(ex.getDetail(),
new I18NBoundMessage1P(Messages.CANNOT_EXECUTE,
TEST_NONEXISTENT_FILE),
ex.getI18NBoundMessage());
}
}
@Test
public void nonexistentWorkingDir()
{
try {
run(TEST_NONEXISTENT_FILE,Disposition.MEMORY,DIR_ROOT);
fail();
} catch (I18NException ex) {
assertFalse(ex instanceof I18NInterruptedException);
assertEquals
(ex.getDetail(),
new I18NBoundMessage1P(Messages.CANNOT_EXECUTE,getJava()),
ex.getI18NBoundMessage());
}
}
@Test
public void unexpectedTerminationAndProcessKilled()
throws Exception
{
ChildExec child=new ChildExec("CommandSleep");
child.start();
Thread.sleep(SLEEP_DURATION);
child.interrupt();
Thread.sleep(SLEEP_DURATION);
I18NException ex=child.getException();
assertTrue(ex instanceof I18NInterruptedException);
assertEquals
(ex.getDetail(),
new I18NBoundMessage1P(Messages.UNEXPECTED_TERMINATION,getJava()),
ex.getI18NBoundMessage());
}
/*
* EXTREME TEST 1: run alone (no other tests in the same file,
* and no other units test) after uncommenting sections in main
* class.
@Test
public void exception()
throws Exception
{
run((File)null,Disposition.MEMORY,"CommandSleep");
assertSingleEvent
(Level.ERROR,TEST_CATEGORY,
"Cannot copy output of command '"+getJava()+"'",TEST_LOCATION);
}
*/
}