package com.bc.process.util;
import junit.framework.TestCase;
import java.io.OutputStream;
import java.io.InputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.LinkedList;
public class ProcessMonitorTest extends TestCase {
private PipedOutputStream outHandle;
private PipedOutputStream errHandle;
private PipedInputStream inHandle;
private DummyProcess dummyProcess;
private DummyStreamObserver stdoutObserver;
private DummyStreamObserver stderrObserver;
private ProcessMonitor monitor;
// there seems to be a bug in ProcessMonitor.readCharacterData:
// Events are fired when '\n' is received. They should rather be fired when no more input
// is available (via InputStream.available) to enable password prompts to be answered by
// sending passwords to the process.
// Also it seems, that a linebuffer is passed to fireCharacterData over and over again.
// (Though the same linebuffer is sent over and over to fireCharacterData, the method - as
// side effect - sets the size of linebuffer (StringBuffer) to 0. This way the result is
// ok, but the code looks strange.
// todo: eliminate side effect in fireCharacterData.
static class DummyProcess extends Process {
private final OutputStream outputStream;
private final InputStream inputStream;
private final InputStream errorStream;
private final int exitValue;
public DummyProcess(int exitValue, InputStream inputStream, InputStream errorStream, OutputStream outputStream) {
this.exitValue = exitValue;
this.inputStream = inputStream;
this.errorStream = errorStream;
this.outputStream = outputStream;
}
public OutputStream getOutputStream() {
return outputStream;
}
public InputStream getInputStream() {
return inputStream;
}
public InputStream getErrorStream() {
return errorStream;
}
public int waitFor() throws InterruptedException {
return 0;
}
public int exitValue() {
return exitValue;
}
public void destroy() {
}
}
static class DummyStreamObserver implements ProcessStreamObserver {
public List strings = new LinkedList();
public void processWroteToStream(String characterData) {
strings.add(characterData);
}
}
/**
* Due to the needs of the Process interface, setup is a bit more complicated...
* Process's streams are piped in order to be triggered from tests. Data written
* to outHandle will appear as if sent by the process to stdout, data written to
* errHandle will appear as if sent by the process to stderr.
* @throws IOException
*/
public void setUp() throws IOException {
PipedInputStream out = new PipedInputStream();
PipedInputStream err = new PipedInputStream();
PipedOutputStream in = new PipedOutputStream();
// handles used in tests to simulate process out/input
outHandle = new PipedOutputStream(out);
errHandle = new PipedOutputStream(err);
inHandle = new PipedInputStream();
// create monitor and observers.
stdoutObserver = new DummyStreamObserver();
stderrObserver = new DummyStreamObserver();
dummyProcess = new DummyProcess(0, out, err, in);
monitor = new ProcessMonitor(dummyProcess);
monitor.setStdoutObserver(stdoutObserver);
monitor.setStderrObserver(stderrObserver);
monitor.start();
}
protected void tearDown() throws Exception {
inHandle.close();
outHandle.close();
errHandle.close();
}
public void testObserverIsTriggeredOnAvailableData() throws IOException, InterruptedException {
outHandle.write("part1".getBytes());
outHandle.flush();
Thread.sleep(25);
outHandle.write("part2".getBytes());
outHandle.flush();
Thread.sleep(25);
outHandle.write("part3".getBytes());
outHandle.flush();
Thread.sleep(25);
outHandle.write("part4".getBytes());
outHandle.flush();
Thread.sleep(25);
assertEquals(4, stdoutObserver.strings.size());
assertEquals("part1", stdoutObserver.strings.get(0));
assertEquals("part2", stdoutObserver.strings.get(1));
assertEquals("part3", stdoutObserver.strings.get(2));
assertEquals("part4", stdoutObserver.strings.get(3));
}
public void testObserverIsTriggeredOnLineBreak() throws IOException, InterruptedException {
outHandle.write("line1\nline2\nline3\nline4".getBytes());
outHandle.flush();
Thread.sleep(25);
assertEquals(4, stdoutObserver.strings.size());
assertEquals("line1\n", stdoutObserver.strings.get(0));
assertEquals("line2\n", stdoutObserver.strings.get(1));
assertEquals("line3\n", stdoutObserver.strings.get(2));
assertEquals("line4", stdoutObserver.strings.get(3));
}
}