diff --git a/gclc-process/pom.xml b/gclc-process/pom.xml index e8fe890..6496d6f 100644 --- a/gclc-process/pom.xml +++ b/gclc-process/pom.xml @@ -49,7 +49,7 @@ net.bigeon gclc - 2.0.12 + 2.1.0 net.bigeon.test diff --git a/gclc-process/src/main/java/net/bigeon/gclc/process/io/ConnectingConsoleInput.java b/gclc-process/src/main/java/net/bigeon/gclc/process/io/ConnectingConsoleInput.java index afc6fb5..f846547 100644 --- a/gclc-process/src/main/java/net/bigeon/gclc/process/io/ConnectingConsoleInput.java +++ b/gclc-process/src/main/java/net/bigeon/gclc/process/io/ConnectingConsoleInput.java @@ -68,6 +68,7 @@ package net.bigeon.gclc.process.io; * #L% */ import java.io.IOException; +import java.io.InterruptedIOException; import java.util.function.Supplier; import net.bigeon.gclc.manager.ConsoleInput; @@ -82,25 +83,27 @@ public final class ConnectingConsoleInput implements ConsoleInput { private static final ConstantString EMPTY_STRING = new ConstantString(""); /** If the input is closed. */ - private boolean close = false; + private boolean close = false; /** The prompt string. */ private Supplier prompt = EMPTY_STRING; /** If the input is currently in prompting state. *

