diff options
Diffstat (limited to 'indra')
-rwxr-xr-x | indra/llcorehttp/tests/test_llcorehttp_peer.py | 35 | ||||
-rwxr-xr-x | indra/llcorehttp/tests/testrunner.py | 265 | ||||
-rw-r--r-- | indra/llimage/llimage.cpp | 2 | ||||
-rw-r--r-- | indra/llimage/llimage.h | 2 | ||||
-rwxr-xr-x | indra/llmessage/tests/test_llsdmessage_peer.py | 27 | ||||
-rwxr-xr-x | indra/llmessage/tests/testrunner.py | 87 | ||||
-rw-r--r-- | indra/llrender/llimagegl.cpp | 6 | ||||
-rwxr-xr-x | indra/newview/tests/test_llxmlrpc_peer.py | 36 |
8 files changed, 134 insertions, 326 deletions
diff --git a/indra/llcorehttp/tests/test_llcorehttp_peer.py b/indra/llcorehttp/tests/test_llcorehttp_peer.py index 6c5f37d407..493143641b 100755 --- a/indra/llcorehttp/tests/test_llcorehttp_peer.py +++ b/indra/llcorehttp/tests/test_llcorehttp_peer.py @@ -34,16 +34,19 @@ import sys import time import select import getopt -from threading import Thread try: from cStringIO import StringIO except ImportError: from StringIO import StringIO from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler -from SocketServer import ThreadingMixIn from llbase.fastest_elementtree import parse as xml_parse from llbase import llsd + +# we're in llcorehttp/tests ; testrunner.py is found in llmessage/tests +sys.path.append(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, + "llmessage", "tests")) + from testrunner import freeport, run, debug, VERBOSE class TestHTTPRequestHandler(BaseHTTPRequestHandler): @@ -269,7 +272,7 @@ class TestHTTPRequestHandler(BaseHTTPRequestHandler): # Suppress error output as well pass -class Server(ThreadingMixIn, HTTPServer): +class Server(HTTPServer): # This pernicious flag is on by default in HTTPServer. But proper # operation of freeport() absolutely depends on it being off. allow_reuse_address = False @@ -293,22 +296,26 @@ if __name__ == "__main__": if option == "-V" or option == "--valgrind": do_valgrind = True - # Instantiate a Server(TestHTTPRequestHandler) on the first free port - # in the specified port range. Doing this inline is better than in a - # daemon thread: if it blows up here, we'll get a traceback. If it blew up - # in some other thread, the traceback would get eaten and we'd run the - # subject test program anyway. - httpd, port = freeport(xrange(8000, 8020), - lambda port: Server(('127.0.0.1', port), 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 # performed in TUT code rather than our own. - os.environ["LL_TEST_PORT"] = str(port) - debug("$LL_TEST_PORT = %s", port) + os.environ["LL_TEST_PORT"] = str(httpd.server_port) + debug("$LL_TEST_PORT = %s", httpd.server_port) if do_valgrind: args = ["valgrind", "--log-file=./valgrind.log"] + args path_search = True - sys.exit(run(server=Thread(name="httpd", target=httpd.serve_forever), use_path=path_search, *args)) - + sys.exit(run(server_inst=httpd, use_path=path_search, *args)) diff --git a/indra/llcorehttp/tests/testrunner.py b/indra/llcorehttp/tests/testrunner.py deleted file mode 100755 index 9a2de71142..0000000000 --- a/indra/llcorehttp/tests/testrunner.py +++ /dev/null @@ -1,265 +0,0 @@ -#!/usr/bin/env python -"""\ -@file testrunner.py -@author Nat Goodspeed -@date 2009-03-20 -@brief Utilities for writing wrapper scripts for ADD_COMM_BUILD_TEST unit tests - -$LicenseInfo:firstyear=2009&license=viewerlgpl$ -Second Life Viewer Source Code -Copyright (C) 2010, Linden Research, Inc. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; -version 2.1 of the License only. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA -$/LicenseInfo$ -""" - -from __future__ import with_statement - -import os -import sys -import re -import errno -import socket - -VERBOSE = os.environ.get("INTEGRATION_TEST_VERBOSE", "0") # default to quiet -# Support usage such as INTEGRATION_TEST_VERBOSE=off -- distressing to user if -# that construct actually turns on verbosity... -VERBOSE = not re.match(r"(0|off|false|quiet)$", VERBOSE, re.IGNORECASE) - -if VERBOSE: - def debug(fmt, *args): - print fmt % args - sys.stdout.flush() -else: - debug = lambda *args: None - -def freeport(portlist, expr): - """ - Find a free server port to use. Specifically, evaluate 'expr' (a - callable(port)) until it stops raising EADDRINUSE exception. - - Pass: - - portlist: an iterable (e.g. xrange()) of ports to try. If you exhaust the - range, freeport() lets the socket.error exception propagate. If you want - unbounded, you could pass itertools.count(baseport), though of course in - practice the ceiling is 2^16-1 anyway. But it seems prudent to constrain - the range much more sharply: if we're iterating an absurd number of times, - probably something else is wrong. - - expr: a callable accepting a port number, specifically one of the items - from portlist. If calling that callable raises socket.error with - EADDRINUSE, freeport() retrieves the next item from portlist and retries. - - Returns: (expr(port), port) - - port: the value from portlist for which expr(port) succeeded - - Raises: - - Any exception raised by expr(port) other than EADDRINUSE. - - socket.error if, for every item from portlist, expr(port) raises - socket.error. The exception you see is the one from the last item in - portlist. - - StopIteration if portlist is completely empty. - - Example: - - class Server(HTTPServer): - # If you use BaseHTTPServer.HTTPServer, turning off this flag is - # essential for proper operation of freeport()! - allow_reuse_address = False - # ... - server, port = freeport(xrange(8000, 8010), - lambda port: Server(("localhost", port), - MyRequestHandler)) - # pass 'port' to client code - # call server.serve_forever() - """ - try: - # If portlist is completely empty, let StopIteration propagate: that's an - # error because we can't return meaningful values. We have no 'port', - # therefore no 'expr(port)'. - portiter = iter(portlist) - port = portiter.next() - - while True: - try: - # If this value of port works, return as promised. - value = expr(port) - - except socket.error, err: - # Anything other than 'Address already in use', propagate - if err.args[0] != errno.EADDRINUSE: - raise - - # Here we want the next port from portiter. But on StopIteration, - # we want to raise the original exception rather than - # StopIteration. So save the original exc_info(). - type, value, tb = sys.exc_info() - try: - try: - port = portiter.next() - except StopIteration: - raise type, value, tb - finally: - # Clean up local traceback, see docs for sys.exc_info() - del tb - - else: - debug("freeport() returning %s on port %s", value, port) - return value, port - - # Recap of the control flow above: - # If expr(port) doesn't raise, return as promised. - # If expr(port) raises anything but EADDRINUSE, propagate that - # exception. - # If portiter.next() raises StopIteration -- that is, if the port - # value we just passed to expr(port) was the last available -- reraise - # the EADDRINUSE exception. - # If we've actually arrived at this point, portiter.next() delivered a - # new port value. Loop back to pass that to expr(port). - - except Exception, err: - debug("*** freeport() raising %s: %s", err.__class__.__name__, err) - raise - -def run(*args, **kwds): - """All positional arguments collectively form a command line, executed as - a synchronous child process. - In addition, pass server=new_thread_instance as an explicit keyword (to - differentiate it from an additional command-line argument). - new_thread_instance should be an instantiated but not yet started Thread - subclass instance, e.g.: - run("python", "-c", 'print "Hello, world!"', server=TestHTTPServer(name="httpd")) - """ - # If there's no server= keyword arg, don't start a server thread: simply - # run a child process. - try: - thread = kwds.pop("server") - except KeyError: - pass - else: - # Start server thread. Note that this and all other comm server - # threads should be daemon threads: we'll let them run "forever," - # confident that the whole process will terminate when the main thread - # terminates, which will be when the child process terminates. - thread.setDaemon(True) - thread.start() - # 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 - -# **************************************************************************** -# test code -- manual at this point, see SWAT-564 -# **************************************************************************** -def test_freeport(): - # ------------------------------- Helpers -------------------------------- - from contextlib import contextmanager - # helper Context Manager for expecting an exception - # with exc(SomeError): - # raise SomeError() - # raises AssertionError otherwise. - @contextmanager - def exc(exception_class, *args): - try: - yield - except exception_class, err: - for i, expected_arg in enumerate(args): - assert expected_arg == err.args[i], \ - "Raised %s, but args[%s] is %r instead of %r" % \ - (err.__class__.__name__, i, err.args[i], expected_arg) - print "Caught expected exception %s(%s)" % \ - (err.__class__.__name__, ', '.join(repr(arg) for arg in err.args)) - else: - assert False, "Failed to raise " + exception_class.__class__.__name__ - - # helper to raise specified exception - def raiser(exception): - raise exception - - # the usual - def assert_equals(a, b): - assert a == b, "%r != %r" % (a, b) - - # ------------------------ Sanity check the above ------------------------ - class SomeError(Exception): pass - # Without extra args, accept any err.args value - with exc(SomeError): - raiser(SomeError("abc")) - # With extra args, accept only the specified value - with exc(SomeError, "abc"): - raiser(SomeError("abc")) - with exc(AssertionError): - with exc(SomeError, "abc"): - raiser(SomeError("def")) - with exc(AssertionError): - with exc(socket.error, errno.EADDRINUSE): - raiser(socket.error(errno.ECONNREFUSED, 'Connection refused')) - - # ----------- freeport() without engaging socket functionality ----------- - # If portlist is empty, freeport() raises StopIteration. - with exc(StopIteration): - freeport([], None) - - assert_equals(freeport([17], str), ("17", 17)) - - # This is the magic exception that should prompt us to retry - inuse = socket.error(errno.EADDRINUSE, 'Address already in use') - # Get the iterator to our ports list so we can check later if we've used all - ports = iter(xrange(5)) - with exc(socket.error, errno.EADDRINUSE): - freeport(ports, lambda port: raiser(inuse)) - # did we entirely exhaust 'ports'? - with exc(StopIteration): - ports.next() - - ports = iter(xrange(2)) - # Any exception but EADDRINUSE should quit immediately - with exc(SomeError): - freeport(ports, lambda port: raiser(SomeError())) - assert_equals(ports.next(), 1) - - # ----------- freeport() with platform-dependent socket stuff ------------ - # This is what we should've had unit tests to begin with (see CHOP-661). - def newbind(port): - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - sock.bind(('127.0.0.1', port)) - return sock - - bound0, port0 = freeport(xrange(7777, 7780), newbind) - assert_equals(port0, 7777) - bound1, port1 = freeport(xrange(7777, 7780), newbind) - assert_equals(port1, 7778) - bound2, port2 = freeport(xrange(7777, 7780), newbind) - assert_equals(port2, 7779) - with exc(socket.error, errno.EADDRINUSE): - bound3, port3 = freeport(xrange(7777, 7780), newbind) - -if __name__ == "__main__": - test_freeport() diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 43b6b3bcd6..a07ea14621 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -800,7 +800,7 @@ U8* LLImageBase::getData() return mData; } -bool LLImageBase::isBufferInvalid() +bool LLImageBase::isBufferInvalid() const { return mBadBufferAllocation || mData == NULL ; } diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index 9cc7431a9c..d0bd4a2aef 100644 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -141,7 +141,7 @@ public: const U8 *getData() const ; U8 *getData() ; - bool isBufferInvalid() ; + bool isBufferInvalid() const; void setSize(S32 width, S32 height, S32 ncomponents); U8* allocateDataSize(S32 width, S32 height, S32 ncomponents, S32 size = -1); // setSize() + allocateData() diff --git a/indra/llmessage/tests/test_llsdmessage_peer.py b/indra/llmessage/tests/test_llsdmessage_peer.py index bac18fa374..9cd2959ea1 100755 --- a/indra/llmessage/tests/test_llsdmessage_peer.py +++ b/indra/llmessage/tests/test_llsdmessage_peer.py @@ -31,7 +31,6 @@ $/LicenseInfo$ import os import sys -from threading import Thread from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler from llbase.fastest_elementtree import parse as xml_parse @@ -155,17 +154,23 @@ class Server(HTTPServer): allow_reuse_address = False if __name__ == "__main__": - # Instantiate a Server(TestHTTPRequestHandler) on the first free port - # in the specified port range. Doing this inline is better than in a - # daemon thread: if it blows up here, we'll get a traceback. If it blew up - # in some other thread, the traceback would get eaten and we'd run the - # subject test program anyway. - httpd, port = freeport(xrange(8000, 8020), - lambda port: Server(('127.0.0.1', port), 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 # performed in TUT code rather than our own. - os.environ["PORT"] = str(port) - debug("$PORT = %s", port) - sys.exit(run(server=Thread(name="httpd", target=httpd.serve_forever), *sys.argv[1:])) + os.environ["PORT"] = str(httpd.server_port) + debug("$PORT = %s", httpd.server_port) + sys.exit(run(server_inst=httpd, *sys.argv[1:])) diff --git a/indra/llmessage/tests/testrunner.py b/indra/llmessage/tests/testrunner.py index 5b9beb359b..c25945067e 100755 --- a/indra/llmessage/tests/testrunner.py +++ b/indra/llmessage/tests/testrunner.py @@ -27,13 +27,12 @@ Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA $/LicenseInfo$ """ -from __future__ import with_statement - import os import sys import re import errno import socket +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 @@ -47,6 +46,9 @@ if VERBOSE: else: debug = lambda *args: None +class Error(Exception): + pass + def freeport(portlist, expr): """ Find a free server port to use. Specifically, evaluate 'expr' (a @@ -141,34 +143,73 @@ def freeport(portlist, expr): raise def run(*args, **kwds): - """All positional arguments collectively form a command line, executed as - a synchronous child process. - In addition, pass server=new_thread_instance as an explicit keyword (to - differentiate it from an additional command-line argument). - new_thread_instance should be an instantiated but not yet started Thread - subclass instance, e.g.: - run("python", "-c", 'print "Hello, world!"', server=TestHTTPServer(name="httpd")) """ - # If there's no server= keyword arg, don't start a server thread: simply - # run a child process. + Run a specified command as a synchronous child process, optionally + launching a server Thread during the run. + + All positional arguments collectively form a command line. The first + positional argument names the program file to execute. + + Returns the termination code of the child process. + + In addition, you may pass keyword-only arguments: + + use_path=True: allow a simple filename as command and search PATH for that + 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, run() calls its handle_request() method in a + loop until the child process terminates. + """ + # server= keyword arg is discontinued try: thread = kwds.pop("server") except KeyError: pass else: - # Start server thread. Note that this and all other comm server - # threads should be daemon threads: we'll let them run "forever," - # confident that the whole process will terminate when the main thread - # terminates, which will be when the child process terminates. - thread.setDaemon(True) - thread.start() - # 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. + raise Error("Obsolete call to testrunner.run(): pass server_inst=, not server=") + debug("Running %s...", " ".join(args)) - rc = os.spawnv(os.P_WAIT, args[0], args) + + try: + server_inst = kwds.pop("server_inst") + except KeyError: + # Without server_inst, this is very simple: just run child process. + rc = subprocess.call(args) + else: + # 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 diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 81a5537f78..20cba68f84 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -1267,6 +1267,12 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S llassert(gGLManager.mInited); stop_glerror(); + if (!imageraw || imageraw->isBufferInvalid()) + { + LL_WARNS() << "Trying to create a texture from invalid image data" << LL_ENDL; + return FALSE; + } + if (discard_level < 0) { llassert(mCurrentDiscardLevel >= 0); diff --git a/indra/newview/tests/test_llxmlrpc_peer.py b/indra/newview/tests/test_llxmlrpc_peer.py index 281b72a058..cff40aa4c2 100755 --- a/indra/newview/tests/test_llxmlrpc_peer.py +++ b/indra/newview/tests/test_llxmlrpc_peer.py @@ -31,15 +31,23 @@ $/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, "lib", "python")) -sys.path.insert(1, os.path.join(mydir, os.pardir, os.pardir, "llmessage", "tests")) +sys.path.insert(0, os.path.join(mydir, os.pardir, os.pardir, "llmessage", "tests")) from testrunner import freeport, run, debug class TestServer(SimpleXMLRPCServer): + # This server_bind() override is borrowed and simplified from + # BaseHTTPServer.HTTPServer.server_bind(): we want to capture the actual + # server port. BaseHTTPServer.HTTPServer.server_bind() stores the actual + # port in a server_port attribute, but SimpleXMLRPCServer isn't derived + # from HTTPServer. So do it ourselves. + def server_bind(self): + """Override server_bind to store the server port.""" + SimpleXMLRPCServer.server_bind(self) + self.server_port = self.socket.getsockname()[1] + def _dispatch(self, method, params): try: func = getattr(self, method) @@ -67,15 +75,21 @@ class TestServer(SimpleXMLRPCServer): pass if __name__ == "__main__": - # Instantiate a TestServer on the first free port in the specified port - # range. Doing this inline is better than in a daemon thread: if it blows - # up here, we'll get a traceback. If it blew up in some other thread, the - # traceback would get eaten and we'd run the subject test program anyway. - xmlrpcd, port = freeport(xrange(8000, 8020), - lambda port: TestServer(('127.0.0.1', port))) + # 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 # performed in TUT code rather than our own. - os.environ["PORT"] = str(port) - sys.exit(run(server=Thread(name="xmlrpc", target=xmlrpcd.serve_forever), *sys.argv[1:])) + os.environ["PORT"] = str(xmlrpcd.server_port) + sys.exit(run(server_inst=xmlrpcd, *sys.argv[1:])) |