def test_json_rpc_response_positive(self): err_responses = [ # message / data is optional ('{"jsonrpc": "2.0", "error": {"code": -32600}, "id": null}', JsonRpc20Error.INVALID_REQUEST), # data is primitive / structured ('{"jsonrpc": "2.0", "error": {"code": -32600, "data": "somedata"}, "id": null}', JsonRpc20Error.INVALID_REQUEST), ('{"jsonrpc": "2.0", "error": {"code": -32600, "data": {"key": "somedata"}}, "id": null}', JsonRpc20Error.INVALID_REQUEST), ('{"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request."}, "id": null}', JsonRpc20Error.INVALID_REQUEST), ('{"jsonrpc": "2.0", "error": {"code": -32700, "message": "Parse error."}, "id": null}', JsonRpc20Error.PARSE_ERROR), ('{"jsonrpc": "2.0", "error": {"code": -32601, "message": "Method not found."}, "id": "1"}', JsonRpc20Error.METHOD_NOT_FOUND), ('{"jsonrpc": "2.0", "error": {"code": -32602, "message": "Invalid params."}, "id": "1"}', JsonRpc20Error.INVALID_PARAMS), ('{"jsonrpc": "2.0", "error": {"code": -32603, "message": "Internal error."}, "id": 1}', JsonRpc20Error.INTERNAL_ERROR), ] for response_str, error_code in err_responses: response = deserialize_response(response_str) self.assertTrue(response.error.code == error_code) response.serialize()
def test_json_rpc_positive(self): requests = [ # id can be null, number, string, or omitted ('{"jsonrpc": "2.0", "method": "subtract", "id": null}', None), ('{"jsonrpc": "2.0", "method": "subtract", "id": 3}', '{"jsonrpc": "2.0", "result": 0, "id": 3}'), ('{"jsonrpc": "2.0", "method": "subtract", "id": "string_id"}', '{"jsonrpc": "2.0", "result": 0, "id": "string_id"}'), # Accept keyed parameters. Do not accept array parameters ('{"jsonrpc": "2.0", "method": "subtract", "params": {"subtrahend": 23, "minuend": 42}, "id": 3}', '{"jsonrpc": "2.0", "result": 19, "id": 3}'), ] for request_str, response_str in requests: request = deserialize_request(request_str) self.assertFalse(request.notification) if response_str: response = deserialize_response(response_str) request.validate_response(response) request.serialize() notifications = [ '{"jsonrpc": "2.0", "method": "subtract"}', ] for notification_str in notifications: request = deserialize_request(notification_str) self.assertTrue(request.notification) request.serialize_notification()
def test_json_rpc_response_negative(self): responses = [ ('', JsonRpc20Error.PARSE_ERROR), ('sjlfskfdl', JsonRpc20Error.PARSE_ERROR), ('{"jsonrpc": "2.0", "result": "foobar, "error": "bar"}', JsonRpc20Error.PARSE_ERROR), ('{"jsonrpc": "2.0", "result": "foobar, "error": "bar", "id": null}', JsonRpc20Error.PARSE_ERROR), ('{"jsonrpc": "2.0", "result": "foobar, "error": {"code": -32603}, "id": null}', JsonRpc20Error.PARSE_ERROR), ('{"result": 19, "id": 3}', JsonRpc20Error.INVALID_PARAMS), ] for response_str, error_code in responses: try: logging.info("response str: %s", response_str) deserialize_response(response_str) self.assertTrue(False) except JsonRpc20Error as err: logging.info("err: %s", str(err)) self.assertTrue(err.code == error_code)
def test_json_rpc_request_negative(self): requests = [ ('', JsonRpc20Error.PARSE_ERROR), ('sjlfskfdl', JsonRpc20Error.PARSE_ERROR), ('{"jsonrpc": "2.0", "method": "foobar, "params": "bar", "baz"]', JsonRpc20Error.PARSE_ERROR), ('{"jsonrpc": "2.0", "method": 1, "params": "bar"}', JsonRpc20Error.INVALID_REQUEST), ('{"jsonrpc": "2.0", "method": "a_method", "params": "bar"}', JsonRpc20Error.INVALID_REQUEST), ] for request_str, error_code in requests: try: logging.info("request str: %s", request_str) deserialize_request(request_str) self.assertTrue(False) except JsonRpc20Error as err: logging.info("err: %s", str(err)) self.assertTrue(err.code == error_code) # Negative validate test requests = [ # Mismatch version ('{"jsonrpc": "2.0", "method": "subtract", "params": {"subtrahend": 23, "minuend": 42}, "id": 3}', '{"version": "1.1", "result": 19, "id": 3}', JsonRpc20Error.INVALID_PARAMS), # Mismatch id ('{"jsonrpc": "2.0", "method": "subtract", "params": {"subtrahend": 23, "minuend": 42}, "id": 3}', '{"jsonrpc": "2.0", "result": 19, "id": 4}', JsonRpc20Error.INVALID_PARAMS), # Mismatch id type ('{"jsonrpc": "2.0", "method": "subtract", "params": {"subtrahend": 23, "minuend": 42}, "id": 3}', '{"jsonrpc": "2.0", "result": 19, "id": "3"}', JsonRpc20Error.INVALID_PARAMS), # Notification should have no response ('{"jsonrpc": "2.0", "method": "subtract"}', '{"jsonrpc": "2.0", "result": 0}', JsonRpc20Error.INVALID_PARAMS), ] for request_str, response_str, error_code in requests: request = deserialize_request(request_str) if response_str: try: response = deserialize_response(response_str) except JsonRpc20Error as err: self.assertTrue(err.code == error_code) continue try: request.validate_response(response) self.assertTrue(False) except JsonRpc20Error as err: logging.info("err: %s", str(err)) self.assertTrue(err.code == error_code)
def _do_request(self, method, params=None): """ Perform json rpc request :type method: :class:`str` :param method: json rpc method name :type params: :class:`dict` or None :param params: json rpc method params :rtype: :class:`vmware.vapi.data.serializer.jsonrpc.JsonRpcResponse` :return: json rpc response """ logger.debug('_do_request: request %s', method) if not self.http_provider.connect(): logger.error('Connection refused') raise vapi_jsonrpc_error_transport_error() request_headers = {'Content-Type': 'application/json'} id_ = six.advance_iterator(self.counter) # atomic increment id_ = str(id_) # TODO: Bypass java barf temporary request = vapi_jsonrpc_request_factory(method=method, params=params, id=id_) request_body = request.serialize() if six.text_type: request_body = request_body.encode('utf-8') for processor in self.post_processors: request_body = processor.process(request_body) request_logger.debug('_do_request: request %s', request_body) # do_request returns http_response http_response = self.http_provider.do_request( HTTPRequest(method=HTTPMethod.POST, url_path=None, headers=request_headers, body=request_body)) if http_response.data is not None: # Currently only RequestsProvider returns the requests Response # object as data back. We need to raise exception if error is # returned to keep existing behavior. http_response.data.raise_for_status() request_logger.debug('_do_request: response %s', http_response.body) response = deserialize_response(http_response.body) request.validate_response(response) if response.error is not None: logger.error('_do_request: method %s response with error %s', method, response.error) raise response.error # pylint: disable=E0702 return response
def test_decimal_json_request(self): ctx = ExecutionContext() template_request = ( '{"params":{"input":%s,"serviceId":"mock","ctx":{"appCtx":{}},' + '"operationId":"mock"},"jsonrpc":' + '"2.0","method":"invoke","id":1}' ) template_response = ( '{"jsonrpc":"2.0","id":1,"result":{"output": %s}}' ) for val, canonical_val in [ ('-12.34e4', '-1.234E5'), ('1E-130', '1.0E-130'), ('0.0E-0', '0.0E0'), ('1.2', '1.2E0'), ('1111111.1111100021e-30', '1.1111111111100021E-24'), ('12312423.0', '1.2312423E7'), ('0.000234E-10', '2.34E-14'), ('17', '1.7E1')]: decimal_val = decimal.Decimal(val) canonical_decimal_val = canonicalize_double(decimal_val) data_value = DoubleValue(decimal_val) params = { 'ctx': ctx, 'serviceId': 'mock', 'operationId': 'mock', 'input': data_value } actual_request = vapi_jsonrpc_request_factory( method=VAPI_INVOKE, params=params, id=1).serialize() expected_request = template_request % canonical_decimal_val self.assertEqual( json.loads(actual_request, parse_float=decimal.Decimal), json.loads(expected_request, parse_float=decimal.Decimal)) response_msg = template_response % canonical_val response = deserialize_response(response_msg) method_result = JsonRpcDictToVapi.method_result(response.result) self.assertTrue(method_result.success()) self.assertTrue(isinstance(method_result.output, DoubleValue)) self.assertEqual(method_result.output, DoubleValue(decimal.Decimal(canonical_val)))
def test_json_handle_request_negative(self): protocol_handler = get_protocol_handler(self.provider) rpc_provider = LocalRpcProvider(protocol_handler) rpc_provider.connect() id_ = 12 requests = [ (vapi_jsonrpc_request_factory(method="bogus", params=None, id=id_), JsonRpc20Error.METHOD_NOT_FOUND), (vapi_jsonrpc_request_factory(method=VAPI_INVOKE, params={"bogus": 12}, id=id_), JsonRpc20Error.INVALID_PARAMS), ] for request, error_code in requests: http_response = rpc_provider.do_request( HTTPRequest(method=HTTPMethod.POST, body=request.serialize())) response = deserialize_response(http_response.body) request.validate_response(response) error = response.error logging.info("error: %s", error) self.assertTrue(error) self.assertTrue(error.code == error_code)
def _do_request(self, method, ctx, params=None): """ Perform json rpc request :type method: :class:`str` :param method: json rpc method name :type ctx: :class:`vmware.vapi.core.ExecutionContext` :param ctx: execution context object :type params: :class:`dict` or None :param params: json rpc method params :rtype: :class:`vmware.vapi.data.serializer.jsonrpc.JsonRpcResponse` :return: json rpc response """ logger.debug('_do_request: request %s', method) if not self.http_provider.connect(): logger.error('Connection refused') raise vapi_jsonrpc_error_transport_error() request_headers = { HTTP_CONTENT_TYPE_HEADER: JSON_CONTENT_TYPE, HTTP_USER_AGENT_HEADER: get_user_agent() } id_ = six.advance_iterator(self.counter) # atomic increment id_ = str(id_) # TODO: Bypass java barf temporary request = vapi_jsonrpc_request_factory(method=method, params=params, id=id_) request_body = request.serialize() if six.text_type: request_body = request_body.encode('utf-8') for processor in self.post_processors: request_body = processor.process(request_body) request_logger.debug('_do_request: request %s', request_body) # do_request returns http_response http_response = self.http_provider.do_request( HTTPRequest(method=HTTPMethod.POST, url_path=None, headers=request_headers, body=request_body)) if http_response.data is not None: # Currently only RequestsProvider returns the requests Response # object as data back. We need to raise exception if error is # returned to keep existing behavior. http_response.data.raise_for_status() request_logger.debug('_do_request: response %s', http_response.body) if ctx.runtime_data is not None: response_extractor = ctx.runtime_data.get('response_extractor') if response_extractor is not None: response_extractor.set_http_status(http_response.status) response_extractor.set_http_headers(http_response.headers) response_extractor.set_http_body(http_response.body) response_extractor.set_http_method(HTTPMethod.POST) response_extractor.set_http_url(self.http_provider._base_url) # pylint: disable=protected-access response = deserialize_response(http_response.body) request.validate_response(response) if response.error is not None: logger.error('_do_request: method %s response with error %s', method, response.error) raise response.error # pylint: disable=E0702 return response