PageRenderTime 44ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llmessage/tests/test_llsdmessage_peer.py

https://bitbucket.org/lindenlab/viewer-beta/
Python | 146 lines | 104 code | 3 blank | 39 comment | 2 complexity | 6970198ea1e08737fa7e58288b6e0919 MD5 | raw file
Possible License(s): LGPL-2.1
  1. #!/usr/bin/env 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. $LicenseInfo:firstyear=2008&license=viewerlgpl$
  10. Second Life Viewer Source Code
  11. Copyright (C) 2010, Linden Research, Inc.
  12. This library is free software; you can redistribute it and/or
  13. modify it under the terms of the GNU Lesser General Public
  14. License as published by the Free Software Foundation;
  15. version 2.1 of the License only.
  16. This library is distributed in the hope that it will be useful,
  17. but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  19. Lesser General Public License for more details.
  20. You should have received a copy of the GNU Lesser General Public
  21. License along with this library; if not, write to the Free Software
  22. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  23. Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. $/LicenseInfo$
  25. """
  26. import os
  27. import sys
  28. from threading import Thread
  29. from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
  30. mydir = os.path.dirname(__file__) # expected to be .../indra/llmessage/tests/
  31. sys.path.insert(0, os.path.join(mydir, os.pardir, os.pardir, "lib", "python"))
  32. from indra.util.fastest_elementtree import parse as xml_parse
  33. from indra.base import llsd
  34. from testrunner import freeport, run, debug, VERBOSE
  35. class TestHTTPRequestHandler(BaseHTTPRequestHandler):
  36. """This subclass of BaseHTTPRequestHandler is to receive and echo
  37. LLSD-flavored messages sent by the C++ LLHTTPClient.
  38. """
  39. def read(self):
  40. # The following logic is adapted from the library module
  41. # SimpleXMLRPCServer.py.
  42. # Get arguments by reading body of request.
  43. # We read this in chunks to avoid straining
  44. # socket.read(); around the 10 or 15Mb mark, some platforms
  45. # begin to have problems (bug #792570).
  46. try:
  47. size_remaining = int(self.headers["content-length"])
  48. except (KeyError, ValueError):
  49. return ""
  50. max_chunk_size = 10*1024*1024
  51. L = []
  52. while size_remaining:
  53. chunk_size = min(size_remaining, max_chunk_size)
  54. chunk = self.rfile.read(chunk_size)
  55. L.append(chunk)
  56. size_remaining -= len(chunk)
  57. return ''.join(L)
  58. # end of swiped read() logic
  59. def read_xml(self):
  60. # This approach reads the entire POST data into memory first
  61. return llsd.parse(self.read())
  62. ## # This approach attempts to stream in the LLSD XML from self.rfile,
  63. ## # assuming that the underlying XML parser reads its input file
  64. ## # incrementally. Unfortunately I haven't been able to make it work.
  65. ## tree = xml_parse(self.rfile)
  66. ## debug("Finished raw parse")
  67. ## debug("parsed XML tree %s", tree)
  68. ## debug("parsed root node %s", tree.getroot())
  69. ## debug("root node tag %s", tree.getroot().tag)
  70. ## return llsd.to_python(tree.getroot())
  71. def do_GET(self):
  72. # Of course, don't attempt to read data.
  73. self.answer(dict(reply="success", status=500,
  74. reason="Your GET operation requested failure"))
  75. def do_POST(self):
  76. # Read the provided POST data.
  77. self.answer(self.read_xml())
  78. def answer(self, data):
  79. debug("%s.answer(%s): self.path = %r", self.__class__.__name__, data, self.path)
  80. if "fail" not in self.path:
  81. response = llsd.format_xml(data.get("reply", llsd.LLSD("success")))
  82. debug("success: %s", response)
  83. self.send_response(200)
  84. self.send_header("Content-type", "application/llsd+xml")
  85. self.send_header("Content-Length", str(len(response)))
  86. self.end_headers()
  87. self.wfile.write(response)
  88. else: # fail requested
  89. status = data.get("status", 500)
  90. # self.responses maps an int status to a (short, long) pair of
  91. # strings. We want the longer string. That's why we pass a string
  92. # pair to get(): the [1] will select the second string, whether it
  93. # came from self.responses or from our default pair.
  94. reason = data.get("reason",
  95. self.responses.get(status,
  96. ("fail requested",
  97. "Your request specified failure status %s "
  98. "without providing a reason" % status))[1])
  99. debug("fail requested: %s: %r", status, reason)
  100. self.send_error(status, reason)
  101. if not VERBOSE:
  102. # When VERBOSE is set, skip both these overrides because they exist to
  103. # suppress output.
  104. def log_request(self, code, size=None):
  105. # For present purposes, we don't want the request splattered onto
  106. # stderr, as it would upset devs watching the test run
  107. pass
  108. def log_error(self, format, *args):
  109. # Suppress error output as well
  110. pass
  111. class Server(HTTPServer):
  112. # This pernicious flag is on by default in HTTPServer. But proper
  113. # operation of freeport() absolutely depends on it being off.
  114. allow_reuse_address = False
  115. if __name__ == "__main__":
  116. # Instantiate a Server(TestHTTPRequestHandler) on the first free port
  117. # in the specified port range. Doing this inline is better than in a
  118. # daemon thread: if it blows up here, we'll get a traceback. If it blew up
  119. # in some other thread, the traceback would get eaten and we'd run the
  120. # subject test program anyway.
  121. httpd, port = freeport(xrange(8000, 8020),
  122. lambda port: Server(('127.0.0.1', port), TestHTTPRequestHandler))
  123. # Pass the selected port number to the subject test program via the
  124. # environment. We don't want to impose requirements on the test program's
  125. # command-line parsing -- and anyway, for C++ integration tests, that's
  126. # performed in TUT code rather than our own.
  127. os.environ["PORT"] = str(port)
  128. debug("$PORT = %s", port)
  129. sys.exit(run(server=Thread(name="httpd", target=httpd.serve_forever), *sys.argv[1:]))