diff options
Diffstat (limited to 'linden/indra/llmessage/tests/test_llsdmessage_peer.py')
-rw-r--r-- | linden/indra/llmessage/tests/test_llsdmessage_peer.py | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/linden/indra/llmessage/tests/test_llsdmessage_peer.py b/linden/indra/llmessage/tests/test_llsdmessage_peer.py new file mode 100644 index 0000000..655169d --- /dev/null +++ b/linden/indra/llmessage/tests/test_llsdmessage_peer.py | |||
@@ -0,0 +1,153 @@ | |||
1 | #!/usr/bin/python | ||
2 | """\ | ||
3 | @file test_llsdmessage_peer.py | ||
4 | @author Nat Goodspeed | ||
5 | @date 2008-10-09 | ||
6 | @brief This script asynchronously runs the executable (with args) specified on | ||
7 | the command line, returning its result code. While that executable is | ||
8 | running, we provide dummy local services for use by C++ tests. | ||
9 | |||
10 | $LicenseInfo:firstyear=2008&license=viewergpl$ | ||
11 | |||
12 | Copyright (c) 2008-2009, Linden Research, Inc. | ||
13 | |||
14 | Second Life Viewer Source Code | ||
15 | The source code in this file ("Source Code") is provided by Linden Lab | ||
16 | to you under the terms of the GNU General Public License, version 2.0 | ||
17 | ("GPL"), unless you have obtained a separate licensing agreement | ||
18 | ("Other License"), formally executed by you and Linden Lab. Terms of | ||
19 | the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
20 | online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 | ||
21 | |||
22 | There are special exceptions to the terms and conditions of the GPL as | ||
23 | it is applied to this Source Code. View the full text of the exception | ||
24 | in the file doc/FLOSS-exception.txt in this software distribution, or | ||
25 | online at | ||
26 | http://secondlifegrid.net/programs/open_source/licensing/flossexception | ||
27 | |||
28 | By copying, modifying or distributing this software, you acknowledge | ||
29 | that you have read and understood your obligations described above, | ||
30 | and agree to abide by those obligations. | ||
31 | |||
32 | ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
33 | WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
34 | COMPLETENESS OR PERFORMANCE. | ||
35 | $/LicenseInfo$ | ||
36 | """ | ||
37 | |||
38 | import os | ||
39 | import sys | ||
40 | from threading import Thread | ||
41 | from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler | ||
42 | mydir = os.path.dirname(__file__) # expected to be .../indra/llmessage/tests/ | ||
43 | sys.path.insert(0, os.path.join(mydir, os.pardir, os.pardir, "lib", "python")) | ||
44 | from indra.util.fastest_elementtree import parse as xml_parse | ||
45 | from indra.base import llsd | ||
46 | |||
47 | def debug(*args): | ||
48 | sys.stdout.writelines(args) | ||
49 | sys.stdout.flush() | ||
50 | # comment out the line below to enable debug output | ||
51 | debug = lambda *args: None | ||
52 | |||
53 | class TestHTTPRequestHandler(BaseHTTPRequestHandler): | ||
54 | """This subclass of BaseHTTPRequestHandler is to receive and echo | ||
55 | LLSD-flavored messages sent by the C++ LLHTTPClient. | ||
56 | """ | ||
57 | def read(self): | ||
58 | # The following logic is adapted from the library module | ||
59 | # SimpleXMLRPCServer.py. | ||
60 | # Get arguments by reading body of request. | ||
61 | # We read this in chunks to avoid straining | ||
62 | # socket.read(); around the 10 or 15Mb mark, some platforms | ||
63 | # begin to have problems (bug #792570). | ||
64 | try: | ||
65 | size_remaining = int(self.headers["content-length"]) | ||
66 | except (KeyError, ValueError): | ||
67 | return "" | ||
68 | max_chunk_size = 10*1024*1024 | ||
69 | L = [] | ||
70 | while size_remaining: | ||
71 | chunk_size = min(size_remaining, max_chunk_size) | ||
72 | chunk = self.rfile.read(chunk_size) | ||
73 | L.append(chunk) | ||
74 | size_remaining -= len(chunk) | ||
75 | return ''.join(L) | ||
76 | # end of swiped read() logic | ||
77 | |||
78 | def read_xml(self): | ||
79 | # This approach reads the entire POST data into memory first | ||
80 | return llsd.parse(self.read()) | ||
81 | ## # This approach attempts to stream in the LLSD XML from self.rfile, | ||
82 | ## # assuming that the underlying XML parser reads its input file | ||
83 | ## # incrementally. Unfortunately I haven't been able to make it work. | ||
84 | ## tree = xml_parse(self.rfile) | ||
85 | ## debug("Finished raw parse\n") | ||
86 | ## debug("parsed XML tree %s\n" % tree) | ||
87 | ## debug("parsed root node %s\n" % tree.getroot()) | ||
88 | ## debug("root node tag %s\n" % tree.getroot().tag) | ||
89 | ## return llsd.to_python(tree.getroot()) | ||
90 | |||
91 | def do_GET(self): | ||
92 | # Of course, don't attempt to read data. | ||
93 | self.answer(dict(reply="success", status=500, | ||
94 | reason="Your GET operation requested failure")) | ||
95 | |||
96 | def do_POST(self): | ||
97 | # Read the provided POST data. | ||
98 | self.answer(self.read_xml()) | ||
99 | |||
100 | def answer(self, data): | ||
101 | if "fail" not in self.path: | ||
102 | response = llsd.format_xml(data.get("reply", llsd.LLSD("success"))) | ||
103 | self.send_response(200) | ||
104 | self.send_header("Content-type", "application/llsd+xml") | ||
105 | self.send_header("Content-Length", str(len(response))) | ||
106 | self.end_headers() | ||
107 | self.wfile.write(response) | ||
108 | else: # fail requested | ||
109 | status = data.get("status", 500) | ||
110 | reason = data.get("reason", | ||
111 | self.responses.get(status, | ||
112 | ("fail requested", | ||
113 | "Your request specified failure status %s " | ||
114 | "without providing a reason" % status))[1]) | ||
115 | self.send_error(status, reason) | ||
116 | |||
117 | def log_request(self, code, size=None): | ||
118 | # For present purposes, we don't want the request splattered onto | ||
119 | # stderr, as it would upset devs watching the test run | ||
120 | pass | ||
121 | |||
122 | def log_error(self, format, *args): | ||
123 | # Suppress error output as well | ||
124 | pass | ||
125 | |||
126 | class TestHTTPServer(Thread): | ||
127 | def run(self): | ||
128 | httpd = HTTPServer(('127.0.0.1', 8000), TestHTTPRequestHandler) | ||
129 | debug("Starting HTTP server...\n") | ||
130 | httpd.serve_forever() | ||
131 | |||
132 | def main(*args): | ||
133 | # Start HTTP server thread. Note that this and all other comm server | ||
134 | # threads should be daemon threads: we'll let them run "forever," | ||
135 | # confident that the whole process will terminate when the main thread | ||
136 | # terminates, which will be when the test executable child process | ||
137 | # terminates. | ||
138 | httpThread = TestHTTPServer(name="httpd") | ||
139 | httpThread.setDaemon(True) | ||
140 | httpThread.start() | ||
141 | # choice of os.spawnv(): | ||
142 | # - [v vs. l] pass a list of args vs. individual arguments, | ||
143 | # - [no p] don't use the PATH because we specifically want to invoke the | ||
144 | # executable passed as our first arg, | ||
145 | # - [no e] child should inherit this process's environment. | ||
146 | debug("Running %s...\n" % (" ".join(args))) | ||
147 | sys.stdout.flush() | ||
148 | rc = os.spawnv(os.P_WAIT, args[0], args) | ||
149 | debug("%s returned %s\n" % (args[0], rc)) | ||
150 | return rc | ||
151 | |||
152 | if __name__ == "__main__": | ||
153 | sys.exit(main(*sys.argv[1:])) | ||