/*
* 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;
import io.vertx.core.Context;
import io.vertx.core.Vertx;
import io.vertx.ext.shell.cli.CliToken;
import io.vertx.ext.shell.command.CommandBuilder;
import io.vertx.ext.shell.command.CommandProcessTest;
import io.vertx.ext.shell.command.CommandResolver;
import io.vertx.ext.shell.session.impl.SessionImpl;
import io.vertx.ext.shell.support.TestCommands;
import io.vertx.ext.shell.term.Pty;
import io.vertx.ext.shell.session.Session;
import io.vertx.ext.shell.system.Job;
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.Arrays;
import java.util.LinkedList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* @author <a href="mailto:julien@julienviet.com">Julien Viet</a>
*/
@RunWith(VertxUnitRunner.class)
public class ShellServerTest {
Vertx vertx;
ShellServer server;
TestCommands commands;
@Before
public void before(TestContext context) {
vertx = Vertx.vertx();
server = ShellServer.create(vertx);
commands = new TestCommands(vertx);
server.
registerCommandResolver(CommandResolver.baseCommands(vertx)).
registerCommandResolver(commands).
listen(context.asyncAssertSuccess());
}
@After
public void after(TestContext context) {
vertx.close(context.asyncAssertSuccess());
}
@Test
public void testRun(TestContext context) {
commands.add(CommandBuilder.command("foo").processHandler(process -> {
process.end(3);
}));
Shell shell = server.createShell();
Job job = shell.createJob(CliToken.tokenize("foo"));
Async async = context.async();
job.setTty(Pty.create().slave()).statusUpdateHandler(CommandProcessTest.terminateHandler(code -> {
context.assertEquals(3, job.process().exitCode());
async.complete();
})).run();
}
@Test
public void testThrowExceptionInProcess(TestContext context) {
commands.add(CommandBuilder.command("foo").processHandler(process -> {
throw new RuntimeException();
}));
Shell shell = server.createShell();
Job job = shell.createJob("foo");
Async async = context.async();
Pty pty = Pty.create();
job.setTty(pty.slave()).statusUpdateHandler(CommandProcessTest.terminateHandler(code -> {
context.assertEquals(1, job.process().exitCode());
async.complete();
})).run();
}
@Test
public void testStdin(TestContext context) {
CountDownLatch latch = new CountDownLatch(1);
commands.add(CommandBuilder.command("foo").processHandler(process -> {
process.stdinHandler(data -> {
context.assertEquals("hello_world", data);
process.end(0);
});
latch.countDown();
}));
Shell shell = server.createShell();
Job job = shell.createJob(CliToken.tokenize("foo"));
Async async = context.async();
Pty pty = Pty.create();
job.setTty(pty.slave());
job.statusUpdateHandler(CommandProcessTest.terminateHandler(code -> {
context.assertEquals(0, job.process().exitCode());
async.complete();
})).run();
try {
latch.await(10, TimeUnit.SECONDS);
} catch (InterruptedException e) {
context.fail(e);
}
pty.write("hello_world");
}
@Test
public void testStdout(TestContext context) {
commands.add(CommandBuilder.command("foo").processHandler(process -> {
process.write("bye_world");
process.end(0);
}));
Shell shell = server.createShell();
Job job = shell.createJob("foo");
Async async = context.async();
LinkedList<String> out = new LinkedList<>();
Pty pty = Pty.create();
pty.stdoutHandler(out::add);
job.setTty(pty.slave());
job.statusUpdateHandler(CommandProcessTest.terminateHandler(code -> {
context.assertEquals(0, job.process().exitCode());
context.assertEquals(Arrays.asList("bye_world"), out);
async.complete();
})).run();
}
@Test
public void testVertxContext(TestContext testContext) throws Exception {
Context commandCtx = vertx.getOrCreateContext();
Context shellCtx = vertx.getOrCreateContext();
Async async = testContext.async();
Async latch = testContext.async();
commandCtx.runOnContext(v1 -> {
CommandBuilder cmd = CommandBuilder.command("foo");
cmd.processHandler(process -> {
Context currentCtx = Vertx.currentContext();
testContext.assertTrue(commandCtx == currentCtx);
process.stdinHandler(text -> {
testContext.assertTrue(commandCtx == Vertx.currentContext());
testContext.assertEquals("ping", text);
process.write("pong");
});
process.suspendHandler(event -> {
testContext.assertTrue(commandCtx == Vertx.currentContext());
process.end(0);
});
latch.countDown();
});
commands.add(cmd);
shellCtx.runOnContext(v3 -> {
testContext.assertTrue(shellCtx == Vertx.currentContext());
Shell shell = server.createShell();
Job job = shell.createJob("foo");
Pty pty = Pty.create();
pty.stdoutHandler(text -> {
testContext.assertTrue(shellCtx == Vertx.currentContext());
testContext.assertEquals("pong", text);
job.suspend();
});
job.setTty(pty.slave()).statusUpdateHandler(CommandProcessTest.terminateHandler(code -> {
testContext.assertTrue(shellCtx == Vertx.currentContext());
async.complete();
})).run();
latch.awaitSuccess(10000);
pty.write("ping");
});
});
}
@Test
public void testSendEvent(TestContext context) {
CountDownLatch latch = new CountDownLatch(1);
commands.add(CommandBuilder.command("foo").processHandler(process -> {
process.suspendHandler(v -> {
process.end(0);
});
latch.countDown();
}));
Shell shell = server.createShell();
Job job = shell.createJob("foo");
Async async = context.async();
Pty pty = Pty.create();
job.setTty(pty.slave()).statusUpdateHandler(CommandProcessTest.terminateHandler(status -> {
async.complete();
})).run();
try {
latch.await(10, TimeUnit.SECONDS);
} catch (InterruptedException e) {
context.fail(e);
}
job.suspend();
}
@Test
public void testResize(TestContext context) {
commands.add(CommandBuilder.command("foo").processHandler(process -> {
context.assertEquals(20, process.width());
context.assertEquals(10, process.height());
process.resizehandler(v -> {
context.assertEquals(25, process.width());
context.assertEquals(15, process.height());
process.end(0);
});
process.write("ping");
}));
Shell shell = server.createShell();
Job job = shell.createJob("foo");
Pty pty = Pty.create();
Async async = context.async();
pty.setSize(20, 10);
pty.stdoutHandler(text -> {
pty.setSize(25, 15);
});
job.setTty(pty.slave()).statusUpdateHandler(CommandProcessTest.terminateHandler(status -> {
async.complete();
})).run();
}
@Test
public void testSessionGet(TestContext context) throws Exception {
Async async = context.async();
commands.add(CommandBuilder.command("foo").processHandler(process -> {
Session session = process.session();
context.assertNotNull(session);
context.assertEquals("the_value", session.get("the_key"));
process.end();
}));
Shell shell = server.createShell();
Job job = shell.createJob("foo");
Session session = new SessionImpl();
session.put("the_key", "the_value");
Pty pty = Pty.create();
job.setSession(session).setTty(pty.slave()).statusUpdateHandler(CommandProcessTest.terminateHandler(status -> {
context.assertEquals(0, job.process().exitCode());
async.complete();
})).run();
}
@Test
public void testSessionPut(TestContext context) throws Exception {
Async async = context.async();
commands.add(CommandBuilder.command("foo").processHandler(process -> {
Session session = process.session();
context.assertNotNull(session);
context.assertNull(session.get("the_key"));
session.put("the_key", "the_value");
process.end();
}));
Shell shell = server.createShell();
Job job = shell.createJob("foo");
Pty pty = Pty.create();
Session session = new SessionImpl();
job.setSession(session).setTty(pty.slave()).statusUpdateHandler(CommandProcessTest.terminateHandler(status -> {
context.assertEquals(0, job.process().exitCode());
context.assertEquals("the_value", session.get("the_key"));
async.complete();
})).run();
}
@Test
public void testSessionRemove(TestContext context) throws Exception {
Async async = context.async();
commands.add(CommandBuilder.command("foo").processHandler(process -> {
Session session = process.session();
context.assertNotNull(session);
context.assertEquals("the_value", session.remove("the_key"));
process.end();
}));
Shell shell = server.createShell();
Job job = shell.createJob("foo");
Pty pty = Pty.create();
Session session = new SessionImpl();
session.put("the_key", "the_value");
job.setSession(session).setTty(pty.slave()).statusUpdateHandler(CommandProcessTest.terminateHandler(status -> {
context.assertEquals(0, job.process().exitCode());
context.assertNull(session.get("the_key"));
async.complete();
})).run();
}
@Test
public void testClose(TestContext context) {
Async endLatch = context.async(2);
Async runningLatch = context.async();
commands.add(CommandBuilder.command("foo").processHandler(process -> {
process.endHandler(v -> endLatch.countDown());
runningLatch.countDown();
}));
Shell shell = server.createShell();
Job job = shell.createJob("foo");
Pty pty = Pty.create();
job.setTty(pty.slave()).statusUpdateHandler(CommandProcessTest.terminateHandler(status -> {
endLatch.countDown();
})).run();
runningLatch.awaitSuccess(10000);
shell.close();
endLatch.awaitSuccess(10000);
context.assertEquals(0, shell.jobController().jobs().size());
}
// Just some proof of concept, there are issues because we there is a timing
// problem when wiring processes
/*
@Test
public void testPipe(TestContext context) {
CommandManager manager = CommandManager.create(vertx);
Command cmd1 = Command.create("cmd1");
cmd1.processHandler(process -> {
process.setStdin(text -> {
process.stdout().handle("|" + text + "|");
process.end(0);
});
});
Command cmd2 = Command.create("cmd2");
cmd2.processHandler(process -> {
System.out.println("");
process.setStdin(text -> {
process.stdout().handle("<" + text + ">");
process.end(0);
});
});
manager.registerCommand(cmd.build()1, context.asyncAssertSuccess(v1 -> {
manager.registerCommand(cmd.build()2, context.asyncAssertSuccess(v2 -> {
Shell shell = Shell.create(vertx, manager);
shell.createJob("cmd2", context.asyncAssertSuccess(process2 -> {
Async async = context.async();
process2().setStdout(text -> {
context.assertEquals("<|hello|>", text);
async.complete();
});
process2.run(a1 -> {
shell.createJob("cmd1", context.asyncAssertSuccess(process1 -> {
process1().setStdout(process2().stdin());
process1.run(a2 -> {
process1().stdin().handle("hello");
});
}));
});
}));
}));
}));
}
*/
}