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); + } +}