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="-<lambda>"><strong>' 126 '<lambda></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 two instances together. This ' 144 'follows <a href="http://www.python.org/dev/peps/pep-0008/">' 145 'PEP008</a>, but has nothing<br>\nto do ' 146 'with <a href="http://www.rfc-editor.org/rfc/rfc1952.txt">' 147 'RFC1952</a>. Case should matter: pEp008 ' 148 'and rFC1952. Things<br>\nthat start ' 149 'with http and ftp should be ' 150 'auto-linked, 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>() => [\'add\', \'subtract\',' 168 ' \'multiple\']<br>\n <br>\nReturns a list' 169 ' of the methods supported by the' 170 ' 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\') ' 173 '=> "Adds two integers together"<br>\n ' 174 '<br>\nReturns a string containing documentation' 175 ' for the specified 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\') ' 179 '=> [double, int, int]<br>\n <br>\nReturns' 180 ' a list describing the signature of' 181 ' the method. In the<br>\nabove example,' 182 ' the add method takes two integers' 183 ' as arguments<br>\nand returns a double' 184 ' result.<br>\n <br>\nThis server does ' 185 'NOT support 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 self.<strong>add</strong>, too.""", 195 response.read()) 196 197 def test_main(): 198 test_support.run_unittest(DocXMLRPCHTTPGETServer) 199 200 if __name__ == '__main__': 201 test_main() 202