class TestJsonRpc(unittest.TestCase): def setUp(self): """ setup """ self.to_vapi = JsonRpcDictToVapi api_iface = FakeInterface() self.provider = LocalProvider() self.provider.add_interface(api_iface) def tearDown(self): """ tear down """ def to_json(self, value): return json.dumps(value, check_circular=False, separators=(',', ':'), cls=VAPIJsonEncoder) def to_vapi_data_value(self, value): python_dict = json.loads(value, parse_float=decimal.Decimal) return self.to_vapi.data_value(python_dict) def to_vapi_method_result(self, value): python_dict = json.loads(value, parse_float=decimal.Decimal) return self.to_vapi.method_result(python_dict) def get_data_definition(self): # Get a cover all data definitions data_defs = [ VoidDefinition(), IntegerDefinition(), DoubleDefinition(), StringDefinition(), SecretDefinition(), BooleanDefinition(), BlobDefinition(), OpaqueDefinition(), OptionalDefinition(IntegerDefinition()), ListDefinition(IntegerDefinition()), StructDefinition('struct', [ ('int', IntegerDefinition()), ('str', StringDefinition()), ('struct', StructDefinition('struct1', [('double', DoubleDefinition()), ('secret', SecretDefinition())])), ('list', ListDefinition(StructDefinition('struct1', [('double', DoubleDefinition()), ('secret', SecretDefinition())]))), ('optional', ListDefinition(StructDefinition('struct1', [('double', DoubleDefinition()), ('secret', SecretDefinition())]))) ]), ErrorDefinition('error', [ ('int', IntegerDefinition()), ('str', StringDefinition()) ]), ] return data_defs def get_error_value(self): error_value = ErrorValue('struct0') error_value.set_field('int', IntegerValue(7)) error_value.set_field('optional', OptionalValue(StringValue("123"))) error_value.set_field('optional1', OptionalValue()) return error_value def get_struct_value(self): struct_value = StructValue('struct0') struct_value.set_field('int', IntegerValue(7)) struct_value.set_field('optional', OptionalValue(StringValue("123"))) struct_value.set_field('optional1', OptionalValue()) return struct_value def get_data_values(self): # Data values list_value = ListValue() list_value.add_all([IntegerValue(val) for val in range(1,15)]) data_values = [ VoidValue(), IntegerValue(3), DoubleValue(decimal.Decimal('7.2')), StringValue('blah'), SecretValue(), BooleanValue(True), BlobValue(b"a blob"), BlobValue(b"0\x82\x04\x00"), list_value, OptionalValue(), OptionalValue(IntegerValue(7)), StructValue('name'), self.get_struct_value(), self.get_error_value(), ] struct_value = StructValue('struct') for idx, data_val in enumerate(data_values): struct_value.set_field(str(idx), data_val) data_values.append(struct_value) return data_values def test_method_result(self): # Method result error_value = self.get_error_value() method_result = MethodResult(error=error_value) self.assertEqual(self.to_vapi_method_result(self.to_json(method_result)).error, method_result.error) data_values = self.get_data_values() for data_value in data_values: method_result = MethodResult(output=data_value) self.assertEqual(self.to_vapi_method_result(self.to_json(method_result)).output, method_result.output) def test_data_value_conversion(self): data_values = self.get_data_values() for data_value in data_values: json_value = self.to_json(data_value) self.assertEqual(self.to_vapi_data_value(json_value), data_value) json_value = self.to_json(DoubleValue(17.0)) self.assertEqual('1.7E1', json_value) vapi_value = self.to_vapi_data_value('1.7E1') self.assertEqual(DoubleValue(decimal.Decimal('1.7E1')), vapi_value) def test_jsonrpc_invalid_params_1(self): invalid_json = '{"STRUCTURE": {"vapi.struct": {}}, "bogus": "bogus"}' self.assertRaises(JsonRpc20Error, self.to_vapi_data_value, invalid_json) def test_jsonrpc_invalid_params_2(self): invalid_json = '{"STRUCTURE": {"vapi.struct": {}, "bogus": "bogus"}}' self.assertRaises(JsonRpc20Error, self.to_vapi_data_value, invalid_json) def test_jsonrpc_invalid_binary_value(self): invalid_json = '{"BINARY": "bogus"}' self.assertRaises(JsonRpc20Error, self.to_vapi_data_value, invalid_json) 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_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 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_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_error_factory(self): exceptions = [ (vapi_jsonrpc_error_parse_error, "testing", JsonRpc20Error.PARSE_ERROR), (vapi_jsonrpc_error_invalid_request, 3, JsonRpc20Error.INVALID_REQUEST), (vapi_jsonrpc_error_method_not_found, {"a_dict" : 3}, JsonRpc20Error.METHOD_NOT_FOUND), (vapi_jsonrpc_error_invalid_params, None, JsonRpc20Error.INVALID_PARAMS), (vapi_jsonrpc_error_internal_error, 3.14159, JsonRpc20Error.INTERNAL_ERROR), (vapi_jsonrpc_error_transport_error, "blah", JsonRpc20Error.TRANSPORT_ERROR), ] for exception_factory, data, error_code in exceptions: error = exception_factory(data=data) self.assertTrue(error.code == error_code) def get_loopback_connector(self, provider): protocol_handler = get_protocol_handler(provider) rpc_provider = LocalRpcProvider(protocol_handler) return get_protocol_connector(rpc_provider) def test_json_loopback_positive(self): connector = self.get_loopback_connector(self.provider) remote = connector.get_api_provider() for method_def in [null_method_def, echo_method_def]: # invoke_method ctx = ExecutionContext() params = build_adhoc_data_value(method_def.get_input_definition()) method_id = echo_method_def.get_identifier().get_name() remote_result = remote.invoke(fake_iface_id, method_id, params, ctx) local_result = self.provider.invoke(fake_iface_id, method_id, params, ctx) if remote_result.success(): # Validate result output method_def.get_output_definition().validate(remote_result.output) # Validate direct call self.assertEqual(remote_result.output, local_result.output) else: self.assertTrue(remote_result.error, local_result.error) def test_json_loopback_negative(self): connector = self.get_loopback_connector(self.provider) remote = connector.get_api_provider() # Bogus interface / method ctx = connector.new_context() params = VoidValue() result = remote.invoke('bogus.interface', 'bogus', params, ctx) self.assertFalse(result.success()) self.assertTrue(result.error == self.provider.invoke('bogus.interface', 'bogus', params, ctx).error) logging.error("error: %s", str(result.error)) # test_json_handle_request_positive should be covered by test_json_loopback_positive 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 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)))
class TestLocalProvider(unittest.TestCase): def setUp(self): mockup_api_interface = MockupApiInterface() self.local_provider = LocalProvider() self.local_provider.add_interface(mockup_api_interface) connector = LocalConnector(self.local_provider) self.introspection = IntrospectableApiProvider(connector) def _test_method_failure(self, operation_id, error, message_id=None, *args): ctx = ExecutionContext() method_id = method_id_dict[operation_id] service_id = method_id.get_interface_identifier().get_name() if isinstance(error, ErrorValue): expected_error_value = error else: msg = message_factory.get_message(message_id, *args) expected_error_value = make_error_value_from_msgs(error, msg) provider = self.local_provider method_def = self.introspection.get_method(service_id, operation_id) input_value = method_def.get_input_definition().new_value() input_value.set_field(param_name, IntegerValue(0)) method_result = provider.invoke(service_id, operation_id, input_value, ctx) self.assertEquals(None, method_result.output) self.assertEquals(expected_error_value, method_result.error) def _test_operation_not_found(self, interface_name, method_name, error, message_id, *args): ctx = ExecutionContext() expected_msg = message_factory.get_message(message_id, *args) expected_error_value = make_error_value_from_msgs(error, expected_msg) method_result = self.local_provider.invoke(interface_name, method_name, StructValue(), ctx) self.assertEquals(None, method_result.output) self.assertEquals(expected_error_value, method_result.error) def test_add_duplicate_interface(self): mockup_api_interface = MockupApiInterface() self.local_provider = LocalProvider() self.local_provider.add_interface(mockup_api_interface) self.assertRaises(Exception, self.local_provider.add_interface, mockup_api_interface) def test_register_duplicate_interface(self): self.local_provider = LocalProvider() properties = ProviderConfig() properties.cfg = configparser.SafeConfigParser() properties.cfg.add_section(Sections.ENDPOINT) properties.cfg.set( Sections.ENDPOINT, 'local.interfaces', 'test.vmware.vapi.provider.test_local,' + 'test.vmware.vapi.provider.test_local') self.assertRaises(Exception, self.local_provider.register_by_properties, properties) def test_report_declared_error(self): self._test_method_failure(report_declared_error, not_found_error) def test_report_undeclared_error(self): msg = message_factory.get_message( 'vapi.method.status.errors.invalid', not_found_error.name, str(method_id_dict[report_undeclared_error].get_name())) expected_error = make_error_value_from_msgs(internal_server_error_def, *([msg, _msg])) self._test_method_failure(report_undeclared_error, expected_error) def test_raise_python_exception(self): self._test_method_failure(raise_python_exception, internal_server_error_def, 'vapi.method.invoke.exception', str(RuntimeError())) def test_invalid_input(self): ctx = ExecutionContext() expected_msg = message_factory.get_message('vapi.method.input.invalid') expected_error_value = make_error_value_from_msgs( invalid_argument_def, expected_msg) method_result = self.local_provider.invoke( service_id=raise_python_exception_id.get_interface_identifier( ).get_name(), operation_id=raise_python_exception_id.get_name(), input_value=IntegerValue(), ctx=ctx) self.assertEquals(None, method_result.output) self.assertEquals(expected_error_value, method_result.error) def test_input_validation_failure(self): ctx = ExecutionContext() expected_msg0 = message_factory.get_message( 'vapi.data.structure.field.invalid', 'param', OPERATION_INPUT) expected_msg1 = message_factory.get_message( 'vapi.data.validate.mismatch', 'Integer', 'Structure') expected_error_value = make_error_value_from_msgs( invalid_argument_def, expected_msg0, expected_msg1) service_id = raise_python_exception_id.get_interface_identifier( ).get_name() operation_id = raise_python_exception_id.get_name() method_def = self.introspection.get_method(service_id, operation_id) input_value = method_def.get_input_definition().new_value() input_value.set_field(param_name, StructValue()) method_result = self.local_provider.invoke(service_id=service_id, operation_id=operation_id, input_value=input_value, ctx=ctx) self.assertEquals(None, method_result.output) self.assertEquals(expected_error_value, method_result.error) def test_output_validation_failure(self): self._test_method_failure(return_invalid_output, internal_server_error_def, 'vapi.data.validate.mismatch', 'Void', 'Structure') def test_missing_interface(self): interface_name = 'bogus_interface' method_name = 'test_method' self._test_operation_not_found(interface_name, method_name, operation_not_found_def, 'vapi.method.input.invalid.interface', interface_name) def test_missing_method(self): interface_name = interface_id.get_name() method_name = 'bogus_method' self._test_operation_not_found(interface_name, method_name, operation_not_found_def, 'vapi.method.input.invalid.method', method_name) def test_introspection_operation_get(self): ctx = ExecutionContext() input_val = StructValue(OPERATION_INPUT) input_val.set_field('service_id', StringValue('mockup_interface')) input_val.set_field('operation_id', StringValue('mock')) actual_output = self.local_provider.invoke( 'com.vmware.vapi.std.introspection.operation', 'get', input_val, ctx) expected_output = StructValue( name='com.vmware.vapi.std.introspection.operation.info') input_def_value = StructValue( 'com.vmware.vapi.std.introspection.operation.data_definition') input_def_value.set_field('fields', OptionalValue(ListValue(values=[]))) input_def_value.set_field('element_definition', OptionalValue()) input_def_value.set_field('type', StringValue('STRUCTURE')) input_def_value.set_field('name', OptionalValue(StringValue(OPERATION_INPUT))) expected_output.set_field('input_definition', input_def_value) output_def_value = StructValue( 'com.vmware.vapi.std.introspection.operation.data_definition') output_def_value.set_field('fields', OptionalValue()) output_def_value.set_field('element_definition', OptionalValue()) output_def_value.set_field('type', StringValue('VOID')) output_def_value.set_field('name', OptionalValue()) expected_output.set_field('output_definition', output_def_value) expected_output.set_field('error_definitions', error_values) self.assertEqual(actual_output.output, expected_output) def test_success(self): ctx = ExecutionContext() service_id = interface_id.get_name() operation_id = mock_definition method_def = self.introspection.get_method(service_id, operation_id) input_value = method_def.get_input_definition().new_value() input_value.set_field(param_name, IntegerValue(10)) method_result = self.local_provider.invoke(service_id, operation_id, input_value, ctx) self.assertTrue(method_result.success()) self.assertEqual(method_result.output, VoidValue()) def test_success_2(self): ctx = ExecutionContext() service_id = interface_id.get_name() operation_id = mock_definition input_value = StructValue(OPERATION_INPUT) input_value.set_field(param_name, IntegerValue(10)) method_result = self.local_provider.invoke(service_id, operation_id, input_value, ctx) self.assertTrue(method_result.success()) self.assertEqual(method_result.output, VoidValue())
class TestApiInterfaceSkeleton(unittest.TestCase): def setUp(self): self.provider = LocalProvider() self.provider.add_interface(MockImpl()) connector = LocalConnector(self.provider) stub_config = StubConfigurationFactory.new_std_configuration(connector) self.service = Service(stub_config) self.operation = Operation(stub_config) def test_services(self): expected_services = sorted([ 'com.vmware.vapi.std.introspection.service', 'com.vmware.vapi.std.introspection.provider', 'mock_interface', 'com.vmware.vapi.std.introspection.operation' ]) actual_services = sorted(self.service.list()) self.assertEqual(actual_services, expected_services) def test_service_info(self): info = self.service.get(id='mock_interface') self.assertEqual(info.operations, set([method_name, task_method_name, '%s$task' % task_method_name, application_context_method_name])) def test_operation_info(self): actual_info = self.operation.get(service_id=interface_name, operation_id=method_name) input_def = Operation.DataDefinition( type=Operation.DataDefinition.DataType.STRUCTURE, name=OPERATION_INPUT, fields={ 'message': Operation.DataDefinition( type=Operation.DataDefinition.DataType.STRING ), 'throw': Operation.DataDefinition( type=Operation.DataDefinition.DataType.BOOLEAN ) } ) output_def = Operation.DataDefinition( type=Operation.DataDefinition.DataType.STRING) error_defs = [ make_introspection_error_def('com.vmware.vapi.std.errors.not_found'), make_introspection_error_def('com.vmware.vapi.std.errors.unexpected_input'), make_introspection_error_def('com.vmware.vapi.std.errors.internal_server_error'), make_introspection_error_def('com.vmware.vapi.std.errors.invalid_argument'), make_introspection_error_def('com.vmware.vapi.std.errors.operation_not_found'), ] expected_info = Operation.Info(input_definition=input_def, output_definition=output_def, error_definitions=error_defs) self.assertEqual(actual_info.input_definition, expected_info.input_definition) self.assertEqual(actual_info.output_definition, expected_info.output_definition) actual_errors = [error.name for error in actual_info.error_definitions] expected_errors = [error.name for error in expected_info.error_definitions] self.assertEqual(sorted(actual_errors), sorted(expected_errors)) def test_invoke(self): ctx = ExecutionContext() input_ = StructValue(method_name) input_.set_field('message', StringValue('hello')) input_.set_field('throw', BooleanValue(False)) actual_method_result = self.provider.invoke(interface_name, method_name, input_, ctx) expected_method_result = MethodResult(output=StringValue('hello')) self.assertEqual(actual_method_result.output, expected_method_result.output) self.assertEqual(actual_method_result.error, expected_method_result.error) def test_invoke_long_running(self): ctx = ExecutionContext() input_ = StructValue(method_name) input_.set_field('message', StringValue('hello')) input_.set_field('throw', BooleanValue(False)) actual_method_result = self.provider.invoke(interface_name, '%s$task' % task_method_name, input_, ctx) expected_method_result = MethodResult(output=StringValue('hello')) try: id_split = actual_method_result.output.value.split(':') uuid.UUID(id_split[0], version=4) uuid.UUID(id_split[1], version=4) except ValueError: # There's no assertNotRaises so explicitly fail assert # in case a ValueError is thrown for invalid uuid. self.assertTrue(False) self.assertEqual(actual_method_result.error, expected_method_result.error) def test_invoke_long_running_sync(self): ctx = ExecutionContext() input_ = StructValue(method_name) input_.set_field('message', StringValue('hello')) input_.set_field('throw', BooleanValue(False)) actual_method_result = self.provider.invoke(interface_name, task_method_name, input_, ctx) expected_method_result = MethodResult(output=StringValue('hello')) self.assertEqual(actual_method_result.output, expected_method_result.output) self.assertEqual(actual_method_result.error, expected_method_result.error) def test_invoke_invalid_arg(self): ctx = ExecutionContext() input_ = StructValue(method_name) input_.set_field('message', IntegerValue(10)) input_.set_field('throw', BooleanValue(False)) actual_method_result = self.provider.invoke(interface_name, method_name, input_, ctx) self.assertFalse(actual_method_result.success()) def test_invoke_error(self): ctx = ExecutionContext() input_ = StructValue(method_name) input_.set_field('message', IntegerValue(10)) input_.set_field('throw', BooleanValue(True)) actual_method_result = self.provider.invoke(interface_name, method_name, input_, ctx) self.assertFalse(actual_method_result.success()) def test_check_for_unknown_fields(self): struct_type = StructType( 'test', { 'name': StringType() } ) struct_value = StructValue( name='test', values={ 'name': StringValue('hello') } ) self.assertIsNone( ApiInterfaceSkeleton.check_for_unknown_fields( struct_type, struct_value)) def test_check_for_unknown_fields_2(self): optional_struct_type = OptionalType(StructType( 'test', { 'name': StringType() } )) optional_struct_value = OptionalValue(StructValue( name='test', values={ 'name': StringValue('hello') } )) self.assertIsNone( ApiInterfaceSkeleton.check_for_unknown_fields( optional_struct_type, optional_struct_value)) def test_check_for_unknown_fields_invalid_1(self): struct_type = StructType( 'test', { 'name': StringType() } ) struct_value = StructValue( name='test', values={ 'name': StringValue('hello'), 'address': StringValue('hello') } ) self.assertIsNotNone( ApiInterfaceSkeleton.check_for_unknown_fields( struct_type, struct_value)) def test_check_for_unknown_fields_invalid_2(self): info_type = StructType( 'info', { 'basic': StructType( 'basic', { 'name': StringType() } ), 'address': StructType( 'address', { 'city': StringType() } ), } ) info_value = StructValue( name='info', values={ 'basic': StructValue( name='basic', values={ 'name': 'foo', 'extra': 'bar' # extra field } ), 'address': StructValue( name='address', values={ 'city': 'foo' } ) } ) self.assertIsNotNone( ApiInterfaceSkeleton.check_for_unknown_fields( info_type, info_value)) def test_check_for_unknown_fields_invalid_3(self): list_info_type = ListType(StructType( 'info', { 'basic': StructType( 'basic', { 'name': StringType() } ), 'address': StructType( 'address', { 'city': StringType() } ), } )) list_info_value = [ StructValue( name='info', values={ 'basic': StructValue( name='basic', values={ 'name': 'foo', } ), 'address': StructValue( name='address', values={ 'city': 'foo' } ) } ), StructValue( name='info', values={ 'basic': StructValue( name='basic', values={ 'name': 'foo', 'extra': 'bar' # extra field in 2nd element of the list } ), 'address': StructValue( name='address', values={ 'city': 'foo' } ) } ) ] self.assertIsNotNone( ApiInterfaceSkeleton.check_for_unknown_fields( list_info_type, list_info_value)) def _run_method_in_thread(self, results, index, api_provider, *args): results[index] = api_provider.invoke(*args) def test_check_application_context(self): # Invoke an operation that checks for application context in 10 threads input_ = StructValue(application_context_method_name) num_threads = 10 results = [None] * num_threads threads = [None] * num_threads for i in range(num_threads): threads[i] = threading.Thread( target=self._run_method_in_thread, args=( results, i, self.provider, interface_name, application_context_method_name, input_, ExecutionContext(application_context=ApplicationContext( { 'thread_no': str(i) })),)) threads[i].start() for i in range(num_threads): threads[i].join() method_result = results[i] self.assertTrue(method_result.success()) self.assertTrue(method_result.output.value, str(i))