/** * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. * Licensed under the terms of the Eclipse Public License (EPL). * Please see the license.txt included with this distribution for details. * Any modifications to this file must keep this entire header intact. */ package org.python.pydev.debug.codecoverage; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import junit.framework.TestCase; import org.apache.xmlrpc.XmlRpcException; import org.apache.xmlrpc.XmlRpcHandler; import org.apache.xmlrpc.XmlRpcRequest; import org.apache.xmlrpc.server.XmlRpcHandlerMapping; import org.apache.xmlrpc.server.XmlRpcNoSuchHandlerException; import org.apache.xmlrpc.server.XmlRpcServer; import org.apache.xmlrpc.webserver.WebServer; import org.python.pydev.core.TestDependent; import org.python.pydev.core.docutils.StringUtils; import com.aptana.interactive_console.console.IXmlRpcClient; import com.aptana.interactive_console.console.ScriptXmlRpcClient; import com.aptana.shared_core.io.FileUtils; import com.aptana.shared_core.io.ThreadStreamReader; import com.aptana.shared_core.net.SocketUtil; public class XmlRpcTest extends TestCase { String[] EXPECTED = new String[] { "false", "false", "10", "false", "false", "false", "false", "true", "false", "true", "false", "true", "false", "20", "30", "false", "false", "false", "false", "false", "false", "start get completions", "Foo", "1", "foo", "3|4", "end get completions", "start raw_input", "'input_request'", "false", "false", "finish raw_input", "'foo'", "false", "false", "Console already exited with value: 0 while waiting for an answer.|exceptions.SystemExit:0", }; private int next = -1; private ThreadStreamReader err; private ThreadStreamReader out; private WebServer webServer; public static void main(String[] args) throws MalformedURLException, XmlRpcException { try { XmlRpcTest xmlRpcTest = new XmlRpcTest(); xmlRpcTest.setUp(); xmlRpcTest.testXmlRpcServerJython(); xmlRpcTest.tearDown(); junit.textui.TestRunner.run(XmlRpcTest.class); } catch (Throwable e) { e.printStackTrace(); } } @Override protected void tearDown() throws Exception { if (this.webServer != null) { this.webServer.shutdown(); } } private Process startServer(int client_port, int port, boolean python) throws IOException { File f = new File(TestDependent.TEST_PYDEV_PLUGIN_LOC + "pysrc/pydevconsole.py"); String[] cmdLine; if (python) { cmdLine = new String[] { TestDependent.PYTHON_EXE, "-u", FileUtils.getFileAbsolutePath(f), "" + port, "" + client_port }; } else { cmdLine = new String[] { TestDependent.JAVA_LOCATION, "-classpath", TestDependent.JYTHON_JAR_LOCATION, "org.python.util.jython", FileUtils.getFileAbsolutePath(f), "" + port, "" + client_port }; } Process process = Runtime.getRuntime().exec(cmdLine); err = new ThreadStreamReader(process.getErrorStream()); out = new ThreadStreamReader(process.getInputStream()); err.start(); out.start(); this.webServer = new WebServer(client_port); XmlRpcServer serverToHandleRawInput = this.webServer.getXmlRpcServer(); serverToHandleRawInput.setHandlerMapping(new XmlRpcHandlerMapping() { public XmlRpcHandler getHandler(String handlerName) throws XmlRpcNoSuchHandlerException, XmlRpcException { return new XmlRpcHandler() { public Object execute(XmlRpcRequest request) throws XmlRpcException { return "input_request"; } }; } }); this.webServer.start(); return process; } public void testXmlRpcServerPython() throws XmlRpcException, IOException, InterruptedException { checkServer(true); } public void testXmlRpcServerJython() throws XmlRpcException, IOException, InterruptedException { checkServer(false); } public void checkServer(boolean python) throws XmlRpcException, IOException, InterruptedException { Integer[] ports = SocketUtil.findUnusedLocalPorts(2); int port = ports[0]; int clientPort = ports[1]; Process process = startServer(clientPort, port, python); // int port = 8000; // Process process = null; //give some time for the process to start if (!python) { synchronized (this) { this.wait(1500); } } else { synchronized (this) { this.wait(500); } } try { int exitValue = process.exitValue(); fail("Already exited with val: " + exitValue); } catch (IllegalThreadStateException e) { //that's ok } try { IXmlRpcClient client = new ScriptXmlRpcClient(process, err, out); client.setPort(port); printArr(client.execute("addExec", new Object[] { "abc = 10" })); printArr(client.execute("addExec", new Object[] { "abc" })); printArr(client.execute("addExec", new Object[] { "import sys" })); printArr(client.execute("addExec", new Object[] { "class Foo:" })); printArr(client.execute("addExec", new Object[] { " print 20" })); printArr(client.execute("addExec", new Object[] { " print >> sys.stderr, 30" })); printArr(client.execute("addExec", new Object[] { "" })); printArr(client.execute("addExec", new Object[] { "foo=Foo()" })); printArr(client.execute("addExec", new Object[] { "foo.__doc__=None" })); printArr("start get completions"); Object[] completions = (Object[]) client.execute("getCompletions", new Object[] { "fo" }); //the completions may come in any order, we must sort it for the test and remove things we don't expect. Arrays.sort(completions, new Comparator<Object>() { public int compare(Object o1, Object o2) { String s1 = (String) ((Object[]) o1)[0]; String s2 = (String) ((Object[]) o2)[0]; return s1.compareTo(s2); } }); ArrayList<Object> arrayList = new ArrayList<Object>(); for (Object o : completions) { Object[] found = (Object[]) o; if (found[0].equals("foo") || found[0].equals("Foo")) { arrayList.add(found); } } printArr(arrayList.toArray()); printArr("end get completions"); printArr("start raw_input"); printArr(client.execute("addExec", new Object[] { "raw_input()" })); printArr("finish raw_input"); printArr(client.execute("addExec", new Object[] { "'foo'" })); // System.out.println("Ask exit"); printArr(client.execute("addExec", new Object[] { "sys.exit(0)" })); // System.out.println("End Ask exit"); } finally { if (process != null) { process.destroy(); } } assertEquals(next, EXPECTED.length - 1); } private void printArr(Object... execute) { if (this.out != null) { print(this.out.getAndClearContents()); print(this.err.getAndClearContents()); } for (Object o : execute) { print(o); } } private void print(Object execute) { if (execute instanceof Object[]) { Object[] objects = (Object[]) execute; for (Object o : objects) { print(o); } } else { String s = "" + execute; if (s.length() > 0) { String expected = EXPECTED[nextExpected()].trim(); String found = s.trim(); if (!expected.equals(found)) { if (expected.equals("false")) { expected = "0"; } if (expected.equals("true")) { expected = "1"; } if (expected.equals("3|4")) { if (found.equals("3") || found.equals("4")) { return; } } if (expected .equals("Console already exited with value: 0 while waiting for an answer.|exceptions.SystemExit:0")) { if ((found.indexOf("Console already exited with value: 0 while waiting for an answer.") != -1) || (found.indexOf("exceptions.SystemExit:0") != -1) || (found.indexOf("Failed to create input stream: Connection refused") != -1)) { return; } } String errorMessage = com.aptana.shared_core.string.StringUtils.format("Expected: >>%s<< and not: >>%s<< (position:%s)", expected, found, next); assertEquals(errorMessage, expected, found); } } } } private int nextExpected() { next += 1; return next; } }