package fitnesse.testsystems.slim; import java.io.IOException; import java.io.PipedInputStream; import java.io.PipedOutputStream; import java.util.Collections; import java.util.List; import java.util.Map; import fitnesse.slim.SlimServer; import fitnesse.slim.SlimStreamReader; import fitnesse.slim.SlimVersion; import fitnesse.slim.instructions.Instruction; import fitnesse.slim.protocol.SlimDeserializer; import fitnesse.slim.protocol.SlimListBuilder; import fitnesse.slim.protocol.SlimSerializer; import fitnesse.testsystems.ExecutionLogListener; import fitnesse.util.MockSocket; import static fitnesse.testsystems.slim.SlimCommandRunningClient.resultToMap; public class InProcessSlimClient implements SlimClient { private final String testSystemName; private final SlimServer slimServer; private final ExecutionLogListener executionLogListener; private MockSocket socket; private PipedOutputStream clientOutput; private Thread slimServerThread; private SlimStreamReader reader; private double slimServerVersion; public InProcessSlimClient(String testSystemName, SlimServer slimServer, ExecutionLogListener executionLogListener) { this.testSystemName = testSystemName; this.slimServer = slimServer; this.executionLogListener = executionLogListener; } @Override public void start() throws IOException, SlimVersionMismatch { commandStarted(); PipedInputStream socketInput = new PipedInputStream(); clientOutput = new PipedOutputStream(socketInput); PipedInputStream clientInput = new PipedInputStream(); PipedOutputStream socketOutput = new PipedOutputStream(clientInput); reader = new SlimStreamReader(clientInput); socket = new MockSocket(socketInput, socketOutput); // Start SlimServer in a separate thread slimServerThread = new Thread(new Runnable() { @Override public void run() { try { slimServer.serve(socket); executionLogListener.exitCode(0); } catch (Throwable t) { // NOSONAR // This point is not reached since no errors bubble up this far executionLogListener.exceptionOccurred(t); } } }); slimServerThread.start(); connect(); } private void commandStarted() { executionLogListener.commandStarted(new ExecutionLogListener.ExecutionContext() { @Override public String getCommand() { return ""; } @Override public String getTestSystemName() { return testSystemName; } }); } @Override public Map<String, Object> invokeAndGetResponse(List<Instruction> statements) throws SlimCommunicationException { if (statements.isEmpty()) return Collections.emptyMap(); String instructions = SlimSerializer.serialize(new SlimListBuilder(slimServerVersion).toList(statements)); String results; try { SlimStreamReader.sendSlimMessage(clientOutput, instructions); results = reader.getSlimMessage(); } catch (IOException e) { throw new SlimCommunicationException("Could not send/receive data with SUT", e); } List<Object> resultList = SlimDeserializer.deserialize(results); return resultToMap(resultList); } @Override public void connect() throws IOException, SlimVersionMismatch { String slimServerVersionMessage = reader.readLine(); if (!isConnected(slimServerVersionMessage)) { throw new SlimVersionMismatch("Got invalid slim header from client. Read the following: " + slimServerVersionMessage); } slimServerVersion = Double.parseDouble(slimServerVersionMessage.replace(SlimVersion.SLIM_HEADER, "")); if (slimServerVersion == SlimCommandRunningClient.NO_SLIM_SERVER_CONNECTION_FLAG) { throw new SlimVersionMismatch("Slim Protocol Version Error: Server did not respond with a valid version number."); } else if (slimServerVersion < SlimCommandRunningClient.MINIMUM_REQUIRED_SLIM_VERSION) { throw new SlimVersionMismatch(String.format("Slim Protocol Version Error: Expected V%s but was V%s", SlimCommandRunningClient.MINIMUM_REQUIRED_SLIM_VERSION, slimServerVersion)); } } public boolean isConnected(String slimServerVersionMessage) { return slimServerVersionMessage.startsWith(SlimVersion.SLIM_HEADER); } @Override public void bye() throws IOException { // Close slimServer thread if (slimServerThread.isAlive()) { SlimStreamReader.sendSlimMessage(clientOutput, SlimVersion.BYEMESSAGE); } } @Override public void kill() { slimServerThread.interrupt(); } }