summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xindra/llcorehttp/tests/test_llcorehttp_peer.py18
-rwxr-xr-xindra/llmessage/tests/test_llsdmessage_peer.py19
-rwxr-xr-xindra/llmessage/tests/testrunner.py82
-rwxr-xr-xindra/newview/tests/test_llxmlrpc_peer.py17
4 files changed, 82 insertions, 54 deletions
diff --git a/indra/llcorehttp/tests/test_llcorehttp_peer.py b/indra/llcorehttp/tests/test_llcorehttp_peer.py
index aad3d4b7b3..b2af8a6c9c 100755
--- a/indra/llcorehttp/tests/test_llcorehttp_peer.py
+++ b/indra/llcorehttp/tests/test_llcorehttp_peer.py
@@ -34,7 +34,6 @@ import sys
import time
import select
import getopt
-from threading import Thread
try:
from cStringIO import StringIO
except ImportError:
@@ -48,7 +47,7 @@ from llbase import llsd
sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir,
"llmessage", "tests"))
-from testrunner import run, debug, VERBOSE
+from testrunner import freeport, run, debug, VERBOSE
class TestHTTPRequestHandler(BaseHTTPRequestHandler):
"""This subclass of BaseHTTPRequestHandler is to receive and echo
@@ -303,9 +302,18 @@ if __name__ == "__main__":
if option == "-V" or option == "--valgrind":
do_valgrind = True
- # Instantiate a Server(TestHTTPRequestHandler) on a port chosen by the
- # runtime.
- httpd = Server(('127.0.0.1', 0), TestHTTPRequestHandler)
+ # function to make a server with specified port
+ make_server = lambda port: Server(('127.0.0.1', port), TestHTTPRequestHandler)
+
+ if not sys.platform.startswith("win"):
+ # Instantiate a Server(TestHTTPRequestHandler) on a port chosen by the
+ # runtime.
+ httpd = make_server(0)
+ else:
+ # "Then there's Windows"
+ # Instantiate a Server(TestHTTPRequestHandler) on the first free port
+ # in the specified port range.
+ httpd, port = freeport(xrange(8000, 8020), make_server)
# Pass the selected port number to the subject test program via the
# environment. We don't want to impose requirements on the test program's
diff --git a/indra/llmessage/tests/test_llsdmessage_peer.py b/indra/llmessage/tests/test_llsdmessage_peer.py
index 8e1204fb20..9cd2959ea1 100755
--- a/indra/llmessage/tests/test_llsdmessage_peer.py
+++ b/indra/llmessage/tests/test_llsdmessage_peer.py
@@ -31,12 +31,11 @@ $/LicenseInfo$
import os
import sys
-from threading import Thread
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
from llbase.fastest_elementtree import parse as xml_parse
from llbase import llsd
-from testrunner import run, debug, VERBOSE
+from testrunner import freeport, run, debug, VERBOSE
import time
_storage=None
@@ -155,9 +154,19 @@ class Server(HTTPServer):
allow_reuse_address = False
if __name__ == "__main__":
- # Instantiate a Server(TestHTTPRequestHandler) on a port chosen by the
- # runtime.
- httpd = Server(('127.0.0.1', 0), TestHTTPRequestHandler)
+ # function to make a server with specified port
+ make_server = lambda port: Server(('127.0.0.1', port), TestHTTPRequestHandler)
+
+ if not sys.platform.startswith("win"):
+ # Instantiate a Server(TestHTTPRequestHandler) on a port chosen by the
+ # runtime.
+ httpd = make_server(0)
+ else:
+ # "Then there's Windows"
+ # Instantiate a Server(TestHTTPRequestHandler) on the first free port
+ # in the specified port range.
+ httpd, port = freeport(xrange(8000, 8020), make_server)
+
# Pass the selected port number to the subject test program via the
# environment. We don't want to impose requirements on the test program's
# command-line parsing -- and anyway, for C++ integration tests, that's
diff --git a/indra/llmessage/tests/testrunner.py b/indra/llmessage/tests/testrunner.py
index 09f0f3c681..c25945067e 100755
--- a/indra/llmessage/tests/testrunner.py
+++ b/indra/llmessage/tests/testrunner.py
@@ -32,7 +32,7 @@ import sys
import re
import errno
import socket
-from threading import Thread
+import subprocess
VERBOSE = os.environ.get("INTEGRATION_TEST_VERBOSE", "0") # default to quiet
# Support usage such as INTEGRATION_TEST_VERBOSE=off -- distressing to user if
@@ -155,13 +155,13 @@ def run(*args, **kwds):
In addition, you may pass keyword-only arguments:
use_path=True: allow a simple filename as command and search PATH for that
- filename. Otherwise the command must be a full pathname.
+ filename. (This argument is retained for backwards compatibility but is
+ now the default behavior.)
server_inst: an instance of a subclass of SocketServer.BaseServer.
- When you pass server_inst, its serve_forever() method is called on a
- separate Thread before the child process is run. It is shutdown() when the
- child process terminates.
+ When you pass server_inst, run() calls its handle_request() method in a
+ loop until the child process terminates.
"""
# server= keyword arg is discontinued
try:
@@ -171,45 +171,47 @@ def run(*args, **kwds):
else:
raise Error("Obsolete call to testrunner.run(): pass server_inst=, not server=")
+ debug("Running %s...", " ".join(args))
+
try:
server_inst = kwds.pop("server_inst")
except KeyError:
- # We're not starting a thread, so shutdown() is a no-op.
- shutdown = lambda: None
+ # Without server_inst, this is very simple: just run child process.
+ rc = subprocess.call(args)
else:
- # Make a Thread on which to call server_inst.serve_forever().
- thread = Thread(name="server", target=server_inst.serve_forever)
-
- # Make this a "daemon" thread.
- thread.setDaemon(True)
- thread.start()
-
- # We used to simply call sys.exit() with the daemon thread still
- # running -- but in recent versions of Python 2, even when you call
- # sys.exit(0), apparently killing the thread causes the Python runtime
- # to force the process termination code to 1. So try to play nice.
- def shutdown():
- # evidently this call blocks until shutdown is complete
- server_inst.shutdown()
- # which should make it straightforward to join()
- thread.join()
-
- try:
- # choice of os.spawnv():
- # - [v vs. l] pass a list of args vs. individual arguments,
- # - [no p] don't use the PATH because we specifically want to invoke the
- # executable passed as our first arg,
- # - [no e] child should inherit this process's environment.
- debug("Running %s...", " ".join(args))
- if kwds.get("use_path", False):
- rc = os.spawnvp(os.P_WAIT, args[0], args)
- else:
- rc = os.spawnv(os.P_WAIT, args[0], args)
- debug("%s returned %s", args[0], rc)
- return rc
-
- finally:
- shutdown()
+ # We're being asked to run a local server while the child process
+ # runs. We used to launch a daemon thread calling
+ # server_inst.serve_forever(), then eventually call sys.exit() with
+ # the daemon thread still running -- but in recent versions of Python
+ # 2, even when you call sys.exit(0), apparently killing the thread
+ # causes the Python runtime to force the process termination code
+ # nonzero. So now we avoid the extra thread altogether.
+
+ # SocketServer.BaseServer.handle_request() honors a 'timeout'
+ # attribute, if it's set to something other than None.
+ # We pick 0.5 seconds because that's the default poll timeout for
+ # BaseServer.serve_forever(), which is what we used to use.
+ server_inst.timeout = 0.5
+
+ child = subprocess.Popen(args)
+ while child.poll() is None:
+ # Setting server_inst.timeout is what keeps this handle_request()
+ # call from blocking "forever." Interestingly, looping over
+ # handle_request() with a timeout is very like the implementation
+ # of serve_forever(). We just check a different flag to break out.
+ # It might be interesting if handle_request() returned an
+ # indication of whether it in fact handled a request or timed out.
+ # Oddly, it doesn't. We could discover that by overriding
+ # handle_timeout(), whose default implementation does nothing --
+ # but in fact we really don't care. All that matters is that we
+ # regularly poll both the child process and the server socket.
+ server_inst.handle_request()
+ # We don't bother to capture the rc returned by child.poll() because
+ # poll() is already defined to capture that in its returncode attr.
+ rc = child.returncode
+
+ debug("%s returned %s", args[0], rc)
+ return rc
# ****************************************************************************
# test code -- manual at this point, see SWAT-564
diff --git a/indra/newview/tests/test_llxmlrpc_peer.py b/indra/newview/tests/test_llxmlrpc_peer.py
index 12394ad1d9..cff40aa4c2 100755
--- a/indra/newview/tests/test_llxmlrpc_peer.py
+++ b/indra/newview/tests/test_llxmlrpc_peer.py
@@ -31,12 +31,11 @@ $/LicenseInfo$
import os
import sys
-from threading import Thread
from SimpleXMLRPCServer import SimpleXMLRPCServer
mydir = os.path.dirname(__file__) # expected to be .../indra/newview/tests/
sys.path.insert(0, os.path.join(mydir, os.pardir, os.pardir, "llmessage", "tests"))
-from testrunner import run, debug
+from testrunner import freeport, run, debug
class TestServer(SimpleXMLRPCServer):
# This server_bind() override is borrowed and simplified from
@@ -76,8 +75,18 @@ class TestServer(SimpleXMLRPCServer):
pass
if __name__ == "__main__":
- # Make the runtime choose an available port.
- xmlrpcd = TestServer(('127.0.0.1', 0))
+ # function to make a server with specified port
+ make_server = lambda port: TestServer(('127.0.0.1', port))
+
+ if not sys.platform.startswith("win"):
+ # Instantiate a TestServer on a port chosen by the runtime.
+ xmlrpcd = make_server(0)
+ else:
+ # "Then there's Windows"
+ # Instantiate a TestServer on the first free port in the specified
+ # port range.
+ xmlrpcd, port = freeport(xrange(8000, 8020), make_server)
+
# Pass the selected port number to the subject test program via the
# environment. We don't want to impose requirements on the test program's
# command-line parsing -- and anyway, for C++ integration tests, that's