/** * Copyright 2007-2015, Kaazing Corporation. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.kaazing.k3po.driver.internal; import static java.util.concurrent.TimeUnit.SECONDS; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.ConnectException; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import java.net.URI; import java.net.URL; import java.net.URLClassLoader; import java.nio.CharBuffer; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.DisableOnDebug; import org.junit.rules.ExpectedException; import org.junit.rules.TestRule; import org.junit.rules.Timeout; public class RobotServerIT { private RobotServer robot; private Socket control; private Socket client; private ServerSocket server; private Socket accepted; @Rule public TestRule timeout = new DisableOnDebug(new Timeout(5, SECONDS)); @Rule public ExpectedException thrown = ExpectedException.none(); @Before public void setupRobot() throws Exception { robot = new RobotServer(URI.create("tcp://localhost:9080"), false, new URLClassLoader(new URL[]{new File( "src/test/scripts").toURI().toURL()})); robot.start(); control = new Socket(); control.connect(new InetSocketAddress("localhost", 9080)); client = new Socket(); server = new ServerSocket(); } @After public void shutdownRobot() throws Exception { control.close(); robot.stop(); client.close(); if (accepted != null) { accepted.close(); } server.close(); } @Test public void shouldFinishEmptyOK() throws Exception { String path = "org/kaazing/robot/driver/emptyScript"; // @formatter:off String strPrepared = "PREPARED\n" + "content-length:0\n" + "\n"; String strExpected = "STARTED\n" + "\n" + "FINISHED\n" + "content-length:0\n" + "\n"; // @formatter:on CharBuffer expectedPrepared = CharBuffer.wrap(strPrepared); CharBuffer expectedStartedAndFinished = CharBuffer.wrap(strExpected); BufferedWriter out = new BufferedWriter(new OutputStreamWriter(control.getOutputStream())); out.append("PREPARE\n"); out.append("version:2.0\n"); out.append("name:" + path + "\n"); out.append("\n"); out.flush(); BufferedReader in = new BufferedReader(new InputStreamReader(control.getInputStream())); CharBuffer prepared = CharBuffer.allocate(strPrepared.length()); while (prepared.hasRemaining()) { in.read(prepared); } prepared.flip(); assertEquals(expectedPrepared, prepared); out.append("START\n"); out.append("\n"); out.flush(); CharBuffer startedAndFinished = CharBuffer.allocate(strExpected.length()); while (startedAndFinished.hasRemaining()) { in.read(startedAndFinished); } startedAndFinished.flip(); assertEquals(expectedStartedAndFinished, startedAndFinished); assertFalse(in.ready()); } @Test public void shouldPrepareThenStartOK() throws Exception { String path = "org/kaazing/robot/driver/accept-then-close"; // @formatter:off String strExpectedPrepared = "PREPARED\n" + "content-length:60\n" + "\n" + "accept tcp://localhost:8080\n" + "accepted\n" + "connected\n" + "close\n" + "closed\n"; String strExpectedStarted = "STARTED\n" + "\n"; // @formatter:on CharBuffer expectedPrepared = CharBuffer.wrap(strExpectedPrepared); CharBuffer expectedStarted = CharBuffer.wrap(strExpectedStarted); BufferedWriter out = new BufferedWriter(new OutputStreamWriter(control.getOutputStream())); out.append("PREPARE\n"); out.append("version:2.0\n"); out.append("name:" + path + "\n"); out.append("\n"); out.flush(); BufferedReader in = new BufferedReader(new InputStreamReader(control.getInputStream())); CharBuffer prepared = CharBuffer.allocate(strExpectedPrepared.length()); while (prepared.hasRemaining()) { in.read(prepared); } prepared.flip(); out.append("START\n"); out.append("\n"); out.flush(); CharBuffer started = CharBuffer.allocate(strExpectedStarted.length()); while (started.hasRemaining()) { in.read(started); } started.flip(); assertEquals(expectedPrepared, prepared); assertEquals(expectedStarted, started); } @Test public void shouldAcceptThenCloseWithPrepareOK() throws Exception { String path = "org/kaazing/robot/driver/accept-then-close"; // @formatter:off String strExpectedPrepared = "PREPARED\n" + "content-length:60\n" + "\n" + "accept tcp://localhost:8080\n" + "accepted\n" + "connected\n" + "close\n" + "closed\n"; String strExpectedStarted = "STARTED\n" + "\n"; String strExpectedFinished = "FINISHED\n" + "content-length:60\n" + "\n" + "accept tcp://localhost:8080\n" + "accepted\n" + "connected\n" + "close\n" + "closed\n"; // @formatter:on CharBuffer expectedPrepared = CharBuffer.wrap(strExpectedPrepared); CharBuffer expectedStarted = CharBuffer.wrap(strExpectedStarted); CharBuffer expectedFinished = CharBuffer.wrap(strExpectedFinished); BufferedWriter out = new BufferedWriter(new OutputStreamWriter(control.getOutputStream())); out.append("PREPARE\n"); out.append("version:2.0\n"); out.append("name:" + path + "\n"); out.append("\n"); out.flush(); BufferedReader in = new BufferedReader(new InputStreamReader(control.getInputStream())); CharBuffer prepared = CharBuffer.allocate(strExpectedPrepared.length()); while (prepared.hasRemaining()) { in.read(prepared); } prepared.flip(); assertEquals(expectedPrepared, prepared); // Connect before we START client.connect(new InetSocketAddress("localhost", 8080)); out.append("START\n"); out.append("\n"); out.flush(); CharBuffer started = CharBuffer.allocate(strExpectedStarted.length()); while (started.hasRemaining()) { in.read(started); } started.flip(); assertEquals(expectedStarted, started); CharBuffer finished = CharBuffer.allocate(strExpectedFinished.length()); while (finished.hasRemaining()) { in.read(finished); } finished.flip(); assertEquals(expectedFinished, finished); assertFalse(in.ready()); assertEquals(-1, client.getInputStream().read()); } @Test public void shouldAcceptThenCloseOK() throws Exception { String path = "org/kaazing/robot/driver/accept-then-close"; // @formatter:off String strExpectedPrepared = "PREPARED\n" + "content-length:60\n" + "\n" + "accept tcp://localhost:8080\n" + "accepted\n" + "connected\n" + "close\n" + "closed\n"; String strExpectedStarted = "STARTED\n" + "\n"; String strExpectedFinished = "FINISHED\n" + "content-length:60\n" + "\n" + "accept tcp://localhost:8080\n" + "accepted\n" + "connected\n" + "close\n" + "closed\n"; // @formatter:on CharBuffer expectedPrepared = CharBuffer.wrap(strExpectedPrepared); CharBuffer expectedStarted = CharBuffer.wrap(strExpectedStarted); CharBuffer expectedFinished = CharBuffer.wrap(strExpectedFinished); BufferedWriter out = new BufferedWriter(new OutputStreamWriter(control.getOutputStream())); out.append("PREPARE\n"); out.append("version:2.0\n"); out.append("name:" + path + "\n"); out.append("\n"); out.flush(); BufferedReader in = new BufferedReader(new InputStreamReader(control.getInputStream())); CharBuffer prepared = CharBuffer.allocate(strExpectedPrepared.length()); while (prepared.hasRemaining()) { in.read(prepared); } prepared.flip(); assertEquals(expectedPrepared, prepared); client.connect(new InetSocketAddress("localhost", 8080)); out.append("START\n"); out.append("\n"); out.flush(); CharBuffer started = CharBuffer.allocate(strExpectedStarted.length()); while (started.hasRemaining()) { in.read(started); } started.flip(); assertEquals(expectedStarted, started); CharBuffer finished = CharBuffer.allocate(strExpectedFinished.length()); while (finished.hasRemaining()) { in.read(finished); } finished.flip(); assertEquals(expectedFinished, finished); assertFalse(in.ready()); assertEquals(-1, client.getInputStream().read()); } @Test public void shouldConnectThenCloseOK() throws Exception { server.bind(new InetSocketAddress("localhost", 8080)); String path = "org/kaazing/robot/driver/connect-then-close"; // @formatter:off String strExpectedPrepared = "PREPARED\n" + "content-length:52\n" + "\n" + "connect tcp://localhost:8080\n" + "connected\n" + "close\n" + "closed\n"; String strExpectedStarted = "STARTED\n" + "\n"; String strExpectedFinished = "FINISHED\n" + "content-length:52\n" + "\n" + "connect tcp://localhost:8080\n" + "connected\n" + "close\n" + "closed\n"; // @formatter:on CharBuffer expectedPrepared = CharBuffer.wrap(strExpectedPrepared); CharBuffer expectedStarted = CharBuffer.wrap(strExpectedStarted); CharBuffer expectedFinished = CharBuffer.wrap(strExpectedFinished); BufferedWriter out = new BufferedWriter(new OutputStreamWriter(control.getOutputStream())); BufferedReader in = new BufferedReader(new InputStreamReader(control.getInputStream())); out.append("PREPARE\n"); out.append("version:2.0\n"); out.append("name:" + path + "\n"); out.append("\n"); out.flush(); CharBuffer prepared = CharBuffer.allocate(strExpectedPrepared.length()); while (prepared.hasRemaining()) { in.read(prepared); } prepared.flip(); assertEquals(expectedPrepared, prepared); out.append("START\n"); out.append("\n"); out.flush(); CharBuffer started = CharBuffer.allocate(strExpectedStarted.length()); while (started.hasRemaining()) { in.read(started); } started.flip(); assertEquals(expectedStarted, started); accepted = server.accept(); CharBuffer finished = CharBuffer.allocate(strExpectedFinished.length()); while (finished.hasRemaining()) { in.read(finished); } finished.flip(); assertEquals(expectedFinished, finished); assertFalse(in.ready()); assertEquals(-1, accepted.getInputStream().read()); } @Test public void shouldConnectThenCloseWithPrepareOK() throws Exception { server.bind(new InetSocketAddress("localhost", 8080)); String path = "org/kaazing/robot/driver/connect-then-close"; // @formatter:off String strExpectedPrepared = "PREPARED\n" + "content-length:52\n" + "\n" + "connect tcp://localhost:8080\n" + "connected\n" + "close\n" + "closed\n"; String strExpectedStarted = "STARTED\n" + "\n"; String strExpectedFinished = "FINISHED\n" + "content-length:52\n" + "\n" + "connect tcp://localhost:8080\n" + "connected\n" + "close\n" + "closed\n"; // @formatter:on CharBuffer expectedPrepared = CharBuffer.wrap(strExpectedPrepared); CharBuffer expectedStarted = CharBuffer.wrap(strExpectedStarted); CharBuffer expectedFinished = CharBuffer.wrap(strExpectedFinished); BufferedWriter out = new BufferedWriter(new OutputStreamWriter(control.getOutputStream())); out.append("PREPARE\n"); out.append("version:2.0\n"); out.append("name:" + path + "\n"); out.append("\n"); out.flush(); BufferedReader in = new BufferedReader(new InputStreamReader(control.getInputStream())); CharBuffer prepared = CharBuffer.allocate(strExpectedPrepared.length()); while (prepared.hasRemaining()) { in.read(prepared); } prepared.flip(); assertEquals(expectedPrepared, prepared); out.append("START\n"); out.append("\n"); out.flush(); CharBuffer started = CharBuffer.allocate(strExpectedStarted.length()); while (started.hasRemaining()) { in.read(started); } started.flip(); assertEquals(expectedStarted, started); accepted = server.accept(); CharBuffer finished = CharBuffer.allocate(strExpectedFinished.length()); while (finished.hasRemaining()) { in.read(finished); } finished.flip(); assertEquals(expectedFinished, finished); assertFalse(in.ready()); assertEquals(-1, accepted.getInputStream().read()); } @Test public void shouldPrepareStartThenAbortOK() throws Exception { server.bind(new InetSocketAddress("localhost", 8080)); String path = "org/kaazing/robot/driver/shouldAbortOK"; // @formatter:off String strExpectedPrepared = "PREPARED\n" + "content-length:64\n" + "\n" + "connect tcp://localhost:8080\n" + "connected\n" + "read [0..4]\n" + "close\n" + "closed\n"; String strExpectedStarted = "STARTED\n" + "\n"; String strExpectedFinished = "FINISHED\n" + "content-length:40\n" + "\n" + "connect tcp://localhost:8080\n" + "connected\n" + "\n"; // @formatter:on CharBuffer expectedPrepared = CharBuffer.wrap(strExpectedPrepared); CharBuffer expectedStarted = CharBuffer.wrap(strExpectedStarted); CharBuffer expectedFinished = CharBuffer.wrap(strExpectedFinished); BufferedWriter out = new BufferedWriter(new OutputStreamWriter(control.getOutputStream())); out.append("PREPARE\n"); out.append("version:2.0\n"); out.append("name:" + path + "\n"); out.append("\n"); out.flush(); BufferedReader in = new BufferedReader(new InputStreamReader(control.getInputStream())); CharBuffer prepared = CharBuffer.allocate(strExpectedPrepared.length()); while (prepared.hasRemaining()) { in.read(prepared); } prepared.flip(); assertEquals(expectedPrepared, prepared); out = new BufferedWriter(new OutputStreamWriter(control.getOutputStream())); out.append("START\n"); out.append("\n"); out.flush(); CharBuffer started = CharBuffer.allocate(strExpectedStarted.length()); while (started.hasRemaining()) { in.read(started); } started.flip(); assertEquals(expectedStarted, started); accepted = server.accept(); // let the connect succeed before we abort // TODO: remove this sleep Thread.sleep(100); out = new BufferedWriter(new OutputStreamWriter(control.getOutputStream())); out.append("ABORT\n"); out.append("\n"); out.flush(); CharBuffer finished = CharBuffer.allocate(strExpectedFinished.length()); while (finished.hasRemaining()) { in.read(finished); System.out.println("Read in data, still has " + finished.length() + " to read"); } finished.flip(); assertEquals(expectedFinished, finished); assertFalse(in.ready()); } @Test public void shouldPrepareThenAbortOK() throws Exception { String path = "org/kaazing/robot/driver/shouldAbortOK"; // @formatter:off String strExpectedPrepared = "PREPARED\n" + "content-length:64\n" + "\n" + "connect tcp://localhost:8080\n" + "connected\n" + "read [0..4]\n" + "close\n" + "closed\n"; String strExpectedFinished = "FINISHED\n" + "content-length:1\n" + "\n" + "\n"; // @formatter:on CharBuffer expectedPrepared = CharBuffer.wrap(strExpectedPrepared); CharBuffer expectedFinished = CharBuffer.wrap(strExpectedFinished); BufferedWriter out = new BufferedWriter(new OutputStreamWriter(control.getOutputStream())); out.append("PREPARE\n"); out.append("version:2.0\n"); out.append("name:" + path + "\n"); out.append("\n"); out.flush(); BufferedReader in = new BufferedReader(new InputStreamReader(control.getInputStream())); CharBuffer prepared = CharBuffer.allocate(strExpectedPrepared.length()); while (prepared.hasRemaining()) { in.read(prepared); } prepared.flip(); assertEquals(expectedPrepared, prepared); out = new BufferedWriter(new OutputStreamWriter(control.getOutputStream())); out.append("ABORT\n"); out.append("\n"); out.flush(); CharBuffer finished = CharBuffer.allocate(strExpectedFinished.length()); while (finished.hasRemaining()) { in.read(finished); } finished.flip(); assertEquals(expectedFinished, finished); } @Test public void shouldDisconnectOK() throws Exception { String path = "org/kaazing/robot/driver/accept-then-close"; // @formatter:off String strExpectedPrepared = "PREPARED\n" + "content-length:60\n" + "\n" + "accept tcp://localhost:8080\n" + "accepted\n" + "connected\n" + "close\n" + "closed\n"; // @formatter:on CharBuffer expectedPrepared = CharBuffer.wrap(strExpectedPrepared); BufferedWriter out = new BufferedWriter(new OutputStreamWriter(control.getOutputStream())); out.append("PREPARE\n"); out.append("version:2.0\n"); out.append("name:" + path + "\n"); out.append("\n"); out.flush(); BufferedReader in = new BufferedReader(new InputStreamReader(control.getInputStream())); CharBuffer prepared = CharBuffer.allocate(strExpectedPrepared.length()); while (prepared.hasRemaining()) { in.read(prepared); } prepared.flip(); assertEquals(expectedPrepared, prepared); // Close the control channel control.close(); // TODO: How can I test this correctly? It takes some amount of time // before the server channel is closed. Thread.sleep(1000); thrown.expect(ConnectException.class); thrown.expectMessage("Connection refused"); // Now this should fail ... client.connect(new InetSocketAddress("localhost", 8080)); } @Test public void shouldParseErrorOK() throws Exception { String path = "org/kaazing/robot/driver/invalidScript"; BufferedWriter out = new BufferedWriter(new OutputStreamWriter(control.getOutputStream())); out.append("PREPARE\n"); out.append("version:2.0\n"); out.append("name:" + path + "\n"); out.append("\n"); out.flush(); BufferedReader in = new BufferedReader(new InputStreamReader(control.getInputStream())); String msg = in.readLine(); assertEquals("ERROR", msg); msg = in.readLine(); Pattern p = Pattern.compile("summary:.+"); Matcher m = p.matcher(msg); assertTrue(m.matches()); msg = in.readLine(); p = Pattern.compile("content-length:(\\d+)"); m = p.matcher(msg); assertTrue(m.matches()); final int contentLength = Integer.parseInt(m.group(1)); // End of header in.readLine(); CharBuffer error = CharBuffer.allocate(contentLength); while (error.hasRemaining()) { in.read(error); } error.flip(); } }