2 The tests in this file compare the request and response objects
3 to the JSON-RPC 2.0 specification document, as well as testing
4 several internal components of the jsonrpclib library. Run this
5 module without any parameters to run the tests.
7 Currently, this is not easily tested with a framework like
8 nosetests because we spin up a daemon thread running the
9 the Server, and nosetests (at least in my tests) does not
10 ever "kill" the thread.
12 If you are testing jsonrpclib and the module doesn't return to
13 the command prompt after running the tests, you can hit
14 "Ctrl-C" (or "Ctrl-Break" on Windows) and that should kill it.
17 * Finish implementing JSON-RPC 2.0 Spec tests
18 * Implement JSON-RPC 1.0 tests
19 * Implement JSONClass, History, Config tests
22 from jsonrpclib import Server, MultiCall, history, config, ProtocolError
23 from jsonrpclib.SimpleJSONRPCServer import SimpleJSONRPCServer
24 from jsonrpclib.SimpleJSONRPCServer import SimpleJSONRPCRequestHandler
30 import simplejson as json
31 from threading import Thread
33 PORTS = range(8000, 8999)
35 class TestCompatibility(unittest.TestCase):
42 self.port = PORTS.pop()
43 self.server = server_set_up(port=self.port)
44 self.client = Server('http://localhost:%d' % self.port)
46 # v1 tests forthcoming
49 def test_positional(self):
50 """ Positional arguments in a single call """
51 result = self.client.subtract(23, 42)
52 self.assertTrue(result == -19)
53 result = self.client.subtract(42, 23)
54 self.assertTrue(result == 19)
55 request = json.loads(history.request)
56 response = json.loads(history.response)
58 "jsonrpc": "2.0", "method": "subtract",
59 "params": [42, 23], "id": request['id']
62 "jsonrpc": "2.0", "result": 19, "id": request['id']
64 self.assertTrue(request == verify_request)
65 self.assertTrue(response == verify_response)
68 """ Named arguments in a single call """
69 result = self.client.subtract(subtrahend=23, minuend=42)
70 self.assertTrue(result == 19)
71 result = self.client.subtract(minuend=42, subtrahend=23)
72 self.assertTrue(result == 19)
73 request = json.loads(history.request)
74 response = json.loads(history.response)
76 "jsonrpc": "2.0", "method": "subtract",
77 "params": {"subtrahend": 23, "minuend": 42},
81 "jsonrpc": "2.0", "result": 19, "id": request['id']
83 self.assertTrue(request == verify_request)
84 self.assertTrue(response == verify_response)
86 def test_notification(self):
87 """ Testing a notification (response should be null) """
88 result = self.client._notify.update(1, 2, 3, 4, 5)
89 self.assertTrue(result == None)
90 request = json.loads(history.request)
91 response = history.response
93 "jsonrpc": "2.0", "method": "update", "params": [1,2,3,4,5]
96 self.assertTrue(request == verify_request)
97 self.assertTrue(response == verify_response)
99 def test_non_existent_method(self):
100 self.assertRaises(ProtocolError, self.client.foobar)
101 request = json.loads(history.request)
102 response = json.loads(history.response)
104 "jsonrpc": "2.0", "method": "foobar", "id": request['id']
109 {"code": -32601, "message": response['error']['message']},
112 self.assertTrue(request == verify_request)
113 self.assertTrue(response == verify_response)
115 def test_invalid_json(self):
116 invalid_json = '{"jsonrpc": "2.0", "method": "foobar, '+ \
117 '"params": "bar", "baz]'
118 response = self.client._run_request(invalid_json)
119 response = json.loads(history.response)
120 verify_response = json.loads(
121 '{"jsonrpc": "2.0", "error": {"code": -32700,'+
122 ' "message": "Parse error."}, "id": null}'
124 verify_response['error']['message'] = response['error']['message']
125 self.assertTrue(response == verify_response)
127 def test_invalid_request(self):
128 invalid_request = '{"jsonrpc": "2.0", "method": 1, "params": "bar"}'
129 response = self.client._run_request(invalid_request)
130 response = json.loads(history.response)
131 verify_response = json.loads(
132 '{"jsonrpc": "2.0", "error": {"code": -32600, '+
133 '"message": "Invalid Request."}, "id": null}'
135 verify_response['error']['message'] = response['error']['message']
136 self.assertTrue(response == verify_response)
138 def test_batch_invalid_json(self):
139 invalid_request = '[ {"jsonrpc": "2.0", "method": "sum", '+ \
140 '"params": [1,2,4], "id": "1"},{"jsonrpc": "2.0", "method" ]'
141 response = self.client._run_request(invalid_request)
142 response = json.loads(history.response)
143 verify_response = json.loads(
144 '{"jsonrpc": "2.0", "error": {"code": -32700,'+
145 '"message": "Parse error."}, "id": null}'
147 verify_response['error']['message'] = response['error']['message']
148 self.assertTrue(response == verify_response)
150 def test_empty_array(self):
151 invalid_request = '[]'
152 response = self.client._run_request(invalid_request)
153 response = json.loads(history.response)
154 verify_response = json.loads(
155 '{"jsonrpc": "2.0", "error": {"code": -32600, '+
156 '"message": "Invalid Request."}, "id": null}'
158 verify_response['error']['message'] = response['error']['message']
159 self.assertTrue(response == verify_response)
161 def test_nonempty_array(self):
162 invalid_request = '[1,2]'
163 request_obj = json.loads(invalid_request)
164 response = self.client._run_request(invalid_request)
165 response = json.loads(history.response)
166 self.assertTrue(len(response) == len(request_obj))
167 for resp in response:
168 verify_resp = json.loads(
169 '{"jsonrpc": "2.0", "error": {"code": -32600, '+
170 '"message": "Invalid Request."}, "id": null}'
172 verify_resp['error']['message'] = resp['error']['message']
173 self.assertTrue(resp == verify_resp)
175 def test_batch(self):
176 multicall = MultiCall(self.client)
178 multicall._notify.notify_hello(7)
179 multicall.subtract(42,23)
180 multicall.foo.get(name='myself')
182 job_requests = [j.request() for j in multicall._job_list]
183 job_requests.insert(3, '{"foo": "boo"}')
184 json_requests = '[%s]' % ','.join(job_requests)
185 requests = json.loads(json_requests)
186 responses = self.client._run_request(json_requests)
188 verify_requests = json.loads("""[
189 {"jsonrpc": "2.0", "method": "sum", "params": [1,2,4], "id": "1"},
190 {"jsonrpc": "2.0", "method": "notify_hello", "params": [7]},
191 {"jsonrpc": "2.0", "method": "subtract", "params": [42,23], "id": "2"},
193 {"jsonrpc": "2.0", "method": "foo.get", "params": {"name": "myself"}, "id": "5"},
194 {"jsonrpc": "2.0", "method": "get_data", "id": "9"}
197 # Thankfully, these are in order so testing is pretty simple.
198 verify_responses = json.loads("""[
199 {"jsonrpc": "2.0", "result": 7, "id": "1"},
200 {"jsonrpc": "2.0", "result": 19, "id": "2"},
201 {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request."}, "id": null},
202 {"jsonrpc": "2.0", "error": {"code": -32601, "message": "Method not found."}, "id": "5"},
203 {"jsonrpc": "2.0", "result": ["hello", 5], "id": "9"}
206 self.assertTrue(len(requests) == len(verify_requests))
207 self.assertTrue(len(responses) == len(verify_responses))
212 for i in range(len(requests)):
213 verify_request = verify_requests[i]
214 request = requests[i]
216 if request.get('method') != 'notify_hello':
217 req_id = request.get('id')
218 if verify_request.has_key('id'):
219 verify_request['id'] = req_id
220 verify_response = verify_responses[response_i]
221 verify_response['id'] = req_id
222 responses_by_id[req_id] = verify_response
224 response = verify_response
225 self.assertTrue(request == verify_request)
227 for response in responses:
228 verify_response = responses_by_id.get(response.get('id'))
229 if verify_response.has_key('error'):
230 verify_response['error']['message'] = \
231 response['error']['message']
232 self.assertTrue(response == verify_response)
234 def test_batch_notifications(self):
235 multicall = MultiCall(self.client)
236 multicall._notify.notify_sum(1, 2, 4)
237 multicall._notify.notify_hello(7)
239 self.assertTrue(len(result) == 0)
240 valid_request = json.loads(
241 '[{"jsonrpc": "2.0", "method": "notify_sum", '+
242 '"params": [1,2,4]},{"jsonrpc": "2.0", '+
243 '"method": "notify_hello", "params": [7]}]'
245 request = json.loads(history.request)
246 self.assertTrue(len(request) == len(valid_request))
247 for i in range(len(request)):
249 valid_req = valid_request[i]
250 self.assertTrue(req == valid_req)
251 self.assertTrue(history.response == '')
253 class InternalTests(unittest.TestCase):
255 These tests verify that the client and server portions of
256 jsonrpclib talk to each other properly.
263 self.port = PORTS.pop()
264 self.server = server_set_up(port=self.port)
266 def get_client(self):
267 return Server('http://localhost:%d' % self.port)
269 def get_multicall_client(self):
270 server = self.get_client()
271 return MultiCall(server)
273 def test_connect(self):
274 client = self.get_client()
275 result = client.ping()
276 self.assertTrue(result)
278 def test_single_args(self):
279 client = self.get_client()
280 result = client.add(5, 10)
281 self.assertTrue(result == 15)
283 def test_single_kwargs(self):
284 client = self.get_client()
285 result = client.add(x=5, y=10)
286 self.assertTrue(result == 15)
288 def test_single_kwargs_and_args(self):
289 client = self.get_client()
290 self.assertRaises(ProtocolError, client.add, (5,), {'y':10})
292 def test_single_notify(self):
293 client = self.get_client()
294 result = client._notify.add(5, 10)
295 self.assertTrue(result == None)
297 def test_single_namespace(self):
298 client = self.get_client()
299 response = client.namespace.sum(1,2,4)
300 request = json.loads(history.request)
301 response = json.loads(history.response)
303 "jsonrpc": "2.0", "params": [1, 2, 4],
304 "id": "5", "method": "namespace.sum"
307 "jsonrpc": "2.0", "result": 7, "id": "5"
309 verify_request['id'] = request['id']
310 verify_response['id'] = request['id']
311 self.assertTrue(verify_request == request)
312 self.assertTrue(verify_response == response)
314 def test_multicall_success(self):
315 multicall = self.get_multicall_client()
318 multicall.namespace.sum([5, 10, 15])
319 correct = [True, 15, 30]
321 for result in multicall():
322 self.assertTrue(result == correct[i])
325 def test_multicall_success(self):
326 multicall = self.get_multicall_client()
330 self.assertTrue(result[2] == 7)
332 def test_multicall_failure(self):
333 multicall = self.get_multicall_client()
335 multicall.add(x=5, y=10, z=10)
336 raises = [None, ProtocolError]
344 self.assertRaises(raises[i], func)
348 def subtract(minuend, subtrahend):
349 """ Using the keywords from the JSON-RPC v2 doc """
350 return minuend-subtrahend
358 def summation(*args):
361 def notify_hello(*args):
370 def server_set_up(port):
371 # Not sure this is a good idea to spin up a new server thread
372 # for each test... but it seems to work fine.
373 def log_request(self, *args, **kwargs):
374 """ Making the server output 'quiet' """
376 SimpleJSONRPCRequestHandler.log_request = log_request
377 server = SimpleJSONRPCServer(('', port))
378 server.register_function(summation, 'sum')
379 server.register_function(summation, 'notify_sum')
380 server.register_function(notify_hello)
381 server.register_function(subtract)
382 server.register_function(update)
383 server.register_function(get_data)
384 server.register_function(add)
385 server.register_function(ping)
386 server.register_function(summation, 'namespace.sum')
387 server_proc = Thread(target=server.serve_forever)
388 server_proc.daemon = True
392 if __name__ == '__main__':