def setUp(self): # Set up the server self.server = UtilityServer().start('', 0) self.port = self.server.get_port() # Prepare the client self.history = jsonrpclib.history.History()
def setUp(self): """ Sets up the test """ # Set up the server self.server = UtilityServer().start('', 0) self.port = self.server.get_port()
def setUp(self): """ Pre-test set up """ # Set up the server self.server = UtilityServer().start('', 0) self.port = self.server.get_port() # Set up the client self.history = jsonrpclib.history.History() self.client = jsonrpclib.ServerProxy( 'http://localhost:{0}'.format(self.port), history=self.history)
class InternalTests(unittest.TestCase): """ These tests verify that the client and server portions of jsonrpclib talk to each other properly. """ def setUp(self): # Set up the server self.server = UtilityServer().start('', 0) self.port = self.server.get_port() # Prepare the client self.history = jsonrpclib.history.History() def tearDown(self): """ Post-test clean up """ # Stop the server self.server.stop() def get_client(self): return jsonrpclib.ServerProxy('http://localhost:{0}'.format(self.port), history=self.history) def get_multicall_client(self): server = self.get_client() return jsonrpclib.MultiCall(server) def test_connect(self): client = self.get_client() result = client.ping() self.assertTrue(result) def test_single_args(self): client = self.get_client() result = client.add(5, 10) self.assertTrue(result == 15) def test_single_kwargs(self): client = self.get_client() result = client.add(x=5, y=10) self.assertTrue(result == 15) def test_single_kwargs_and_args(self): client = self.get_client() self.assertRaises(jsonrpclib.ProtocolError, client.add, (5,), {'y':10}) def test_single_notify(self): client = self.get_client() result = client._notify.add(5, 10) self.assertTrue(result == None) def test_single_namespace(self): client = self.get_client() client.namespace.sum(1, 2, 4) request = json.loads(self.history.request) response = json.loads(self.history.response) verify_request = { "jsonrpc": "2.0", "params": [1, 2, 4], "id": "5", "method": "namespace.sum" } verify_response = { "jsonrpc": "2.0", "result": 7, "id": "5" } verify_request['id'] = request['id'] verify_response['id'] = request['id'] self.assertTrue(verify_request == request) self.assertTrue(verify_response == response) def test_multicall_success(self): multicall = self.get_multicall_client() multicall.ping() multicall.add(5, 10) multicall.namespace.sum(5, 10, 15) correct = [True, 15, 30] for i, result in enumerate(multicall()): self.assertTrue(result == correct[i]) def test_multicall_success_2(self): multicall = self.get_multicall_client() for i in range(3): multicall.add(5, i) result = multicall() self.assertTrue(result[2] == 7) def test_multicall_failure(self): multicall = self.get_multicall_client() multicall.ping() multicall.add(x=5, y=10, z=10) raises = [None, jsonrpclib.ProtocolError] result = multicall() for i in range(2): if not raises[i]: result[i] else: def func(): return result[i] self.assertRaises(raises[i], func)
class InternalTests(unittest.TestCase): """ These tests verify that the client and server portions of jsonrpclib talk to each other properly. """ def setUp(self): # Set up the server self.server = UtilityServer().start('', 0) self.port = self.server.get_port() # Prepare the client self.history = jsonrpclib.history.History() def tearDown(self): """ Post-test clean up """ # Stop the server self.server.stop() def get_client(self): return jsonrpclib.ServerProxy('http://localhost:{0}'.format(self.port), history=self.history) def get_multicall_client(self): server = self.get_client() return jsonrpclib.MultiCall(server) def test_connect(self): client = self.get_client() result = client.ping() self.assertTrue(result) def test_single_args(self): client = self.get_client() result = client.add(5, 10) self.assertTrue(result == 15) def test_single_kwargs(self): client = self.get_client() result = client.add(x=5, y=10) self.assertTrue(result == 15) def test_single_kwargs_and_args(self): client = self.get_client() self.assertRaises(jsonrpclib.ProtocolError, client.add, (5, ), {'y': 10}) def test_single_notify(self): client = self.get_client() result = client._notify.add(5, 10) self.assertTrue(result is None) def test_single_namespace(self): client = self.get_client() client.namespace.sum(1, 2, 4) request = json.loads(self.history.request) response = json.loads(self.history.response) verify_request = { "jsonrpc": "2.0", "params": [1, 2, 4], "id": "5", "method": "namespace.sum" } verify_response = {"jsonrpc": "2.0", "result": 7, "id": request['id']} verify_request['id'] = request['id'] self.assertTrue(verify_request == request) self.assertTrue(verify_response == response) def test_multicall_success(self): multicall = self.get_multicall_client() multicall.ping() multicall.add(5, 10) multicall.namespace.sum(5, 10, 15) correct = [True, 15, 30] for i, result in enumerate(multicall()): self.assertTrue(result == correct[i]) def test_multicall_success_2(self): multicall = self.get_multicall_client() for i in range(3): multicall.add(5, i) result = multicall() self.assertTrue(result[2] == 7) def test_multicall_failure(self): multicall = self.get_multicall_client() multicall.ping() multicall.add(x=5, y=10, z=10) raises = [None, jsonrpclib.ProtocolError] result = multicall() for i in range(2): if not raises[i]: result[i] else: def func(): return result[i] self.assertRaises(raises[i], func)
class TestCompatibility(unittest.TestCase): """ Tests JSON-RPC compatibility """ def setUp(self): """ Pre-test set up """ # Set up the server self.server = UtilityServer().start("", 0) self.port = self.server.get_port() # Set up the client self.history = jsonrpclib.history.History() self.client = jsonrpclib.ServerProxy( "http://localhost:{0}".format(self.port), history=self.history ) def tearDown(self): """ Post-test clean up """ # Close the client self.client("close")() # Stop the server self.server.stop() # Version 2.0 Tests def test_positional(self): """ Positional arguments in a single call """ result = self.client.subtract(23, 42) self.assertTrue(result == -19) result = self.client.subtract(42, 23) self.assertTrue(result == 19) request = json.loads(self.history.request) response = json.loads(self.history.response) verify_request = { "jsonrpc": "2.0", "method": "subtract", "params": [42, 23], "id": request["id"], } verify_response = {"jsonrpc": "2.0", "result": 19, "id": request["id"]} self.assertTrue(request == verify_request) self.assertTrue(response == verify_response) def test_named(self): """ Named arguments in a single call """ result = self.client.subtract(subtrahend=23, minuend=42) self.assertTrue(result == 19) result = self.client.subtract(minuend=42, subtrahend=23) self.assertTrue(result == 19) request = json.loads(self.history.request) response = json.loads(self.history.response) verify_request = { "jsonrpc": "2.0", "method": "subtract", "params": {"subtrahend": 23, "minuend": 42}, "id": request["id"], } verify_response = {"jsonrpc": "2.0", "result": 19, "id": request["id"]} self.assertTrue(request == verify_request) self.assertTrue(response == verify_response) def test_notification(self): """ Testing a notification (response should be null) """ result = self.client._notify.update(1, 2, 3, 4, 5) self.assertTrue(result is None) request = json.loads(self.history.request) response = self.history.response verify_request = { "jsonrpc": "2.0", "method": "update", "params": [1, 2, 3, 4, 5], } verify_response = "" self.assertTrue(request == verify_request) self.assertTrue(response == verify_response) def test_non_existent_method(self): """ Testing behaviour when calling a non-existent method """ self.assertRaises(jsonrpclib.ProtocolError, self.client.foobar) request = json.loads(self.history.request) response = json.loads(self.history.response) verify_request = { "jsonrpc": "2.0", "method": "foobar", "id": request["id"], } verify_response = { "jsonrpc": "2.0", "error": {"code": -32601, "message": response["error"]["message"]}, "id": request["id"], } self.assertTrue(request == verify_request) self.assertTrue(response == verify_response) def test_special_method(self): """ Tests behaviour on dunder methods """ self.assertRaises( AttributeError, getattr, self.client, "__special_method__" ) self.assertIsNone(self.history.request) def test_invalid_json(self): """ Tests behaviour on invalid JSON request """ invalid_json = ( '{"jsonrpc": "2.0", "method": "foobar, ' + '"params": "bar", "baz]' ) self.client._run_request(invalid_json) response = json.loads(self.history.response) verify_response = json.loads( '{"jsonrpc": "2.0", "error": {"code": -32700,' + ' "message": "Parse error."}, "id": null}' ) verify_response["error"]["message"] = response["error"]["message"] self.assertTrue(response == verify_response) def test_invalid_request(self): """ Tests incomplete request """ invalid_request = '{"jsonrpc": "2.0", "method": 1, "params": "bar"}' self.client._run_request(invalid_request) response = json.loads(self.history.response) verify_response = json.loads( '{"jsonrpc": "2.0", "error": {"code": -32600, ' + '"message": "Invalid Request."}, "id": null}' ) verify_response["error"]["message"] = response["error"]["message"] self.assertTrue(response == verify_response) def test_batch_invalid_json(self): """ Tests invalid JSON request on batch call """ invalid_request = ( '[ {"jsonrpc": "2.0", "method": "sum", ' + '"params": [1,2,4], "id": "1"},{"jsonrpc": "2.0", "method" ]' ) self.client._run_request(invalid_request) response = json.loads(self.history.response) verify_response = json.loads( '{"jsonrpc": "2.0", "error": {"code": -32700,' + '"message": "Parse error."}, "id": null}' ) verify_response["error"]["message"] = response["error"]["message"] self.assertTrue(response == verify_response) def test_empty_array(self): """ Tests empty array as request """ invalid_request = "[]" self.client._run_request(invalid_request) response = json.loads(self.history.response) verify_response = json.loads( '{"jsonrpc": "2.0", "error": {"code": -32600, ' + '"message": "Invalid Request."}, "id": null}' ) verify_response["error"]["message"] = response["error"]["message"] self.assertTrue(response == verify_response) def test_nonempty_array(self): """ Tests array as request """ invalid_request = "[1,2]" request_obj = json.loads(invalid_request) self.client._run_request(invalid_request) response = json.loads(self.history.response) self.assertTrue(len(response) == len(request_obj)) for resp in response: verify_resp = json.loads( '{"jsonrpc": "2.0", "error": {"code": -32600, ' + '"message": "Invalid Request."}, "id": null}' ) verify_resp["error"]["message"] = resp["error"]["message"] self.assertTrue(resp == verify_resp) def test_batch(self): """ Tests batch call """ multicall = jsonrpclib.MultiCall(self.client) multicall.sum(1, 2, 4) multicall._notify.notify_hello(7) multicall.subtract(42, 23) multicall.foo.get(name="myself") multicall.get_data() job_requests = [j.request() for j in multicall._job_list] job_requests.insert(3, '{"foo": "boo"}') json_requests = "[%s]" % ",".join(job_requests) requests = json.loads(json_requests) responses = self.client._run_request(json_requests) verify_requests = json.loads( """[ {"jsonrpc": "2.0", "method": "sum", "params": [1,2,4], "id": "1"}, {"jsonrpc": "2.0", "method": "notify_hello", "params": [7]}, {"jsonrpc": "2.0", "method": "subtract", "params": [42,23], "id": "2"}, {"foo": "boo"}, {"jsonrpc": "2.0", "method": "foo.get", "params": {"name": "myself"}, "id": "5"}, {"jsonrpc": "2.0", "method": "get_data", "id": "9"} ]""" ) # Thankfully, these are in order so testing is pretty simple. verify_responses = json.loads( """[ {"jsonrpc": "2.0", "result": 7, "id": "1"}, {"jsonrpc": "2.0", "result": 19, "id": "2"}, {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request."}, "id": null}, {"jsonrpc": "2.0", "error": {"code": -32601, "message": "Method not found."}, "id": "5"}, {"jsonrpc": "2.0", "result": ["hello", 5], "id": "9"} ]""" ) self.assertTrue(len(requests) == len(verify_requests)) self.assertTrue(len(responses) == len(verify_responses)) responses_by_id = {} response_i = 0 for verify_request, request in zip(verify_requests, requests): response = None if request.get("method") != "notify_hello": req_id = request.get("id") if "id" in verify_request: verify_request["id"] = req_id verify_response = verify_responses[response_i] verify_response["id"] = req_id responses_by_id[req_id] = verify_response response_i += 1 response = verify_response self.assertTrue(request == verify_request) for response in responses: verify_response = responses_by_id.get(response.get("id")) if "error" in verify_response: verify_response["error"]["message"] = response["error"][ "message" ] self.assertTrue(response == verify_response) def test_batch_notifications(self): """ Tests batch notifications """ multicall = jsonrpclib.MultiCall(self.client) multicall._notify.notify_sum(1, 2, 4) multicall._notify.notify_hello(7) result = multicall() self.assertTrue(len(result) == 0) valid_request = json.loads( '[{"jsonrpc": "2.0", "method": "notify_sum", ' + '"params": [1,2,4]},{"jsonrpc": "2.0", ' + '"method": "notify_hello", "params": [7]}]' ) request = json.loads(self.history.request) self.assertTrue(len(request) == len(valid_request)) for req, valid_req in zip(request, valid_request): self.assertTrue(req == valid_req) self.assertTrue(self.history.response == "") def test_url_query_string(self): """ Tests if the query string arguments are kept """ # Prepare a simple server class ReqHandler(BaseHTTPRequestHandler): """ Basic request handler that returns parameters """ def do_POST(self): parsed = urlparse(self.path) result = { "id": 0, "error": None, "result": { "path": parsed.path, "qs": parsed.query, }, } result_str = json.dumps(result).encode("utf8") self.send_response(200) self.send_header("content-type", "application/json") self.send_header("content-length", str(len(result_str))) self.end_headers() self.wfile.write(result_str) # Start it httpd = HTTPServer(("", 0), ReqHandler) # Run it in a thread thread = threading.Thread(target=httpd.serve_forever) thread.daemon = True thread.start() # Prepare a random value arg = str(random.randint(0, 1024)) # Prepare the client client = jsonrpclib.ServerProxy( "http://localhost:{port}/test?q={arg}".format( port=httpd.server_port, arg=arg ) ) # Run a query result = client.test() # Stop the server httpd.shutdown() httpd.server_close() # Check the result self.assertEqual(result["path"], "/test", "Invalid path") self.assertEqual( result["qs"], "q={}".format(arg), "Invalid query string" ) # Wait the server to stop (5 sec max) thread.join(5)
class HeadersTests(unittest.TestCase): """ These tests verify functionality of additional headers. """ REQUEST_LINE = "^send: POST" def setUp(self): """ Sets up the test """ # Set up the server self.server = UtilityServer().start('', 0) self.port = self.server.get_port() def tearDown(self): """ Post-test clean up """ # Stop the server self.server.stop() @contextlib.contextmanager def captured_headers(self, check_duplicates=True): """ Captures the request headers. Yields the {header : value} dictionary, where keys are in lower case. :param check_duplicates: If True, raises an error if a header appears twice """ # Redirect the standard output, to catch jsonrpclib verbose messages stdout = sys.stdout sys.stdout = f = StringIO() headers = {} yield headers sys.stdout = stdout # Extract the sent request content request_lines = f.getvalue().splitlines() request_lines = list( filter(lambda l: l.startswith("send:"), request_lines)) request_line = request_lines[0].split("send: ")[-1] # Convert it to a string try: # Use eval to convert the representation into a string request_line = from_bytes(eval(request_line)) except: # Keep the received version pass # Extract headers raw_headers = request_line.splitlines()[1:-1] raw_headers = map(lambda h: re.split(r":\s?", h, 1), raw_headers) for header, value in raw_headers: header = header.lower() if check_duplicates and header in headers: raise KeyError("Header defined twice: {0}".format(header)) headers[header] = value def test_should_extract_headers(self): # given client = jsonrpclib.ServerProxy('http://localhost:{0}'.format( self.port), verbose=1) # when with self.captured_headers() as headers: response = client.ping() self.assertTrue(response) # then self.assertTrue(len(headers) > 0) self.assertTrue('content-type' in headers) self.assertEqual(headers['content-type'], 'application/json-rpc') def test_should_add_additional_headers(self): # given client = jsonrpclib.ServerProxy('http://localhost:{0}'.format( self.port), verbose=1, headers={'X-My-Header': 'Test'}) # when with self.captured_headers() as headers: response = client.ping() self.assertTrue(response) # then self.assertTrue('x-my-header' in headers) self.assertEqual(headers['x-my-header'], 'Test') def test_should_add_additional_headers_to_notifications(self): # given client = jsonrpclib.ServerProxy('http://localhost:{0}'.format( self.port), verbose=1, headers={'X-My-Header': 'Test'}) # when with self.captured_headers() as headers: client._notify.ping() # then self.assertTrue('x-my-header' in headers) self.assertEqual(headers['x-my-header'], 'Test') def test_should_override_headers(self): # given client = jsonrpclib.ServerProxy('http://localhost:{0}'.format( self.port), verbose=1, headers={ 'User-Agent': 'jsonrpclib test', 'Host': 'example.com' }) # when with self.captured_headers(False) as headers: response = client.ping() self.assertTrue(response) # then self.assertEqual(headers['user-agent'], 'jsonrpclib test') self.assertEqual(headers['host'], 'example.com') def test_should_not_override_content_length(self): # given client = jsonrpclib.ServerProxy( 'http://localhost:{0}'.format(self.port), verbose=1, headers={'Content-Length': 'invalid value'}) # when with self.captured_headers() as headers: response = client.ping() self.assertTrue(response) # then self.assertTrue('content-length' in headers) self.assertNotEqual(headers['content-length'], 'invalid value') def test_should_convert_header_values_to_basestring(self): # given client = jsonrpclib.ServerProxy('http://localhost:{0}'.format( self.port), verbose=1, headers={'X-Test': 123}) # when with self.captured_headers() as headers: response = client.ping() self.assertTrue(response) # then self.assertTrue('x-test' in headers) self.assertEqual(headers['x-test'], '123') def test_should_add_custom_headers_to_methods(self): # given client = jsonrpclib.ServerProxy('http://localhost:{0}'.format( self.port), verbose=1) # when with self.captured_headers() as headers: with client._additional_headers({'X-Method': 'Method'}) as cl: response = cl.ping() self.assertTrue(response) # then self.assertTrue('x-method' in headers) self.assertEqual(headers['x-method'], 'Method') def test_should_override_global_headers(self): # given client = jsonrpclib.ServerProxy('http://localhost:{0}'.format( self.port), verbose=1, headers={'X-Test': 'Global'}) # when with self.captured_headers() as headers: with client._additional_headers({'X-Test': 'Method'}) as cl: response = cl.ping() self.assertTrue(response) # then self.assertTrue('x-test' in headers) self.assertEqual(headers['x-test'], 'Method') def test_should_restore_global_headers(self): # given client = jsonrpclib.ServerProxy('http://localhost:{0}'.format( self.port), verbose=1, headers={'X-Test': 'Global'}) # when with self.captured_headers() as headers: with client._additional_headers({'X-Test': 'Method'}) as cl: response = cl.ping() self.assertTrue(response) self.assertTrue('x-test' in headers) self.assertEqual(headers['x-test'], 'Method') with self.captured_headers() as headers: response = cl.ping() self.assertTrue(response) # then self.assertTrue('x-test' in headers) self.assertEqual(headers['x-test'], 'Global') def test_should_allow_to_nest_additional_header_blocks(self): # given client = jsonrpclib.ServerProxy('http://localhost:{0}'.format( self.port), verbose=1) # when with client._additional_headers({'X-Level-1': '1'}) as cl_level1: with self.captured_headers() as headers1: response = cl_level1.ping() self.assertTrue(response) with cl_level1._additional_headers({'X-Level-2': '2'}) as cl: with self.captured_headers() as headers2: response = cl.ping() self.assertTrue(response) # then self.assertTrue('x-level-1' in headers1) self.assertEqual(headers1['x-level-1'], '1') self.assertTrue('x-level-1' in headers2) self.assertEqual(headers1['x-level-1'], '1') self.assertTrue('x-level-2' in headers2) self.assertEqual(headers2['x-level-2'], '2')
class TestCompatibility(unittest.TestCase): """ Tests JSON-RPC compatibility """ def setUp(self): """ Pre-test set up """ # Set up the server self.server = UtilityServer().start('', 0) self.port = self.server.get_port() # Set up the client self.history = jsonrpclib.history.History() self.client = jsonrpclib.ServerProxy('http://localhost:{0}'.format( self.port), history=self.history) def tearDown(self): """ Post-test clean up """ # Close the client self.client("close")() # Stop the server self.server.stop() # Version 2.0 Tests def test_positional(self): """ Positional arguments in a single call """ result = self.client.subtract(23, 42) self.assertTrue(result == -19) result = self.client.subtract(42, 23) self.assertTrue(result == 19) request = json.loads(self.history.request) response = json.loads(self.history.response) verify_request = { "jsonrpc": "2.0", "method": "subtract", "params": [42, 23], "id": request['id'] } verify_response = {"jsonrpc": "2.0", "result": 19, "id": request['id']} self.assertTrue(request == verify_request) self.assertTrue(response == verify_response) def test_named(self): """ Named arguments in a single call """ result = self.client.subtract(subtrahend=23, minuend=42) self.assertTrue(result == 19) result = self.client.subtract(minuend=42, subtrahend=23) self.assertTrue(result == 19) request = json.loads(self.history.request) response = json.loads(self.history.response) verify_request = { "jsonrpc": "2.0", "method": "subtract", "params": { "subtrahend": 23, "minuend": 42 }, "id": request['id'] } verify_response = {"jsonrpc": "2.0", "result": 19, "id": request['id']} self.assertTrue(request == verify_request) self.assertTrue(response == verify_response) def test_notification(self): """ Testing a notification (response should be null) """ result = self.client._notify.update(1, 2, 3, 4, 5) self.assertTrue(result is None) request = json.loads(self.history.request) response = self.history.response verify_request = { "jsonrpc": "2.0", "method": "update", "params": [1, 2, 3, 4, 5] } verify_response = '' self.assertTrue(request == verify_request) self.assertTrue(response == verify_response) def test_non_existent_method(self): self.assertRaises(jsonrpclib.ProtocolError, self.client.foobar) request = json.loads(self.history.request) response = json.loads(self.history.response) verify_request = { "jsonrpc": "2.0", "method": "foobar", "id": request['id'] } verify_response = { "jsonrpc": "2.0", "error": { "code": -32601, "message": response['error']['message'] }, "id": request['id'] } self.assertTrue(request == verify_request) self.assertTrue(response == verify_response) def test_special_method(self): self.assertRaises(AttributeError, getattr, self.client, '__special_method__') self.assertIsNone(self.history.request) def test_invalid_json(self): invalid_json = '{"jsonrpc": "2.0", "method": "foobar, ' + \ '"params": "bar", "baz]' self.client._run_request(invalid_json) response = json.loads(self.history.response) verify_response = json.loads( '{"jsonrpc": "2.0", "error": {"code": -32700,' + ' "message": "Parse error."}, "id": null}') verify_response['error']['message'] = response['error']['message'] self.assertTrue(response == verify_response) def test_invalid_request(self): invalid_request = '{"jsonrpc": "2.0", "method": 1, "params": "bar"}' self.client._run_request(invalid_request) response = json.loads(self.history.response) verify_response = json.loads( '{"jsonrpc": "2.0", "error": {"code": -32600, ' + '"message": "Invalid Request."}, "id": null}') verify_response['error']['message'] = response['error']['message'] self.assertTrue(response == verify_response) def test_batch_invalid_json(self): invalid_request = '[ {"jsonrpc": "2.0", "method": "sum", ' + \ '"params": [1,2,4], "id": "1"},{"jsonrpc": "2.0", "method" ]' self.client._run_request(invalid_request) response = json.loads(self.history.response) verify_response = json.loads( '{"jsonrpc": "2.0", "error": {"code": -32700,' + '"message": "Parse error."}, "id": null}') verify_response['error']['message'] = response['error']['message'] self.assertTrue(response == verify_response) def test_empty_array(self): invalid_request = '[]' self.client._run_request(invalid_request) response = json.loads(self.history.response) verify_response = json.loads( '{"jsonrpc": "2.0", "error": {"code": -32600, ' + '"message": "Invalid Request."}, "id": null}') verify_response['error']['message'] = response['error']['message'] self.assertTrue(response == verify_response) def test_nonempty_array(self): invalid_request = '[1,2]' request_obj = json.loads(invalid_request) self.client._run_request(invalid_request) response = json.loads(self.history.response) self.assertTrue(len(response) == len(request_obj)) for resp in response: verify_resp = json.loads( '{"jsonrpc": "2.0", "error": {"code": -32600, ' + '"message": "Invalid Request."}, "id": null}') verify_resp['error']['message'] = resp['error']['message'] self.assertTrue(resp == verify_resp) def test_batch(self): multicall = jsonrpclib.MultiCall(self.client) multicall.sum(1, 2, 4) multicall._notify.notify_hello(7) multicall.subtract(42, 23) multicall.foo.get(name='myself') multicall.get_data() job_requests = [j.request() for j in multicall._job_list] job_requests.insert(3, '{"foo": "boo"}') json_requests = '[%s]' % ','.join(job_requests) requests = json.loads(json_requests) responses = self.client._run_request(json_requests) verify_requests = json.loads("""[ {"jsonrpc": "2.0", "method": "sum", "params": [1,2,4], "id": "1"}, {"jsonrpc": "2.0", "method": "notify_hello", "params": [7]}, {"jsonrpc": "2.0", "method": "subtract", "params": [42,23], "id": "2"}, {"foo": "boo"}, {"jsonrpc": "2.0", "method": "foo.get", "params": {"name": "myself"}, "id": "5"}, {"jsonrpc": "2.0", "method": "get_data", "id": "9"} ]""") # Thankfully, these are in order so testing is pretty simple. verify_responses = json.loads("""[ {"jsonrpc": "2.0", "result": 7, "id": "1"}, {"jsonrpc": "2.0", "result": 19, "id": "2"}, {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request."}, "id": null}, {"jsonrpc": "2.0", "error": {"code": -32601, "message": "Method not found."}, "id": "5"}, {"jsonrpc": "2.0", "result": ["hello", 5], "id": "9"} ]""") self.assertTrue(len(requests) == len(verify_requests)) self.assertTrue(len(responses) == len(verify_responses)) responses_by_id = {} response_i = 0 for i in range(len(requests)): verify_request = verify_requests[i] request = requests[i] response = None if request.get('method') != 'notify_hello': req_id = request.get('id') if 'id' in verify_request: verify_request['id'] = req_id verify_response = verify_responses[response_i] verify_response['id'] = req_id responses_by_id[req_id] = verify_response response_i += 1 response = verify_response self.assertTrue(request == verify_request) for response in responses: verify_response = responses_by_id.get(response.get('id')) if 'error' in verify_response: verify_response['error']['message'] = \ response['error']['message'] self.assertTrue(response == verify_response) def test_batch_notifications(self): multicall = jsonrpclib.MultiCall(self.client) multicall._notify.notify_sum(1, 2, 4) multicall._notify.notify_hello(7) result = multicall() self.assertTrue(len(result) == 0) valid_request = json.loads( '[{"jsonrpc": "2.0", "method": "notify_sum", ' + '"params": [1,2,4]},{"jsonrpc": "2.0", ' + '"method": "notify_hello", "params": [7]}]') request = json.loads(self.history.request) self.assertTrue(len(request) == len(valid_request)) for i in range(len(request)): req = request[i] valid_req = valid_request[i] self.assertTrue(req == valid_req) self.assertTrue(self.history.response == '')
class HeadersTests(unittest.TestCase): """ These tests verify functionality of additional headers. """ REQUEST_LINE = "^send: POST" def setUp(self): """ Sets up the test """ # Set up the server self.server = UtilityServer().start('', 0) self.port = self.server.get_port() def tearDown(self): """ Post-test clean up """ # Stop the server self.server.stop() @contextlib.contextmanager def captured_headers(self): """ Captures the request headers. Yields the {header : value} dictionary, where keys are in lower case. """ # Redirect the standard output, to catch jsonrpclib verbose messages stdout = sys.stdout sys.stdout = f = StringIO() headers = {} yield headers sys.stdout = stdout # Extract the sent request content request_lines = f.getvalue().splitlines() request_lines = list(filter(lambda l: l.startswith("send:"), request_lines)) request_line = request_lines[0].split("send: ")[-1] # Convert it to a string try: # Use eval to convert the representation into a string request_line = from_bytes(eval(request_line)) except: # Keep the received version pass # Extract headers raw_headers = request_line.splitlines()[1:-1] raw_headers = map(lambda h: re.split(r":\s?", h, 1), raw_headers) for header, value in raw_headers: headers[header.lower()] = value def test_should_extract_headers(self): # given client = jsonrpclib.ServerProxy('http://localhost:{0}' .format(self.port), verbose=1) # when with self.captured_headers() as headers: response = client.ping() self.assertTrue(response) # then self.assertTrue(len(headers) > 0) self.assertTrue('content-type' in headers) self.assertEqual(headers['content-type'], 'application/json-rpc') def test_should_add_additional_headers(self): # given client = jsonrpclib.ServerProxy( 'http://localhost:{0}'.format(self.port), verbose=1, headers={'X-My-Header': 'Test'}) # when with self.captured_headers() as headers: response = client.ping() self.assertTrue(response) # then self.assertTrue('x-my-header' in headers) self.assertEqual(headers['x-my-header'], 'Test') def test_should_add_additional_headers_to_notifications(self): # given client = jsonrpclib.ServerProxy( 'http://localhost:{0}'.format(self.port), verbose=1, headers={'X-My-Header': 'Test'}) # when with self.captured_headers() as headers: client._notify.ping() # then self.assertTrue('x-my-header' in headers) self.assertEqual(headers['x-my-header'], 'Test') def test_should_override_headers(self): # given client = jsonrpclib.ServerProxy( 'http://localhost:{0}'.format(self.port), verbose=1, headers={'User-Agent': 'jsonrpclib test', 'Host': 'example.com'}) # when with self.captured_headers() as headers: response = client.ping() self.assertTrue(response) # then self.assertEqual(headers['user-agent'], 'jsonrpclib test') self.assertEqual(headers['host'], 'example.com') def test_should_not_override_content_length(self): # given client = jsonrpclib.ServerProxy( 'http://localhost:{0}'.format(self.port), verbose=1, headers={'Content-Length': 'invalid value'}) # when with self.captured_headers() as headers: response = client.ping() self.assertTrue(response) # then self.assertTrue('content-length' in headers) self.assertNotEqual(headers['content-length'], 'invalid value') def test_should_convert_header_values_to_basestring(self): # given client = jsonrpclib.ServerProxy( 'http://localhost:{0}'.format(self.port), verbose=1, headers={'X-Test': 123}) # when with self.captured_headers() as headers: response = client.ping() self.assertTrue(response) # then self.assertTrue('x-test' in headers) self.assertEqual(headers['x-test'], '123') def test_should_add_custom_headers_to_methods(self): # given client = jsonrpclib.ServerProxy('http://localhost:{0}' .format(self.port), verbose=1) # when with self.captured_headers() as headers: with client._additional_headers({'X-Method': 'Method'}) as cl: response = cl.ping() self.assertTrue(response) # then self.assertTrue('x-method' in headers) self.assertEqual(headers['x-method'], 'Method') def test_should_override_global_headers(self): # given client = jsonrpclib.ServerProxy( 'http://localhost:{0}'.format(self.port), verbose=1, headers={'X-Test': 'Global'}) # when with self.captured_headers() as headers: with client._additional_headers({'X-Test': 'Method'}) as cl: response = cl.ping() self.assertTrue(response) # then self.assertTrue('x-test' in headers) self.assertEqual(headers['x-test'], 'Method') def test_should_restore_global_headers(self): # given client = jsonrpclib.ServerProxy( 'http://localhost:{0}'.format(self.port), verbose=1, headers={'X-Test': 'Global'}) # when with self.captured_headers() as headers: with client._additional_headers({'X-Test': 'Method'}) as cl: response = cl.ping() self.assertTrue(response) self.assertTrue('x-test' in headers) self.assertEqual(headers['x-test'], 'Method') with self.captured_headers() as headers: response = cl.ping() self.assertTrue(response) # then self.assertTrue('x-test' in headers) self.assertEqual(headers['x-test'], 'Global') def test_should_allow_to_nest_additional_header_blocks(self): # given client = jsonrpclib.ServerProxy('http://localhost:{0}' .format(self.port), verbose=1) # when with client._additional_headers({'X-Level-1': '1'}) as cl_level1: with self.captured_headers() as headers1: response = cl_level1.ping() self.assertTrue(response) with cl_level1._additional_headers({'X-Level-2': '2'}) as cl: with self.captured_headers() as headers2: response = cl.ping() self.assertTrue(response) # then self.assertTrue('x-level-1' in headers1) self.assertEqual(headers1['x-level-1'], '1') self.assertTrue('x-level-1' in headers2) self.assertEqual(headers1['x-level-1'], '1') self.assertTrue('x-level-2' in headers2) self.assertEqual(headers2['x-level-2'], '2')
class TestCompatibility(unittest.TestCase): """ Tests JSON-RPC compatibility """ def setUp(self): """ Pre-test set up """ # Set up the server self.server = UtilityServer().start('', 0) self.port = self.server.get_port() # Set up the client self.history = jsonrpclib.history.History() self.client = jsonrpclib.ServerProxy( 'http://localhost:{0}'.format(self.port), history=self.history) def tearDown(self): """ Post-test clean up """ # Close the client self.client("close")() # Stop the server self.server.stop() # Version 2.0 Tests def test_positional(self): """ Positional arguments in a single call """ result = self.client.subtract(23, 42) self.assertTrue(result == -19) result = self.client.subtract(42, 23) self.assertTrue(result == 19) request = json.loads(self.history.request) response = json.loads(self.history.response) verify_request = { "jsonrpc": "2.0", "method": "subtract", "params": [42, 23], "id": request['id'] } verify_response = { "jsonrpc": "2.0", "result": 19, "id": request['id'] } self.assertTrue(request == verify_request) self.assertTrue(response == verify_response) def test_named(self): """ Named arguments in a single call """ result = self.client.subtract(subtrahend=23, minuend=42) self.assertTrue(result == 19) result = self.client.subtract(minuend=42, subtrahend=23) self.assertTrue(result == 19) request = json.loads(self.history.request) response = json.loads(self.history.response) verify_request = { "jsonrpc": "2.0", "method": "subtract", "params": {"subtrahend": 23, "minuend": 42}, "id": request['id'] } verify_response = { "jsonrpc": "2.0", "result": 19, "id": request['id'] } self.assertTrue(request == verify_request) self.assertTrue(response == verify_response) def test_notification(self): """ Testing a notification (response should be null) """ result = self.client._notify.update(1, 2, 3, 4, 5) self.assertTrue(result is None) request = json.loads(self.history.request) response = self.history.response verify_request = { "jsonrpc": "2.0", "method": "update", "params": [1, 2, 3, 4, 5] } verify_response = '' self.assertTrue(request == verify_request) self.assertTrue(response == verify_response) def test_non_existent_method(self): self.assertRaises(jsonrpclib.ProtocolError, self.client.foobar) request = json.loads(self.history.request) response = json.loads(self.history.response) verify_request = { "jsonrpc": "2.0", "method": "foobar", "id": request['id'] } verify_response = { "jsonrpc": "2.0", "error": {"code": -32601, "message": response['error']['message']}, "id": request['id'] } self.assertTrue(request == verify_request) self.assertTrue(response == verify_response) def test_invalid_json(self): invalid_json = '{"jsonrpc": "2.0", "method": "foobar, ' + \ '"params": "bar", "baz]' self.client._run_request(invalid_json) response = json.loads(self.history.response) verify_response = json.loads( '{"jsonrpc": "2.0", "error": {"code": -32700,' + ' "message": "Parse error."}, "id": null}' ) verify_response['error']['message'] = response['error']['message'] self.assertTrue(response == verify_response) def test_invalid_request(self): invalid_request = '{"jsonrpc": "2.0", "method": 1, "params": "bar"}' self.client._run_request(invalid_request) response = json.loads(self.history.response) verify_response = json.loads( '{"jsonrpc": "2.0", "error": {"code": -32600, ' + '"message": "Invalid Request."}, "id": null}' ) verify_response['error']['message'] = response['error']['message'] self.assertTrue(response == verify_response) def test_batch_invalid_json(self): invalid_request = '[ {"jsonrpc": "2.0", "method": "sum", ' + \ '"params": [1,2,4], "id": "1"},{"jsonrpc": "2.0", "method" ]' self.client._run_request(invalid_request) response = json.loads(self.history.response) verify_response = json.loads( '{"jsonrpc": "2.0", "error": {"code": -32700,' + '"message": "Parse error."}, "id": null}' ) verify_response['error']['message'] = response['error']['message'] self.assertTrue(response == verify_response) def test_empty_array(self): invalid_request = '[]' self.client._run_request(invalid_request) response = json.loads(self.history.response) verify_response = json.loads( '{"jsonrpc": "2.0", "error": {"code": -32600, ' + '"message": "Invalid Request."}, "id": null}' ) verify_response['error']['message'] = response['error']['message'] self.assertTrue(response == verify_response) def test_nonempty_array(self): invalid_request = '[1,2]' request_obj = json.loads(invalid_request) self.client._run_request(invalid_request) response = json.loads(self.history.response) self.assertTrue(len(response) == len(request_obj)) for resp in response: verify_resp = json.loads( '{"jsonrpc": "2.0", "error": {"code": -32600, ' + '"message": "Invalid Request."}, "id": null}' ) verify_resp['error']['message'] = resp['error']['message'] self.assertTrue(resp == verify_resp) def test_batch(self): multicall = jsonrpclib.MultiCall(self.client) multicall.sum(1, 2, 4) multicall._notify.notify_hello(7) multicall.subtract(42, 23) multicall.foo.get(name='myself') multicall.get_data() job_requests = [j.request() for j in multicall._job_list] job_requests.insert(3, '{"foo": "boo"}') json_requests = '[%s]' % ','.join(job_requests) requests = json.loads(json_requests) responses = self.client._run_request(json_requests) verify_requests = json.loads("""[ {"jsonrpc": "2.0", "method": "sum", "params": [1,2,4], "id": "1"}, {"jsonrpc": "2.0", "method": "notify_hello", "params": [7]}, {"jsonrpc": "2.0", "method": "subtract", "params": [42,23], "id": "2"}, {"foo": "boo"}, {"jsonrpc": "2.0", "method": "foo.get", "params": {"name": "myself"}, "id": "5"}, {"jsonrpc": "2.0", "method": "get_data", "id": "9"} ]""") # Thankfully, these are in order so testing is pretty simple. verify_responses = json.loads("""[ {"jsonrpc": "2.0", "result": 7, "id": "1"}, {"jsonrpc": "2.0", "result": 19, "id": "2"}, {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request."}, "id": null}, {"jsonrpc": "2.0", "error": {"code": -32601, "message": "Method not found."}, "id": "5"}, {"jsonrpc": "2.0", "result": ["hello", 5], "id": "9"} ]""") self.assertTrue(len(requests) == len(verify_requests)) self.assertTrue(len(responses) == len(verify_responses)) responses_by_id = {} response_i = 0 for i in range(len(requests)): verify_request = verify_requests[i] request = requests[i] response = None if request.get('method') != 'notify_hello': req_id = request.get('id') if 'id' in verify_request: verify_request['id'] = req_id verify_response = verify_responses[response_i] verify_response['id'] = req_id responses_by_id[req_id] = verify_response response_i += 1 response = verify_response self.assertTrue(request == verify_request) for response in responses: verify_response = responses_by_id.get(response.get('id')) if 'error' in verify_response: verify_response['error']['message'] = \ response['error']['message'] self.assertTrue(response == verify_response) def test_batch_notifications(self): multicall = jsonrpclib.MultiCall(self.client) multicall._notify.notify_sum(1, 2, 4) multicall._notify.notify_hello(7) result = multicall() self.assertTrue(len(result) == 0) valid_request = json.loads( '[{"jsonrpc": "2.0", "method": "notify_sum", ' + '"params": [1,2,4]},{"jsonrpc": "2.0", ' + '"method": "notify_hello", "params": [7]}]' ) request = json.loads(self.history.request) self.assertTrue(len(request) == len(valid_request)) for i in range(len(request)): req = request[i] valid_req = valid_request[i] self.assertTrue(req == valid_req) self.assertTrue(self.history.response == '')
class HeadersTests(unittest.TestCase): """ These tests verify functionality of additional headers. """ REQUEST_LINE = "^send: POST" def setUp(self): """ Sets up the test """ # Set up the server self.server = UtilityServer().start("", 0) self.port = self.server.get_port() def tearDown(self): """ Post-test clean up """ # Stop the server self.server.stop() @contextlib.contextmanager def captured_headers(self, check_duplicates=True): """ Captures the request headers. Yields the {header : value} dictionary, where keys are in lower case. :param check_duplicates: If True, raises an error if a header appears twice """ # Redirect the standard output, to catch jsonrpclib verbose messages stdout = sys.stdout sys.stdout = f = StringIO() headers = {} yield headers sys.stdout = stdout # Extract the sent request content request_lines = f.getvalue().splitlines() request_lines = list( filter(lambda l: l.startswith("send:"), request_lines)) request_line = request_lines[0].split("send: ")[-1] # Convert it to a string try: # Use eval to convert the representation into a string request_line = from_bytes(eval(request_line)) except: # Keep the received version pass # Extract headers raw_headers = request_line.splitlines()[1:-1] raw_headers = map(lambda h: re.split(r":\s?", h, 1), raw_headers) for header, value in raw_headers: header = header.lower() if check_duplicates and header in headers: raise KeyError("Header defined twice: {0}".format(header)) headers[header] = value def test_should_extract_headers(self): """ Check client headers capture """ # given client = jsonrpclib.ServerProxy("http://localhost:{0}".format( self.port), verbose=1) # when with self.captured_headers() as headers: response = client.ping() self.assertTrue(response) # then self.assertTrue(len(headers) > 0) self.assertTrue("content-type" in headers) self.assertEqual(headers["content-type"], "application/json-rpc") def test_should_add_additional_headers(self): """ Check sending of custom headers """ # given client = jsonrpclib.ServerProxy( "http://localhost:{0}".format(self.port), verbose=1, headers={"X-My-Header": "Test"}, ) # when with self.captured_headers() as headers: response = client.ping() self.assertTrue(response) # then self.assertTrue("x-my-header" in headers) self.assertEqual(headers["x-my-header"], "Test") def test_should_add_additional_headers_to_notifications(self): """ Check custom headers on notifications """ # given client = jsonrpclib.ServerProxy( "http://localhost:{0}".format(self.port), verbose=1, headers={"X-My-Header": "Test"}, ) # when with self.captured_headers() as headers: client._notify.ping() # then self.assertTrue("x-my-header" in headers) self.assertEqual(headers["x-my-header"], "Test") def test_should_override_headers(self): """ Custom headers must override default ones """ # given client = jsonrpclib.ServerProxy( "http://localhost:{0}".format(self.port), verbose=1, headers={ "User-Agent": "jsonrpclib test", "Host": "example.com" }, ) # when with self.captured_headers(False) as headers: response = client.ping() self.assertTrue(response) # then self.assertEqual(headers["user-agent"], "jsonrpclib test") self.assertEqual(headers["host"], "example.com") def test_should_not_override_content_length(self): """ Custom headers can't override Content-Length """ # given client = jsonrpclib.ServerProxy( "http://localhost:{0}".format(self.port), verbose=1, headers={"Content-Length": "invalid value"}, ) # when with self.captured_headers() as headers: response = client.ping() self.assertTrue(response) # then self.assertTrue("content-length" in headers) self.assertNotEqual(headers["content-length"], "invalid value") def test_should_convert_header_values_to_basestring(self): """ Custom headers values should be converted to str """ # given client = jsonrpclib.ServerProxy( "http://localhost:{0}".format(self.port), verbose=1, headers={"X-Test": 123}, ) # when with self.captured_headers() as headers: response = client.ping() self.assertTrue(response) # then self.assertTrue("x-test" in headers) self.assertEqual(headers["x-test"], "123") def test_should_add_custom_headers_to_methods(self): """ Check method-based custom headers """ # given client = jsonrpclib.ServerProxy("http://localhost:{0}".format( self.port), verbose=1) # when with self.captured_headers() as headers: with client._additional_headers({"X-Method": "Method"}) as cl: response = cl.ping() self.assertTrue(response) # then self.assertTrue("x-method" in headers) self.assertEqual(headers["x-method"], "Method") def test_should_override_global_headers(self): """ Method-based custom headers override context ones """ # given client = jsonrpclib.ServerProxy( "http://localhost:{0}".format(self.port), verbose=1, headers={"X-Test": "Global"}, ) # when with self.captured_headers() as headers: with client._additional_headers({"X-Test": "Method"}) as cl: response = cl.ping() self.assertTrue(response) # then self.assertTrue("x-test" in headers) self.assertEqual(headers["x-test"], "Method") def test_should_restore_global_headers(self): """ Check custom headers context clean up """ # given client = jsonrpclib.ServerProxy( "http://localhost:{0}".format(self.port), verbose=1, headers={"X-Test": "Global"}, ) # when with self.captured_headers() as headers: with client._additional_headers({"X-Test": "Method"}) as cl: response = cl.ping() self.assertTrue(response) self.assertTrue("x-test" in headers) self.assertEqual(headers["x-test"], "Method") with self.captured_headers() as headers: response = cl.ping() self.assertTrue(response) # then self.assertTrue("x-test" in headers) self.assertEqual(headers["x-test"], "Global") def test_should_allow_to_nest_additional_header_blocks(self): """ Check nested additional headers """ # given client = jsonrpclib.ServerProxy("http://localhost:{0}".format( self.port), verbose=1) # when with client._additional_headers({"X-Level-1": "1"}) as cl_level1: with self.captured_headers() as headers1: response = cl_level1.ping() self.assertTrue(response) with cl_level1._additional_headers({"X-Level-2": "2"}) as cl: with self.captured_headers() as headers2: response = cl.ping() self.assertTrue(response) # then self.assertTrue("x-level-1" in headers1) self.assertEqual(headers1["x-level-1"], "1") self.assertTrue("x-level-1" in headers2) self.assertEqual(headers1["x-level-1"], "1") self.assertTrue("x-level-2" in headers2) self.assertEqual(headers2["x-level-2"], "2")
class InternalTests(unittest.TestCase): """ These tests verify that the client and server portions of jsonrpclib talk to each other properly. """ def setUp(self): # Set up the server self.server = UtilityServer().start('', 0) self.port = self.server.get_port() # Prepare the client self.history = jsonrpclib.history.History() def tearDown(self): """ Post-test clean up """ # Stop the server self.server.stop() def get_client(self): """ Utility method to get a proxy to the test server """ return jsonrpclib.ServerProxy( "http://localhost:{0}".format(self.port), history=self.history ) def get_multicall_client(self): """ Utility method to get a multi-call proxy to the test server """ server = self.get_client() return jsonrpclib.MultiCall(server) def test_connect(self): """ Simple Ping() test """ client = self.get_client() result = client.ping() self.assertTrue(result) def test_single_args(self): """ Positional arguments test """ client = self.get_client() result = client.add(5, 10) self.assertTrue(result == 15) def test_single_kwargs(self): """ Keyword-arguments test """ client = self.get_client() result = client.add(x=5, y=10) self.assertTrue(result == 15) def test_single_kwargs_and_args(self): """ Mixed positional/keyword args failure test """ client = self.get_client() self.assertRaises(jsonrpclib.ProtocolError, client.add, (5,), {'y': 10}) def test_single_notify(self): """ Notification test """ client = self.get_client() result = client._notify.add(5, 10) self.assertTrue(result is None) def test_single_namespace(self): """ Namespace test """ client = self.get_client() client.namespace.sum(1, 2, 4) request = json.loads(self.history.request) response = json.loads(self.history.response) verify_request = { "jsonrpc": "2.0", "params": [1, 2, 4], "id": "5", "method": "namespace.sum" } verify_response = {"jsonrpc": "2.0", "result": 7, "id": request['id']} verify_request['id'] = request['id'] self.assertTrue(verify_request == request) self.assertTrue(verify_response == response) def test_exception(self): """ Tests the call to a method that will fail """ client = self.get_client() try: client.fail() except jsonrpclib.ProtocolError as ex: self.assertIn("ValueError", str(ex)) else: self.fail("Exception not raised") def test_multicall_success(self): """ Multi-call test """ multicall = self.get_multicall_client() multicall.ping() multicall.add(5, 10) multicall.namespace.sum(5, 10, 15) correct = [True, 15, 30] for i, result in enumerate(multicall()): self.assertTrue(result == correct[i]) def test_multicall_success_2(self): """ Another multi-call test """ multicall = self.get_multicall_client() for i in range(3): multicall.add(5, i) result = multicall() self.assertTrue(result[2] == 7) def test_multicall_failure(self): """ Multi-call test with failures """ multicall = self.get_multicall_client() multicall.ping() multicall.add(x=5, y=10, z=10) raises = [None, jsonrpclib.ProtocolError] result = multicall() for i in range(2): if not raises[i]: result[i] else: def func(): return result[i] self.assertRaises(raises[i], func)