* To change it you should be in a promptLock. */ - private boolean prompting = false; + private boolean prompting = false; /** The synchronization lock for the prompting status. */ - private final Object promptLock = new Object(); + private final Object promptLock = new Object(); /** The synchronization lock for the connection status. */ - private final Object connectionLock = new Object(); + private final Object connectionLock = new Object(); /** The connected console input. *

* To use it, you should be in a promptLock and connectionLock. */ - private ConsoleInput connected = null; + private ConsoleInput connected = null; /** The connection state. *

* To read or modify it, you should be in a connectionLock synchronize block. */ - private boolean disconnection = false; + private boolean disconnection = false; + + private boolean interrupting = false; /* (non-Javadoc) * @see fr.bigeon.gclc.manager.ConsoleInput#close() */ @@ -149,6 +152,9 @@ public final class ConnectingConsoleInput implements ConsoleInput { public void interruptPrompt() { synchronized (connectionLock) { synchronized (promptLock) { + if (prompting) { + interrupting = true; + } connectionLock.notifyAll(); if (connected != null) { connected.interruptPrompt(); @@ -201,14 +207,21 @@ public final class ConnectingConsoleInput implements ConsoleInput { actualConnected = connected; } if (connect) { - final String res = actualConnected.prompt(message); - synchronized (promptLock) { + try { + final String res = actualConnected.prompt(message); + synchronized (promptLock) { + if (prompting) { + return res; + } + } + } catch (final InterruptedIOException e) { + // The inner console was interrupted. This can mean we are + // disconnecting or actually interrupted. if (disconnection) { disconnection = false; - } else if (prompting) { - return res; } else { - // prompt interrupted, lose the result. + interrupting = false; + throw e; } } } @@ -241,14 +254,21 @@ public final class ConnectingConsoleInput implements ConsoleInput { } if (connect) { synchronized (promptLock) { - final String res = actualConnected.prompt(message, - end - System.currentTimeMillis()); - if (disconnection) { - disconnection = false; - } else if (prompting) { - return res; - } else { - // prompt interrupted, lose the result. + try { + final String res = actualConnected.prompt(message, + end - System.currentTimeMillis()); + if (prompting) { + return res; + } + } catch (final InterruptedIOException e) { + // The inner console was interrupted. This can mean we are + // disconnecting or actually interrupted. + if (disconnection) { + disconnection = false; + } else { + throw e; + } + } } } @@ -257,7 +277,7 @@ public final class ConnectingConsoleInput implements ConsoleInput { } - private void getConnection(final long timeout) { + private void getConnection(final long timeout) throws InterruptedIOException { boolean connect; synchronized (connectionLock) { connect = connected != null; @@ -268,6 +288,10 @@ public final class ConnectingConsoleInput implements ConsoleInput { Thread.currentThread().interrupt(); } } + if (interrupting) { + interrupting = false; + throw new InterruptedIOException("Prompt ws interrupted"); + } } } diff --git a/gclc-process/src/test/java/net/bigeon/gclc/process/ForkTaskTest.java b/gclc-process/src/test/java/net/bigeon/gclc/process/ForkTaskTest.java index 551571d..f897b47 100644 --- a/gclc-process/src/test/java/net/bigeon/gclc/process/ForkTaskTest.java +++ b/gclc-process/src/test/java/net/bigeon/gclc/process/ForkTaskTest.java @@ -12,14 +12,16 @@ import org.junit.Test; import net.bigeon.gclc.exception.CommandRunException; import net.bigeon.gclc.exception.CommandRunExceptionType; -import net.bigeon.gclc.utils.PipedConsoleInput; -import net.bigeon.gclc.utils.PipedConsoleOutput; +import net.bigeon.gclc.manager.PipedConsoleInput; +import net.bigeon.gclc.manager.PipedConsoleOutput; /** @author Emmanuel Bigeon */ public class ForkTaskTest { @Test public void testGenericForkTask() throws IOException { + + // FIXME This test fail to complete on Jenkins. final ForkTask task = new ForkTask(5) { @Override @@ -36,15 +38,11 @@ public class ForkTaskTest { throw new CommandRunException(CommandRunExceptionType.INTERACTION, "Unable to prompt user"); } - if ("ok".equals(msg)) { - out.println("Message"); - } else { - out.println("fail"); - } + out.println(msg); } }; - final Thread execThread = new Thread(task); + final Thread execThread = new Thread(task, "Task"); execThread.start(); try { execThread.join(100); @@ -55,11 +53,11 @@ public class ForkTaskTest { try (PipedConsoleOutput pco = new PipedConsoleOutput(); PipedConsoleInput pci = new PipedConsoleInput(null)) { - pci.type("ok"); while (!pco.available()) { + pci.type("ok"); task.join(pco, pci, 1000); } - assertEquals("Execution should work", "Message", pco.readNextLine()); + assertEquals("Positive execution", "ok", pco.readNextLine()); } assertFalse("Running state should be updated by task on its completion", task.isRunning()); diff --git a/gclc-process/src/test/java/net/bigeon/gclc/process/ProcessListTest.java b/gclc-process/src/test/java/net/bigeon/gclc/process/ProcessListTest.java index 7a3cd05..08b04d9 100644 --- a/gclc-process/src/test/java/net/bigeon/gclc/process/ProcessListTest.java +++ b/gclc-process/src/test/java/net/bigeon/gclc/process/ProcessListTest.java @@ -14,8 +14,8 @@ import org.junit.Test; import net.bigeon.gclc.exception.CommandRunException; import net.bigeon.gclc.exception.CommandRunExceptionType; +import net.bigeon.gclc.manager.PipedConsoleOutput; import net.bigeon.gclc.process.mocks.TaskMock; -import net.bigeon.gclc.utils.PipedConsoleOutput; /** @author Emmanuel Bigeon */ public class ProcessListTest { diff --git a/gclc-process/src/test/java/net/bigeon/gclc/process/io/ConnectingConsoleInputTest.java b/gclc-process/src/test/java/net/bigeon/gclc/process/io/ConnectingConsoleInputTest.java index 542085d..aaa2452 100644 --- a/gclc-process/src/test/java/net/bigeon/gclc/process/io/ConnectingConsoleInputTest.java +++ b/gclc-process/src/test/java/net/bigeon/gclc/process/io/ConnectingConsoleInputTest.java @@ -4,8 +4,10 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.io.IOException; +import java.io.InterruptedIOException; import java.io.PipedInputStream; import java.io.PipedOutputStream; import java.nio.charset.StandardCharsets; @@ -13,9 +15,9 @@ import java.util.concurrent.atomic.AtomicBoolean; import org.junit.Test; +import net.bigeon.gclc.manager.PipedConsoleInput; +import net.bigeon.gclc.manager.StreamConsoleInput; import net.bigeon.gclc.tools.ConstantString; -import net.bigeon.gclc.utils.PipedConsoleInput; -import net.bigeon.gclc.utils.StreamConsoleInput; import net.bigeon.test.junitmt.ATestRunnable; import net.bigeon.test.junitmt.FunctionalTestRunnable; import net.bigeon.test.junitmt.TestFunction; @@ -81,10 +83,26 @@ public class ConnectingConsoleInputTest { @Override public void apply() throws Exception { - assertNull("Interrupted should return null", in.prompt("m1", -1)); - assertNull("Interrupted should return null", in.prompt("m2", 5000)); - ended.set(true); - assertNull("Overtime should return null", in.prompt("m3", 200)); + try { + in.prompt("m1", -1); + fail("interruption of infinite waiting prompt should cause error"); + } catch (final InterruptedIOException e) { + // ok + } + try { + in.prompt("m2", 5000); + fail("interruption of finite waiting prompt should cause error"); + } catch (final InterruptedIOException e) { + // ok + } + synchronized (ended) { + ended.set(true); + try { + assertNull("Overtime should return null", in.prompt("m3", 200)); + } catch (final InterruptedIOException e) { + fail("Unexpected interruption error in overtime"); + } + } } }; final ATestRunnable runnable = new FunctionalTestRunnable(one); @@ -95,12 +113,16 @@ public class ConnectingConsoleInputTest { public void run() { while (!ended.get()) { try { - th.join(500); + th.join(100); } catch (final InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } - in.interruptPrompt(); + synchronized (ended) { + if (!ended.get()) { + in.interruptPrompt(); + } + } } } }); @@ -112,7 +134,7 @@ public class ConnectingConsoleInputTest { final PipedOutputStream os = new PipedOutputStream(); final PipedInputStream pis = new PipedInputStream(os); - in.connect(new StreamConsoleInput(System.out, pis, StandardCharsets.UTF_8)); + in.connect(new StreamConsoleInput(null, pis, StandardCharsets.UTF_8)); final ATestRunnable runnable2 = new FunctionalTestRunnable(one); final Thread th2 = new Thread(runnable2); final Thread inter2 = new Thread(new Runnable() { @@ -121,12 +143,16 @@ public class ConnectingConsoleInputTest { public void run() { while (!ended.get()) { try { - th2.join(500); + th2.join(100); } catch (final InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } - in.interruptPrompt(); + synchronized (ended) { + if (!ended.get()) { + in.interruptPrompt(); + } + } } } }); diff --git a/gclc-process/src/test/java/net/bigeon/gclc/process/io/ConnectingConsoleOutputTest.java b/gclc-process/src/test/java/net/bigeon/gclc/process/io/ConnectingConsoleOutputTest.java index e919b0c..209506b 100644 --- a/gclc-process/src/test/java/net/bigeon/gclc/process/io/ConnectingConsoleOutputTest.java +++ b/gclc-process/src/test/java/net/bigeon/gclc/process/io/ConnectingConsoleOutputTest.java @@ -8,7 +8,7 @@ import java.io.IOException; import org.junit.Test; -import net.bigeon.gclc.utils.PipedConsoleOutput; +import net.bigeon.gclc.manager.PipedConsoleOutput; public class ConnectingConsoleOutputTest {