Home | History | Annotate | Download | only in test
      1 from DocXMLRPCServer import DocXMLRPCServer
      2 import httplib
      3 import sys
      4 from test import test_support
      5 threading = test_support.import_module('threading')
      6 import time
      7 import socket
      8 import unittest
      9 
     10 PORT = None
     11 
     12 def make_request_and_skipIf(condition, reason):
     13     # If we skip the test, we have to make a request because the
     14     # the server created in setUp blocks expecting one to come in.
     15     if not condition:
     16         return lambda func: func
     17     def decorator(func):
     18         def make_request_and_skip(self):
     19             self.client.request("GET", "/")
     20             self.client.getresponse()
     21             raise unittest.SkipTest(reason)
     22         return make_request_and_skip
     23     return decorator
     24 
     25 
     26 def server(evt, numrequests):
     27     serv = DocXMLRPCServer(("localhost", 0), logRequests=False)
     28 
     29     try:
     30         global PORT
     31         PORT = serv.socket.getsockname()[1]
     32 
     33         # Add some documentation
     34         serv.set_server_title("DocXMLRPCServer Test Documentation")
     35         serv.set_server_name("DocXMLRPCServer Test Docs")
     36         serv.set_server_documentation(
     37             "This is an XML-RPC server's documentation, but the server "
     38             "can be used by POSTing to /RPC2. Try self.add, too.")
     39 
     40         # Create and register classes and functions
     41         class TestClass(object):
     42             def test_method(self, arg):
     43                 """Test method's docs. This method truly does very little."""
     44                 self.arg = arg
     45 
     46         serv.register_introspection_functions()
     47         serv.register_instance(TestClass())
     48 
     49         def add(x, y):
     50             """Add two instances together. This follows PEP008, but has nothing
     51             to do with RFC1952. Case should matter: pEp008 and rFC1952.  Things
     52             that start with http and ftp should be auto-linked, too:
     53             http://google.com.
     54             """
     55             return x + y
     56 
     57         serv.register_function(add)
     58         serv.register_function(lambda x, y: x-y)
     59 
     60         while numrequests > 0:
     61             serv.handle_request()
     62             numrequests -= 1
     63     except socket.timeout:
     64         pass
     65     finally:
     66         serv.server_close()
     67         PORT = None
     68         evt.set()
     69 
     70 class DocXMLRPCHTTPGETServer(unittest.TestCase):
     71     def setUp(self):
     72         self._threads = test_support.threading_setup()
     73         # Enable server feedback
     74         DocXMLRPCServer._send_traceback_header = True
     75 
     76         self.evt = threading.Event()
     77         threading.Thread(target=server, args=(self.evt, 1)).start()
     78 
     79         # wait for port to be assigned
     80         n = 1000
     81         while n > 0 and PORT is None:
     82             time.sleep(0.001)
     83             n -= 1
     84 
     85         self.client = httplib.HTTPConnection("localhost:%d" % PORT)
     86 
     87     def tearDown(self):
     88         self.client.close()
     89 
     90         self.evt.wait()
     91 
     92         # Disable server feedback
     93         DocXMLRPCServer._send_traceback_header = False
     94         test_support.threading_cleanup(*self._threads)
     95 
     96     def test_valid_get_response(self):
     97         self.client.request("GET", "/")
     98         response = self.client.getresponse()
     99 
    100         self.assertEqual(response.status, 200)
    101         self.assertEqual(response.getheader("Content-type"), "text/html")
    102 
    103         # Server raises an exception if we don't start to read the data
    104         response.read()
    105 
    106     def test_invalid_get_response(self):
    107         self.client.request("GET", "/spam")
    108         response = self.client.getresponse()
    109 
    110         self.assertEqual(response.status, 404)
    111         self.assertEqual(response.getheader("Content-type"), "text/plain")
    112 
    113         response.read()
    114 
    115     def test_lambda(self):
    116         """Test that lambda functionality stays the same.  The output produced
    117         currently is, I suspect invalid because of the unencoded brackets in the
    118         HTML, "<lambda>".
    119 
    120         The subtraction lambda method is tested.
    121         """
    122         self.client.request("GET", "/")
    123         response = self.client.getresponse()
    124 
    125         self.assertIn('<dl><dt><a name="-&lt;lambda&gt;"><strong>'
    126                       '&lt;lambda&gt;</strong></a>(x, y)</dt></dl>',
    127                       response.read())
    128 
    129     @make_request_and_skipIf(sys.flags.optimize >= 2,
    130                      "Docstrings are omitted with -O2 and above")
    131     def test_autolinking(self):
    132         """Test that the server correctly automatically wraps references to
    133         PEPS and RFCs with links, and that it linkifies text starting with
    134         http or ftp protocol prefixes.
    135 
    136         The documentation for the "add" method contains the test material.
    137         """
    138         self.client.request("GET", "/")
    139         response = self.client.getresponse()
    140 
    141         self.assertIn(
    142             ('<dl><dt><a name="-add"><strong>add</strong></a>(x, y)</dt><dd>'
    143              '<tt>Add&nbsp;two&nbsp;instances&nbsp;together.&nbsp;This&nbsp;'
    144              'follows&nbsp;<a href="http://www.python.org/dev/peps/pep-0008/">'
    145              'PEP008</a>,&nbsp;but&nbsp;has&nbsp;nothing<br>\nto&nbsp;do&nbsp;'
    146              'with&nbsp;<a href="http://www.rfc-editor.org/rfc/rfc1952.txt">'
    147              'RFC1952</a>.&nbsp;Case&nbsp;should&nbsp;matter:&nbsp;pEp008&nbsp;'
    148              'and&nbsp;rFC1952.&nbsp;&nbsp;Things<br>\nthat&nbsp;start&nbsp;'
    149              'with&nbsp;http&nbsp;and&nbsp;ftp&nbsp;should&nbsp;be&nbsp;'
    150              'auto-linked,&nbsp;too:<br>\n<a href="http://google.com">'
    151              'http://google.com</a>.</tt></dd></dl>'), response.read())
    152 
    153     @make_request_and_skipIf(sys.flags.optimize >= 2,
    154                      "Docstrings are omitted with -O2 and above")
    155     def test_system_methods(self):
    156         """Test the precense of three consecutive system.* methods.
    157 
    158         This also tests their use of parameter type recognition and the
    159         systems related to that process.
    160         """
    161         self.client.request("GET", "/")
    162         response = self.client.getresponse()
    163 
    164         self.assertIn(
    165             ('<dl><dt><a name="-system.listMethods"><strong>system.listMethods'
    166              '</strong></a>()</dt><dd><tt><a href="#-system.listMethods">system'
    167              '.listMethods</a>()&nbsp;=&gt;&nbsp;[\'add\',&nbsp;\'subtract\','
    168              '&nbsp;\'multiple\']<br>\n&nbsp;<br>\nReturns&nbsp;a&nbsp;list'
    169              '&nbsp;of&nbsp;the&nbsp;methods&nbsp;supported&nbsp;by&nbsp;the'
    170              '&nbsp;server.</tt></dd></dl>\n <dl><dt><a name="-system.methodHelp">'
    171              '<strong>system.methodHelp</strong></a>(method_name)</dt><dd><tt>'
    172              '<a href="#-system.methodHelp">system.methodHelp</a>(\'add\')&nbsp;'
    173              '=&gt;&nbsp;"Adds&nbsp;two&nbsp;integers&nbsp;together"<br>\n&nbsp;'
    174              '<br>\nReturns&nbsp;a&nbsp;string&nbsp;containing&nbsp;documentation'
    175              '&nbsp;for&nbsp;the&nbsp;specified&nbsp;method.</tt></dd></dl>\n '
    176              '<dl><dt><a name="-system.methodSignature"><strong>system.'
    177              'methodSignature</strong></a>(method_name)</dt><dd><tt><a href="#-'
    178              'system.methodSignature">system.methodSignature</a>(\'add\')&nbsp;'
    179              '=&gt;&nbsp;[double,&nbsp;int,&nbsp;int]<br>\n&nbsp;<br>\nReturns'
    180              '&nbsp;a&nbsp;list&nbsp;describing&nbsp;the&nbsp;signature&nbsp;of'
    181              '&nbsp;the&nbsp;method.&nbsp;In&nbsp;the<br>\nabove&nbsp;example,'
    182              '&nbsp;the&nbsp;add&nbsp;method&nbsp;takes&nbsp;two&nbsp;integers'
    183              '&nbsp;as&nbsp;arguments<br>\nand&nbsp;returns&nbsp;a&nbsp;double'
    184              '&nbsp;result.<br>\n&nbsp;<br>\nThis&nbsp;server&nbsp;does&nbsp;'
    185              'NOT&nbsp;support&nbsp;system.methodSignature.</tt></dd></dl>'),
    186             response.read())
    187 
    188     def test_autolink_dotted_methods(self):
    189         """Test that selfdot values are made strong automatically in the
    190         documentation."""
    191         self.client.request("GET", "/")
    192         response = self.client.getresponse()
    193 
    194         self.assertIn("""Try&nbsp;self.<strong>add</strong>,&nbsp;too.""",
    195                       response.read())
    196 
    197 def test_main():
    198     test_support.run_unittest(DocXMLRPCHTTPGETServer)
    199 
    200 if __name__ == '__main__':
    201     test_main()
    202