blob: 5306c31d713e36593caf3542e367bcee7fc17c32 [file] [log] [blame]
Georg Brandl38eceaa2008-05-26 11:14:17 +00001from xmlrpc.server import DocXMLRPCServer
Georg Brandl24420152008-05-26 16:32:26 +00002import http.client
R. David Murray378c0cf2010-02-24 01:46:21 +00003import sys
Benjamin Petersonee8712c2008-05-20 21:35:26 +00004from test import support
Christian Heimes2f1019e2007-12-10 16:18:49 +00005import threading
6import time
7import unittest
Christian Heimes2f1019e2007-12-10 16:18:49 +00008
9PORT = None
10
R. David Murray378c0cf2010-02-24 01:46:21 +000011def make_request_and_skipIf(condition, reason):
12 # If we skip the test, we have to make a request because the
13 # the server created in setUp blocks expecting one to come in.
14 if not condition:
15 return lambda func: func
16 def decorator(func):
17 def make_request_and_skip(self):
18 self.client.request("GET", "/")
19 self.client.getresponse()
20 raise unittest.SkipTest(reason)
21 return make_request_and_skip
22 return decorator
23
24
Christian Heimes2f1019e2007-12-10 16:18:49 +000025def server(evt, numrequests):
Benjamin Petersonf10a79a2008-10-11 00:49:57 +000026 serv = DocXMLRPCServer(("localhost", 0), logRequests=False)
Christian Heimes2f1019e2007-12-10 16:18:49 +000027
Benjamin Petersonf10a79a2008-10-11 00:49:57 +000028 try:
Christian Heimes2f1019e2007-12-10 16:18:49 +000029 global PORT
30 PORT = serv.socket.getsockname()[1]
31
32 # Add some documentation
33 serv.set_server_title("DocXMLRPCServer Test Documentation")
34 serv.set_server_name("DocXMLRPCServer Test Docs")
35 serv.set_server_documentation(
Ezio Melottib58e0bd2010-01-23 15:40:09 +000036 "This is an XML-RPC server's documentation, but the server "
37 "can be used by POSTing to /RPC2. Try self.add, too.")
Christian Heimes2f1019e2007-12-10 16:18:49 +000038
39 # Create and register classes and functions
40 class TestClass(object):
41 def test_method(self, arg):
42 """Test method's docs. This method truly does very little."""
43 self.arg = arg
44
45 serv.register_introspection_functions()
46 serv.register_instance(TestClass())
47
48 def add(x, y):
49 """Add two instances together. This follows PEP008, but has nothing
50 to do with RFC1952. Case should matter: pEp008 and rFC1952. Things
51 that start with http and ftp should be auto-linked, too:
52 http://google.com.
53 """
54 return x + y
55
56 serv.register_function(add)
57 serv.register_function(lambda x, y: x-y)
58
59 while numrequests > 0:
60 serv.handle_request()
61 numrequests -= 1
62 except socket.timeout:
63 pass
64 finally:
65 serv.server_close()
66 PORT = None
67 evt.set()
68
69class DocXMLRPCHTTPGETServer(unittest.TestCase):
70 def setUp(self):
Antoine Pitroud52656b2009-10-30 17:34:49 +000071 self._threads = support.threading_setup()
Christian Heimes2f1019e2007-12-10 16:18:49 +000072 # Enable server feedback
73 DocXMLRPCServer._send_traceback_header = True
74
75 self.evt = threading.Event()
76 threading.Thread(target=server, args=(self.evt, 1)).start()
77
78 # wait for port to be assigned
79 n = 1000
80 while n > 0 and PORT is None:
81 time.sleep(0.001)
82 n -= 1
83
Georg Brandl24420152008-05-26 16:32:26 +000084 self.client = http.client.HTTPConnection("localhost:%d" % PORT)
Christian Heimes2f1019e2007-12-10 16:18:49 +000085
86 def tearDown(self):
87 self.client.close()
88
89 self.evt.wait()
90
91 # Disable server feedback
92 DocXMLRPCServer._send_traceback_header = False
Antoine Pitroud52656b2009-10-30 17:34:49 +000093 support.threading_cleanup(*self._threads)
Christian Heimes2f1019e2007-12-10 16:18:49 +000094
95 def test_valid_get_response(self):
96 self.client.request("GET", "/")
97 response = self.client.getresponse()
98
99 self.assertEqual(response.status, 200)
100 self.assertEqual(response.getheader("Content-type"), "text/html")
101
102 # Server throws an exception if we don't start to read the data
103 response.read()
104
105 def test_invalid_get_response(self):
106 self.client.request("GET", "/spam")
107 response = self.client.getresponse()
108
109 self.assertEqual(response.status, 404)
110 self.assertEqual(response.getheader("Content-type"), "text/plain")
111
112 response.read()
113
114 def test_lambda(self):
115 """Test that lambda functionality stays the same. The output produced
116 currently is, I suspect invalid because of the unencoded brackets in the
117 HTML, "<lambda>".
118
119 The subtraction lambda method is tested.
120 """
121 self.client.request("GET", "/")
122 response = self.client.getresponse()
123
Ezio Melottib58e0bd2010-01-23 15:40:09 +0000124 self.assertIn((b'<dl><dt><a name="-&lt;lambda&gt;"><strong>'
125 b'&lt;lambda&gt;</strong></a>(x, y)</dt></dl>'),
126 response.read())
Christian Heimes2f1019e2007-12-10 16:18:49 +0000127
R. David Murray378c0cf2010-02-24 01:46:21 +0000128 @make_request_and_skipIf(sys.flags.optimize >= 2,
129 "Docstrings are omitted with -O2 and above")
Christian Heimes2f1019e2007-12-10 16:18:49 +0000130 def test_autolinking(self):
R. David Murray378c0cf2010-02-24 01:46:21 +0000131 """Test that the server correctly automatically wraps references to
132 PEPS and RFCs with links, and that it linkifies text starting with
133 http or ftp protocol prefixes.
Christian Heimes2f1019e2007-12-10 16:18:49 +0000134
135 The documentation for the "add" method contains the test material.
136 """
137 self.client.request("GET", "/")
Christian Heimes2202f872008-02-06 14:31:34 +0000138 response = self.client.getresponse().read()
Christian Heimes2f1019e2007-12-10 16:18:49 +0000139
Ezio Melottib58e0bd2010-01-23 15:40:09 +0000140 self.assertIn(
141 (b'<dl><dt><a name="-add"><strong>add</strong></a>(x, y)</dt><dd>'
142 b'<tt>Add&nbsp;two&nbsp;instances&nbsp;together.&nbsp;This&nbsp;'
143 b'follows&nbsp;<a href="http://www.python.org/dev/peps/pep-0008/">'
144 b'PEP008</a>,&nbsp;but&nbsp;has&nbsp;nothing<br>\nto&nbsp;do&nbsp;'
145 b'with&nbsp;<a href="http://www.rfc-editor.org/rfc/rfc1952.txt">'
146 b'RFC1952</a>.&nbsp;Case&nbsp;should&nbsp;matter:&nbsp;pEp008&nbsp;'
147 b'and&nbsp;rFC1952.&nbsp;&nbsp;Things<br>\nthat&nbsp;start&nbsp;'
148 b'with&nbsp;http&nbsp;and&nbsp;ftp&nbsp;should&nbsp;be&nbsp;'
149 b'auto-linked,&nbsp;too:<br>\n<a href="http://google.com">'
150 b'http://google.com</a>.</tt></dd></dl>'), response)
Christian Heimes2f1019e2007-12-10 16:18:49 +0000151
R. David Murray378c0cf2010-02-24 01:46:21 +0000152 @make_request_and_skipIf(sys.flags.optimize >= 2,
153 "Docstrings are omitted with -O2 and above")
Christian Heimes2f1019e2007-12-10 16:18:49 +0000154 def test_system_methods(self):
155 """Test the precense of three consecutive system.* methods.
156
R. David Murray378c0cf2010-02-24 01:46:21 +0000157 This also tests their use of parameter type recognition and the
158 systems related to that process.
Christian Heimes2f1019e2007-12-10 16:18:49 +0000159 """
160 self.client.request("GET", "/")
Christian Heimesa5535f22007-12-10 20:18:07 +0000161 response = self.client.getresponse().read()
Christian Heimes2f1019e2007-12-10 16:18:49 +0000162
Ezio Melottib58e0bd2010-01-23 15:40:09 +0000163 self.assertIn(
164 (b'<dl><dt><a name="-system.methodHelp"><strong>system.methodHelp'
165 b'</strong></a>(method_name)</dt><dd><tt><a href="#-system.method'
166 b'Help">system.methodHelp</a>(\'add\')&nbsp;=&gt;&nbsp;"Adds&nbsp;'
167 b'two&nbsp;integers&nbsp;together"<br>\n&nbsp;<br>\nReturns&nbsp;a'
168 b'&nbsp;string&nbsp;containing&nbsp;documentation&nbsp;for&nbsp;'
169 b'the&nbsp;specified&nbsp;method.</tt></dd></dl>\n<dl><dt><a name'
170 b'="-system.methodSignature"><strong>system.methodSignature</strong>'
171 b'</a>(method_name)</dt><dd><tt><a href="#-system.methodSignature">'
172 b'system.methodSignature</a>(\'add\')&nbsp;=&gt;&nbsp;[double,&nbsp;'
173 b'int,&nbsp;int]<br>\n&nbsp;<br>\nReturns&nbsp;a&nbsp;list&nbsp;'
174 b'describing&nbsp;the&nbsp;signature&nbsp;of&nbsp;the&nbsp;method.'
175 b'&nbsp;In&nbsp;the<br>\nabove&nbsp;example,&nbsp;the&nbsp;add&nbsp;'
176 b'method&nbsp;takes&nbsp;two&nbsp;integers&nbsp;as&nbsp;arguments'
177 b'<br>\nand&nbsp;returns&nbsp;a&nbsp;double&nbsp;result.<br>\n&nbsp;'
178 b'<br>\nThis&nbsp;server&nbsp;does&nbsp;NOT&nbsp;support&nbsp;system'
179 b'.methodSignature.</tt></dd></dl>\n<dl><dt><a name="-test_method">'
180 b'<strong>test_method</strong></a>(arg)</dt><dd><tt>Test&nbsp;'
181 b'method\'s&nbsp;docs.&nbsp;This&nbsp;method&nbsp;truly&nbsp;does'
182 b'&nbsp;very&nbsp;little.</tt></dd></dl>'), response)
Christian Heimes2f1019e2007-12-10 16:18:49 +0000183
184 def test_autolink_dotted_methods(self):
185 """Test that selfdot values are made strong automatically in the
186 documentation."""
187 self.client.request("GET", "/")
188 response = self.client.getresponse()
189
Ezio Melottib58e0bd2010-01-23 15:40:09 +0000190 self.assertIn(b"""Try&nbsp;self.<strong>add</strong>,&nbsp;too.""",
191 response.read())
Christian Heimes2f1019e2007-12-10 16:18:49 +0000192
193def test_main():
Benjamin Petersonee8712c2008-05-20 21:35:26 +0000194 support.run_unittest(DocXMLRPCHTTPGETServer)
Christian Heimes2f1019e2007-12-10 16:18:49 +0000195
196if __name__ == '__main__':
197 test_main()