blob: a1a1fcf8bc426574990d5311cb50b59605fb1a31 [file] [log] [blame]
Georg Brandle6daafb2007-12-09 22:39:12 +00001from DocXMLRPCServer import DocXMLRPCServer
2import httplib
R. David Murrayf28fd242010-02-23 00:24:49 +00003import sys
Georg Brandle6daafb2007-12-09 22:39:12 +00004from test import test_support
Victor Stinner6a102812010-04-27 23:55:59 +00005threading = test_support.import_module('threading')
Georg Brandle6daafb2007-12-09 22:39:12 +00006import time
Georg Brandl12cad202010-02-06 23:58:25 +00007import socket
Georg Brandle6daafb2007-12-09 22:39:12 +00008import unittest
Georg Brandle6daafb2007-12-09 22:39:12 +00009
10PORT = None
11
R. David Murrayf28fd242010-02-23 00:24:49 +000012def make_request_and_skipIf(condition, reason):
Serhiy Storchaka0f8f7842014-12-01 18:16:30 +020013 # If we skip the test, we have to make a request because
R. David Murrayf28fd242010-02-23 00:24:49 +000014 # 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
Georg Brandle6daafb2007-12-09 22:39:12 +000026def server(evt, numrequests):
Hirokazu Yamamotob7df32e2008-10-03 16:18:42 +000027 serv = DocXMLRPCServer(("localhost", 0), logRequests=False)
Georg Brandle6daafb2007-12-09 22:39:12 +000028
Hirokazu Yamamotob7df32e2008-10-03 16:18:42 +000029 try:
Georg Brandle6daafb2007-12-09 22:39:12 +000030 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(
Ezio Melottiaa980582010-01-23 23:04:36 +000037 "This is an XML-RPC server's documentation, but the server "
38 "can be used by POSTing to /RPC2. Try self.add, too.")
Georg Brandle6daafb2007-12-09 22:39:12 +000039
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
70class DocXMLRPCHTTPGETServer(unittest.TestCase):
71 def setUp(self):
Antoine Pitrou61d5f6f2009-10-30 17:33:28 +000072 self._threads = test_support.threading_setup()
Georg Brandle6daafb2007-12-09 22:39:12 +000073 # 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
Antoine Pitrou61d5f6f2009-10-30 17:33:28 +000094 test_support.threading_cleanup(*self._threads)
Georg Brandle6daafb2007-12-09 22:39:12 +000095
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
Andrew Svetlov4bb142b2012-12-18 21:27:37 +0200103 # Server raises an exception if we don't start to read the data
Georg Brandle6daafb2007-12-09 22:39:12 +0000104 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
Ezio Melottiaa980582010-01-23 23:04:36 +0000125 self.assertIn('<dl><dt><a name="-&lt;lambda&gt;"><strong>'
126 '&lt;lambda&gt;</strong></a>(x, y)</dt></dl>',
127 response.read())
Georg Brandle6daafb2007-12-09 22:39:12 +0000128
R. David Murrayf28fd242010-02-23 00:24:49 +0000129 @make_request_and_skipIf(sys.flags.optimize >= 2,
130 "Docstrings are omitted with -O2 and above")
Georg Brandle6daafb2007-12-09 22:39:12 +0000131 def test_autolinking(self):
R. David Murrayf28fd242010-02-23 00:24:49 +0000132 """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.
Georg Brandle6daafb2007-12-09 22:39:12 +0000135
136 The documentation for the "add" method contains the test material.
137 """
138 self.client.request("GET", "/")
139 response = self.client.getresponse()
140
Ezio Melottiaa980582010-01-23 23:04:36 +0000141 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())
Georg Brandle6daafb2007-12-09 22:39:12 +0000152
R. David Murrayf28fd242010-02-23 00:24:49 +0000153 @make_request_and_skipIf(sys.flags.optimize >= 2,
154 "Docstrings are omitted with -O2 and above")
Georg Brandle6daafb2007-12-09 22:39:12 +0000155 def test_system_methods(self):
156 """Test the precense of three consecutive system.* methods.
157
R. David Murrayf28fd242010-02-23 00:24:49 +0000158 This also tests their use of parameter type recognition and the
159 systems related to that process.
Georg Brandle6daafb2007-12-09 22:39:12 +0000160 """
161 self.client.request("GET", "/")
162 response = self.client.getresponse()
163
Ezio Melottiaa980582010-01-23 23:04:36 +0000164 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())
Georg Brandle6daafb2007-12-09 22:39:12 +0000187
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
Ezio Melottiaa980582010-01-23 23:04:36 +0000194 self.assertIn("""Try&nbsp;self.<strong>add</strong>,&nbsp;too.""",
195 response.read())
Georg Brandle6daafb2007-12-09 22:39:12 +0000196
197def test_main():
198 test_support.run_unittest(DocXMLRPCHTTPGETServer)
199
200if __name__ == '__main__':
201 test_main()