/* * Copyright 2015 Red Hat, Inc. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * and Apache License v2.0 which accompanies this distribution. * * The Eclipse Public License is available at * http://www.eclipse.org/legal/epl-v10.html * * The Apache License v2.0 is available at * http://www.opensource.org/licenses/apache2.0.php * * You may elect to redistribute this code under either of these licenses. * * * Copyright (c) 2015 The original author or authors * ------------------------------------------------------ * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * and Apache License v2.0 which accompanies this distribution. * * The Eclipse Public License is available at * http://www.eclipse.org/legal/epl-v10.html * * The Apache License v2.0 is available at * http://www.opensource.org/licenses/apache2.0.php * * You may elect to redistribute this code under either of these licenses. * */ package io.vertx.ext.shell.command; import io.vertx.core.Context; import io.vertx.core.Handler; import io.vertx.core.Vertx; import io.vertx.ext.shell.session.Session; import io.vertx.ext.shell.system.*; import io.vertx.ext.shell.system.Process; import io.vertx.ext.shell.term.Pty; import io.vertx.ext.unit.Async; import io.vertx.ext.unit.TestContext; import io.vertx.ext.unit.junit.VertxUnitRunner; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; /** * @author <a href="mailto:julien@julienviet.com">Julien Viet</a> */ @RunWith(VertxUnitRunner.class) public class CommandProcessTest { Vertx vertx; @Before public void before() { vertx = Vertx.vertx(); } @After public void after(TestContext context) { vertx.close(context.asyncAssertSuccess()); } private Process createProcessInContext(Context context, Command command) throws Exception { CompletableFuture<Process> fut = new CompletableFuture<>(); context.runOnContext(v -> { Process process = command.createProcess().setSession(Session.create()).setTty(Pty.create().slave()); fut.complete(process); }); return fut.get(2000, TimeUnit.MILLISECONDS); } @Test public void testRunReadyProcess(TestContext context) throws Exception { AtomicInteger status = new AtomicInteger(); CommandBuilder builder = CommandBuilder.command("hello"); Async runningLatch = context.async(2); builder.processHandler(process -> { context.assertEquals(0, status.getAndIncrement()); runningLatch.countDown(); }); Command command = builder.build(vertx); Context ctx = vertx.getOrCreateContext(); Process process = createProcessInContext(ctx, command); process.run(v -> { context.assertEquals(ctx, Vertx.currentContext()); context.assertEquals(1, status.getAndIncrement()); runningLatch.countDown(); }); } @Test public void testRunRunningProcess(TestContext context) { CommandBuilder builder = CommandBuilder.command("hello"); Async runningLatch = context.async(); builder.processHandler(process -> runningLatch.complete()); Process process = builder.build(vertx).createProcess().setSession(Session.create()).setTty(Pty.create().slave()); process.run(); runningLatch.awaitSuccess(10000); try { process.run(); context.fail(); } catch (IllegalStateException ignore) { } } @Test public void testRunSuspendedProcess(TestContext context) { CommandBuilder builder = CommandBuilder.command("hello"); Async suspendedLatch = context.async(); Async runningLatch = context.async(); builder.processHandler(process -> { process.suspendHandler(v -> suspendedLatch.complete()); runningLatch.complete(); }); Process process = builder.build(vertx).createProcess().setSession(Session.create()).setTty(Pty.create().slave()); process.run(); runningLatch.awaitSuccess(10000); process.suspend(); suspendedLatch.awaitSuccess(10000); try { process.run(); context.fail(); } catch (IllegalStateException ignore) { } } public static Handler<ExecStatus> terminateHandler(Handler<Void> handler) { return status -> { if (status == ExecStatus.TERMINATED) { handler.handle(null); } }; } @Test public void testRunTerminatedProcess(TestContext context) { CommandBuilder builder = CommandBuilder.command("hello"); Async terminatedLatch = context.async(); builder.processHandler(CommandProcess::end); Process process = builder.build(vertx).createProcess().setSession(Session.create()).setTty(Pty.create().slave()); process.terminatedHandler(exitCode -> terminatedLatch.complete()); process.run(); terminatedLatch.awaitSuccess(10000); try { process.run(); context.fail(); } catch (IllegalStateException ignore) { } } @Test public void testSuspendReadyProcess(TestContext context) { CommandBuilder builder = CommandBuilder.command("hello"); builder.processHandler(process -> context.fail()); Process process = builder.build(vertx).createProcess().setSession(Session.create()).setTty(Pty.create().slave()); try { process.suspend(); context.fail(); } catch (Exception ignore) { } } @Test public void testSuspendRunningProcess(TestContext context) throws Exception { CommandBuilder builder = CommandBuilder.command("hello"); AtomicInteger status = new AtomicInteger(); Async suspendedLatch = context.async(2); Async runningLatch = context.async(); builder.processHandler(process -> { context.assertEquals(0, status.getAndIncrement()); process.suspendHandler(v -> suspendedLatch.complete()); runningLatch.complete(); }); Context ctx = vertx.getOrCreateContext(); Process process = createProcessInContext(ctx, builder.build(vertx)); process.run(); runningLatch.awaitSuccess(10000); process.suspend(v -> { context.assertEquals(ctx, Vertx.currentContext()); context.assertEquals(1, status.getAndIncrement()); suspendedLatch.countDown(); }); } @Test public void testSuspendSuspendedProcess(TestContext context) { CommandBuilder builder = CommandBuilder.command("hello"); Async suspendedLatch = context.async(); Async runningLatch = context.async(); builder.processHandler(process -> { process.suspendHandler(v -> suspendedLatch.complete()); runningLatch.complete(); }); Process process = builder.build(vertx).createProcess().setSession(Session.create()).setTty(Pty.create().slave()); process.run(); runningLatch.awaitSuccess(10000); process.suspend(); suspendedLatch.awaitSuccess(10000); try { process.suspend(); context.fail(); } catch (Exception ignore) { } } @Test public void testSuspendTerminatedProcess(TestContext context) { CommandBuilder builder = CommandBuilder.command("hello"); Async terminatedLatch = context.async(); builder.processHandler(CommandProcess::end); Process process = builder.build(vertx).createProcess().setSession(Session.create()).setTty(Pty.create().slave()); process.terminatedHandler(exitCode -> terminatedLatch.complete()); process.run(); terminatedLatch.awaitSuccess(10000); try { process.suspend(); context.fail(); } catch (IllegalStateException ignore) { } } @Test public void testResumeReadyProcess(TestContext context) { CommandBuilder builder = CommandBuilder.command("hello"); builder.processHandler(process -> context.fail()); Process process = builder.build(vertx).createProcess().setSession(Session.create()).setTty(Pty.create().slave()); try { process.resume(); context.fail(); } catch (Exception ignore) { } } @Test public void testResumeRunningProcess(TestContext context) { CommandBuilder builder = CommandBuilder.command("hello"); Async runningLatch = context.async(); builder.processHandler(process -> runningLatch.complete()); Process process = builder.build(vertx).createProcess().setSession(Session.create()).setTty(Pty.create().slave()); process.run(); runningLatch.awaitSuccess(10000); try { process.resume(); context.fail(); } catch (Exception ignore) { } } @Test public void testResumeSuspendedProcess(TestContext context) throws Exception { CommandBuilder builder = CommandBuilder.command("hello"); AtomicInteger status = new AtomicInteger(); Async runningLatch = context.async(); Async suspendedLatch = context.async(); Async resumedLatch = context.async(2); builder.processHandler(process -> { process.suspendHandler(v -> { suspendedLatch.complete(); }); process.resumeHandler(v -> { context.assertEquals(0, status.getAndIncrement()); resumedLatch.countDown(); }); runningLatch.complete(); }); Context ctx = vertx.getOrCreateContext(); Process process = createProcessInContext(ctx, builder.build(vertx)); process.run(); runningLatch.awaitSuccess(10000); process.suspend(); suspendedLatch.awaitSuccess(10000); process.resume(v -> { context.assertEquals(ctx, Vertx.currentContext()); context.assertEquals(1, status.getAndIncrement()); resumedLatch.countDown(); }); } @Test public void testResumeTerminatedProcess(TestContext context) { CommandBuilder builder = CommandBuilder.command("hello"); Async terminatedLatch = context.async(); builder.processHandler(CommandProcess::end); Process process = builder.build(vertx).createProcess().setSession(Session.create()).setTty(Pty.create().slave()); process.terminatedHandler(exitCode -> terminatedLatch.complete()); process.run(); terminatedLatch.awaitSuccess(10000); try { process.resume(); context.fail(); } catch (IllegalStateException ignore) { } } @Test public void testInterruptReadyProcess(TestContext context) { CommandBuilder builder = CommandBuilder.command("hello"); builder.processHandler(process -> context.fail()); Process process = builder.build(vertx).createProcess().setSession(Session.create()).setTty(Pty.create().slave()); try { process.interrupt(); context.fail(); } catch (Exception ignore) { } } @Test public void testInterruptRunningProcess(TestContext context) throws Exception { CommandBuilder builder = CommandBuilder.command("hello"); AtomicInteger status = new AtomicInteger(); Async runningLatch = context.async(); Async interruptedLatch = context.async(6); builder.processHandler(process -> { process.interruptHandler(v -> { interruptedLatch.countDown(); }); runningLatch.complete(); }); Context ctx = vertx.getOrCreateContext(); Process process = createProcessInContext(ctx, builder.build(vertx)); process.run(); runningLatch.awaitSuccess(10000); process.interrupt(v -> { context.assertEquals(ctx, Vertx.currentContext()); context.assertEquals(0, status.getAndIncrement()); interruptedLatch.countDown(); }); process.interrupt(v -> { context.assertEquals(ctx, Vertx.currentContext()); context.assertEquals(1, status.getAndIncrement()); interruptedLatch.countDown(); }); process.interrupt(v -> { context.assertEquals(ctx, Vertx.currentContext()); context.assertEquals(2, status.getAndIncrement()); interruptedLatch.countDown(); }); } @Test public void testInterruptSuspendedProcess(TestContext context) { CommandBuilder builder = CommandBuilder.command("hello"); Async runningLatch = context.async(); Async suspendedLatch = context.async(); Async interruptedLatch = context.async(3); builder.processHandler(process -> { process.interruptHandler(v -> interruptedLatch.countDown()); process.suspendHandler(v -> suspendedLatch.complete()); runningLatch.complete(); }); Process process = builder.build(vertx).createProcess().setSession(Session.create()).setTty(Pty.create().slave()); process.run(); runningLatch.awaitSuccess(10000); process.suspend(); suspendedLatch.awaitSuccess(10000); process.interrupt(); process.interrupt(); process.interrupt(); } @Test public void testInterruptTerminatedProcess(TestContext context) { CommandBuilder builder = CommandBuilder.command("hello"); Async terminatedLatch = context.async(); builder.processHandler(process -> process.end()); Process process = builder.build(vertx).createProcess().setSession(Session.create()).setTty(Pty.create().slave()); process.terminatedHandler(exitCode -> terminatedLatch.complete()); process.run(); terminatedLatch.awaitSuccess(10000); try { process.interrupt(); context.fail(); } catch (Exception ignore) { } } @Test public void testTerminateRunningProcess(TestContext context) throws Exception { CommandBuilder builder = CommandBuilder.command("hello"); AtomicInteger status = new AtomicInteger(); Async terminatedLatch = context.async(3); Async runningLatch = context.async(); builder.processHandler(process -> { process.endHandler(v -> { context.assertEquals(0, status.getAndIncrement()); terminatedLatch.countDown(); }); runningLatch.complete(); }); Context ctx = vertx.getOrCreateContext(); Process process = createProcessInContext(ctx, builder.build(vertx)); process.terminatedHandler(exitCode -> terminatedLatch.countDown()); process.run(); runningLatch.awaitSuccess(10000); process.terminate(v -> { context.assertEquals(ctx, Vertx.currentContext()); context.assertEquals(1, status.getAndIncrement()); terminatedLatch.countDown(); }); } @Test public void testTerminateSuspendedProcess(TestContext context) throws Exception { CommandBuilder builder = CommandBuilder.command("hello"); AtomicInteger status = new AtomicInteger(); Async runningLatch = context.async(); Async suspendedLatch = context.async(); Async terminatedLatch = context.async(); builder.processHandler(process -> { process.suspendHandler(v -> suspendedLatch.complete()); process.endHandler(v -> { context.assertEquals(0, status.getAndIncrement()); terminatedLatch.countDown(); }); runningLatch.complete(); }); Context ctx = vertx.getOrCreateContext(); Process process = createProcessInContext(ctx, builder.build(vertx)); process.terminatedHandler(exitCode -> { context.assertEquals(ctx, Vertx.currentContext()); terminatedLatch.countDown(); }); process.run(); runningLatch.awaitSuccess(10000); process.suspend(); suspendedLatch.awaitSuccess(10000); process.terminate(v -> { context.assertEquals(ctx, Vertx.currentContext()); context.assertEquals(1, status.getAndIncrement()); terminatedLatch.countDown(); }); } @Test public void testTerminateReadyProcess(TestContext context) throws Exception { CommandBuilder builder = CommandBuilder.command("hello"); Async terminatedLatch = context.async(2); builder.processHandler(process -> context.fail()); Context ctx = vertx.getOrCreateContext(); Process process = createProcessInContext(ctx, builder.build(vertx)); process.terminatedHandler(exitCode -> { context.assertEquals(ctx, Vertx.currentContext()); terminatedLatch.countDown(); }); process.terminate(v -> { context.assertEquals(ctx, Vertx.currentContext()); terminatedLatch.countDown(); }); } @Test public void testTerminateTerminatedProcess(TestContext context) { CommandBuilder builder = CommandBuilder.command("hello"); Async runningLatch = context.async(); Async terminatedLatch = context.async(); builder.processHandler(process -> runningLatch.complete()); Process process = builder.build(vertx).createProcess().setSession(Session.create()).setTty(Pty.create().slave()); process.terminatedHandler(exitCode -> terminatedLatch.complete()); process.run(); runningLatch.awaitSuccess(10000); process.terminate(); terminatedLatch.awaitSuccess(10000); try { process.terminate(); context.fail(); } catch (IllegalStateException ignore) { } } @Test public void testEndRunningProcess(TestContext context) throws Exception { CommandBuilder builder = CommandBuilder.command("hello"); Async endedHandler = context.async(); builder.processHandler(process -> { process.endHandler(v -> endedHandler.complete()); process.end(0); }); Context ctx = vertx.getOrCreateContext(); Process process = createProcessInContext(ctx, builder.build(vertx)); Async terminatedHandler = context.async(); process.terminatedHandler(exitCode -> { context.assertEquals(ctx, Vertx.currentContext()); terminatedHandler.complete(); }); process.run(); } @Test public void testEndSuspendedProcess(TestContext context) throws Exception { CommandBuilder builder = CommandBuilder.command("hello"); Async runningLatch = context.async(); Async endedHandler = context.async(); builder.processHandler(process -> { process.suspendHandler(v -> { process.end(0); }); process.endHandler(v -> endedHandler.complete()); runningLatch.complete(); }); Context ctx = vertx.getOrCreateContext(); Process process = createProcessInContext(ctx, builder.build(vertx)); Async terminatedHandler = context.async(); process.terminatedHandler(exitCode -> { context.assertEquals(ctx, Vertx.currentContext()); terminatedHandler.complete(); }); process.run(); runningLatch.awaitSuccess(10000); process.suspend(); } /* @Test public void testTerminatedDoesNotExecute(TestContext context) throws InterruptedException { AtomicReference<Command> cmd = new AtomicReference<>(); Async registrationLatch = context.async(); CountDownLatch runningLatch = new CountDownLatch(1); Context ctx = vertx.getOrCreateContext(); ctx.runOnContext(v -> { CommandBuilder builder = CommandBuilder.command("hello"); builder.processHandler(process -> runningLatch.countDown()); cmd.set(builder.build(vertx)); registrationLatch.complete(); }); registrationLatch.awaitSuccess(10000); ctx.runOnContext(v -> { Process process = cmd.get().createProcess().setSession(Session.create()).setTty(Pty.create().slave()); process.run(); process.terminate(); }); context.assertFalse(runningLatch.await(1, TimeUnit.SECONDS)); } */ }