diff --git a/gclc.system/pom.xml b/gclc.system/pom.xml
index 21cb5da..21dee34 100644
--- a/gclc.system/pom.xml
+++ b/gclc.system/pom.xml
@@ -50,6 +50,12 @@
gclc
2.0.11
+
+ org.mockito
+ mockito-core
+ 2.23.0
+ test
+
diff --git a/gclc.system/src/main/java/net/bigeon/gclc/system/ForwardingRunnable.java b/gclc.system/src/main/java/net/bigeon/gclc/system/ForwardingRunnable.java
index 775c371..595047d 100644
--- a/gclc.system/src/main/java/net/bigeon/gclc/system/ForwardingRunnable.java
+++ b/gclc.system/src/main/java/net/bigeon/gclc/system/ForwardingRunnable.java
@@ -63,6 +63,7 @@ public final class ForwardingRunnable implements Runnable {
private final ConsoleOutput out;
/** The input stream. */
private final InputStream is;
+ private Exception error;
/** Create the runnable.
*
@@ -78,21 +79,22 @@ public final class ForwardingRunnable implements Runnable {
@Override
public void run() {
try {
- readToEnd(out, is);
+ readToEnd();
is.close();
} catch (final CommandRunException e) {
LOGGER.log(Level.WARNING, "Manager was closed in the meantime...", e); //$NON-NLS-1$
+ setError(e);
} catch (final IOException e) {
LOGGER.log(Level.WARNING, "Input stream was closed...", e); //$NON-NLS-1$
+ setError(e);
}
}
/** Read the input until its end.
*
- * @param is the input stream
* @throws CommandRunException if the manager was closed while writing the
* stream */
- private static void readToEnd(final ConsoleOutput out, final InputStream is)
+ private void readToEnd()
throws CommandRunException {
int c;
try {
@@ -102,6 +104,7 @@ public final class ForwardingRunnable implements Runnable {
}
} catch (final IOException e) {
LOGGER.log(Level.INFO, "input stream reading failed", e); //$NON-NLS-1$
+ setError(e);
}
}
@@ -141,4 +144,14 @@ public final class ForwardingRunnable implements Runnable {
public static Thread connect(final InputStream stream, final ConsoleOutput output) {
return connect(stream, output, "Forwarding");
}
+
+ /** @return the error */
+ public synchronized Exception getError() {
+ return error;
+ }
+
+ /** @param error the error to set */
+ private synchronized void setError(final Exception error) {
+ this.error = error;
+ }
}
diff --git a/gclc.system/src/test/java/net/bigeon/gclc/system/ForwardingRunnableTest.java b/gclc.system/src/test/java/net/bigeon/gclc/system/ForwardingRunnableTest.java
new file mode 100644
index 0000000..ea2c679
--- /dev/null
+++ b/gclc.system/src/test/java/net/bigeon/gclc/system/ForwardingRunnableTest.java
@@ -0,0 +1,58 @@
+/**
+ *
+ */
+package net.bigeon.gclc.system;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import net.bigeon.gclc.exception.CommandRunException;
+import net.bigeon.gclc.utils.SinkOutput;
+import net.bigeon.gclc.utils.StreamConsoleOutput;
+
+/** @author Emmanuel Bigeon */
+public class ForwardingRunnableTest {
+
+ /** Test method for {@link net.bigeon.gclc.system.ForwardingRunnable#run()}. */
+ @Test
+ public void testClosedOutput() {
+ final StreamConsoleOutput out = new StreamConsoleOutput();
+ out.close();
+ final InputStream is = new ByteArrayInputStream(new byte[] { 1, 2, 3 });
+ final ForwardingRunnable runnable = new ForwardingRunnable(out, is);
+ // Runnable should close immediatly.
+ runnable.run();
+
+ assertTrue("Error should be a CommandRunException",
+ runnable.getError() instanceof CommandRunException);
+ }
+
+ @Test
+ public void testIOInInput() throws IOException {
+ final InputStream is = Mockito.mock(InputStream.class);
+ Mockito.when(is.read()).thenThrow(new IOException());
+ final ForwardingRunnable runnable = new ForwardingRunnable(SinkOutput.INSTANCE,
+ is);
+ // Runnable should close immediatly.
+ runnable.run();
+ assertTrue("Error should be an IO", runnable.getError() instanceof IOException);
+ }
+
+ @Test
+ public void testIOInClose() throws IOException {
+ final InputStream is = Mockito.mock(InputStream.class);
+ Mockito.when(is.read()).thenReturn(-1);
+ Mockito.doThrow(new IOException()).when(is).close();
+ final ForwardingRunnable runnable = new ForwardingRunnable(SinkOutput.INSTANCE,
+ is);
+ // Runnable should close immediatly.
+ runnable.run();
+ assertTrue("Error should be an IO", runnable.getError() instanceof IOException);
+ }
+}