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_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 __init__(self, connector): """ Initialize IntrospectableApiProvider :type connector: :class:`vmware.vapi.protocol.client.connector.Connector` :param Connector: Protocol connector to use for operation invocations """ stub_config = StubConfigurationFactory.new_std_configuration(connector) self._operation = Operation(stub_config)
def struct_ref_def(name): """ Internal function to create structure reference from name. :type name: :`str` :param name: name of the referred to structure :rtype: :class:`com.vmware.vapi.std.introspection_client.Operation.DataDefinition` :return: structure reference definition used to break circular references. """ return Operation.DataDefinition( type=Operation.DataDefinition.DataType.STRUCTURE_REF, name=name )
def list_def(element): """ Internal function to create DataDefinition for a list. :type element: :class:`com.vmware.vapi.std.introspection_client.Operation.DataDefinition` :param element: list element type definition :rtype: :class:`com.vmware.vapi.std.introspection_client.Operation.DataDefinition` :return: definition for a list of element values. """ return Operation.DataDefinition( type=Operation.DataDefinition.DataType.LIST, element_definition=element )
def opt_def(element): """ Internal function to create DataDefinition for an optional element. :type element: :class:`com.vmware.vapi.std.introspection_client.Operation.DataDefinition` :param element: element type definition :rtype: :class:`com.vmware.vapi.std.introspection_client.Operation.DataDefinition` :return: definition for optional value of element type. """ return Operation.DataDefinition( type=Operation.DataDefinition.DataType.OPTIONAL, element_definition=element )
def make_introspection_error_def(error_name): """ Create an instance of :class:`com.vmware.vapi.std.introspection_client.Operation.DataDefinition` that represents the standard error specified :type error_name: :class:`str` :param error_name: Fully qualified error name of one of the vAPI standard errors :rtype: :class:`com.vmware.vapi.std.introspection_client.Operation.DataDefinition` :return: Error definition instance for the given error name """ return Operation.DataDefinition( type=Operation.DataDefinition.DataType.ERROR, name=error_name, fields={ 'messages': list_def(localizable_message_def), 'data': opt_def(Operation.DataDefinition( type=Operation.DataDefinition.DataType.DYNAMIC_STRUCTURE) ), 'error_type': optional_string_def } )
class IntrospectableApiProvider(object): """ Helper class for invoking the 'get' operation in the service 'com.vmware.vapi.std.introspection.Operation' """ def __init__(self, connector): """ Initialize IntrospectableApiProvider :type connector: :class:`vmware.vapi.protocol.client.connector.Connector` :param Connector: Protocol connector to use for operation invocations """ stub_config = StubConfigurationFactory.new_std_configuration(connector) self._operation = Operation(stub_config) def get_method(self, service_id, operation_id): """ Get method definition for the specified operation :type service_id: :class:`str` :param service_id: Service identifier :type operation_id: :class:`str` :param operation_id: Operation identifier :rtype: :class:`vmware.vapi.core.MethodDefinition` :return: Method definition of the specified operation """ info = self._operation.get(service_id=service_id, operation_id=operation_id) input_def = convert_data_value_to_data_def( info.input_definition.get_struct_value()) output_def = convert_data_value_to_data_def( info.output_definition.get_struct_value()) error_defs = [convert_data_value_to_data_def(error_def.get_struct_value()) for error_def in info.error_definitions] interface_id = InterfaceIdentifier(service_id) method_id = MethodIdentifier(interface_id, operation_id) method_definition = MethodDefinition(method_id, input_def, output_def, error_defs) return method_definition
def map_def(key, value): """ Internal function to create map definition from a key and value definitions definitions. For use only by vAPI runtime. :type key: :class:`com.vmware.vapi.std.introspection_client.Operation.DataDefinition` :param key: DataDefintion for the map key :type value: :class:`com.vmware.vapi.std.introspection_client.Operation.DataDefinition` :param value: DataDefintion for the map value :rtype: :class:`com.vmware.vapi.std.introspection_client.Operation.DataDefinition` :return: structure reference definition used to break circular references. """ return list_def( Operation.DataDefinition( type=Operation.DataDefinition.DataType.STRUCTURE, name='map-entry', fields={ 'key': key, 'value': value } ) )
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))
def struct_ref_def(name): """ Internal function to create structure reference from name. :type name: :`str` :param name: name of the referred to structure :rtype: :class:`com.vmware.vapi.std.introspection_client.Operation.DataDefinition` :return: structure reference definition used to break circular references. """ return Operation.DataDefinition( type=Operation.DataDefinition.DataType.STRUCTURE_REF, name=name ) string_def = Operation.DataDefinition( type=Operation.DataDefinition.DataType.STRING ) optional_string_def = opt_def(string_def) optional_long_def = opt_def( Operation.DataDefinition( type=Operation.DataDefinition.DataType.LONG ) ) optional_double_def = opt_def( Operation.DataDefinition( type=Operation.DataDefinition.DataType.DOUBLE ) )