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); } */ }