def test_all_annotations(self): input_val = StructValue(name='operation-input', values={ 'spec_val': StructValue(name='spec', values={ 'string_val': StringValue('string1'), }), 'string_val_url': StringValue('string2'), 'action_val': StringValue('stop'), }) rest_metadata = OperationRestMetadata( http_method='POST', url_template='/foo/{stringValUrl}', request_body_parameter='spec_val', path_variables={'string_val_url': 'stringValUrl'}, query_parameters={'action_val': 'action'}) url_path, actual_headers, actual_body, _ = RestSerializer.serialize_request( input_value=input_val, ctx=None, rest_metadata=rest_metadata, is_vapi_rest=True) expected_url_path = '/foo/string2?action=stop' expected_headers = {} expected_body = '{"string_val":"string1"}' self.assertEqual(expected_url_path, url_path) self.assertEqual(expected_headers, actual_headers) self.assertEqual(expected_body, actual_body)
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 generate_primitive_value(self, typ): output = StructValue(Introspection.DATA_DEFINITION) output.set_field('type', StringValue(typ)) output.set_field('fields', OptionalValue()) output.set_field('name', OptionalValue()) output.set_field('element_definition', OptionalValue()) return output
def test_struct_ref_to_value(self): actual_output = convert_data_def_to_data_value( StructRefDefinition('mock')) expected_output = StructValue(Introspection.DATA_DEFINITION) expected_output.set_field('type', StringValue('STRUCTURE_REF')) expected_output.set_field('fields', OptionalValue()) expected_output.set_field('name', OptionalValue(StringValue('mock'))) expected_output.set_field('element_definition', OptionalValue()) self.assertEqual(actual_output, expected_output)
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_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())
def serialize_input(input_value, rest_metadata): """ Serialize the input value :type input_value: :class:`vmware.vapi.data.value.StructValue` :param input_value: method input parameters :type rest_metadata: :class:`vmware.vapi.lib.rest.OperationRestMetadata` :param rest_metadata: Rest request metadata :rtype :class:`tuple` :return: Tuple of URL path, HTTP headers and request body """ if rest_metadata is not None: path_variable_field_names = \ rest_metadata.get_path_variable_field_names() query_param_field_names = \ rest_metadata.get_query_parameter_field_names() header_field_names = \ rest_metadata.get_header_field_names() request_body_param = rest_metadata.request_body_parameter else: path_variable_field_names = [] query_param_field_names = [] header_field_names = [] request_body_param = None if request_body_param is not None: request_body_input_value = input_value.get_field( request_body_param) else: request_body_input_value = StructValue(name=input_value.name) path_variable_fields = {} query_param_fields = {} header_fields = {} for (field_name, field_val) in input_value.get_fields(): if field_name in path_variable_field_names: field_str = RequestSerializer._convert_to_string(field_val) if field_str is not None: path_variable_fields[field_name] = field_str elif field_name in query_param_field_names: field_str = RequestSerializer._convert_to_string(field_val) if field_str is not None: query_param_fields[field_name] = field_str elif field_name in header_field_names: field_str = RequestSerializer._convert_to_string(field_val) if field_str is not None: header_fields[field_name] = field_str elif request_body_param is None: request_body_input_value.set_field(field_name, field_val) url_path = rest_metadata.get_url_path( path_variable_fields, query_param_fields) if rest_metadata else None return (url_path, header_fields, DataValueConverter.convert_to_json(request_body_input_value))
def test_generic_def_to_value(self): for typ_def, typ in [(OptionalDefinition, 'OPTIONAL'), (ListDefinition, 'LIST')]: typ_def = typ_def(StringDefinition()) actual_output = convert_data_def_to_data_value(typ_def) expected_output = StructValue(Introspection.DATA_DEFINITION) element_value = self.generate_primitive_value('STRING') expected_output.set_field('type', StringValue(typ)) expected_output.set_field('fields', OptionalValue()) expected_output.set_field('name', OptionalValue()) expected_output.set_field('element_definition', OptionalValue(element_value)) self.assertEqual(actual_output, expected_output)
def _visit_dict(self, obj): """ Visit python dictionary object :type obj: :class:`dict` :param obj: Python dictionary object :rtype: :class:`vmware.vapi.data.value.StructValue` :return: Struct value """ result = StructValue() for k, v in six.iteritems(obj): result.set_field(k, self._visit(v)) return result
def test_publish(self): info = self.task_handle.get_info() progress = Progress() progress.total = 100 progress.completed = 42 progress.message = self.progress_msg desc2 = LocalizableMessage(id='msg2', default_message='task1', args=[]) info.description = desc2 info.cancelable = False info.status = 'RUNNING' info.start_time = datetime.utcnow() info.progress = progress self.task_handle.publish() result = self.task_manager.get_info(self.task_id) self.assertEqual(result.get_field('status'), StringValue('RUNNING')) progress_val = StructValue('com.vmware.cis.task.progress') progress_val.set_field('total', IntegerValue(100)) progress_val.set_field('completed', IntegerValue(42)) progress_val.set_field( 'message', TypeConverter.convert_to_vapi( self.progress_msg, LocalizableMessage.get_binding_type())) self.assertEqual(result.get_field('progress'), OptionalValue(progress_val)) self.assertEqual(result.get_field('cancelable'), BooleanValue(False))
def test_query_params_optionals(self): input_val = StructValue(name='operation-input', values={ 'string_val': StringValue('string1'), 'action1_val': OptionalValue(value=StringValue('start')), 'action2_val': OptionalValue() }) rest_metadata = OperationRestMetadata(http_method='POST', url_template='/foo/bar', query_parameters={ 'action1_val': 'action1', 'action2_val': 'action2' }) url_path, actual_headers, actual_body, _ = RestSerializer.serialize_request( input_value=input_val, ctx=None, rest_metadata=rest_metadata, is_vapi_rest=True) expected_url_path = '/foo/bar?action1=start' expected_headers = {} expected_body = '{"string_val":"string1"}' self.assertEqual(expected_url_path, url_path) self.assertEqual(expected_headers, actual_headers) self.assertEqual(expected_body, actual_body)
def generate_operation_input(self, service_id, operation_id, input_data): """ This method generates a StructValue corresponding to the Python dict (deserialized from JSON) suitable as an input value for the specified operation. :type service_id: :class:`str` :param service_id: Identifier of the service to be invoked. :type operation_id: :class:`str` :param operation_id: Identifier of the operation to be invoked. :type input_data: :class:`dict` :param input_data: Dictionary object that represents the deserialized json input. :rtype: :class:`vmware.vapi.data.value.DataValue` or :return: DataValue created using the input """ param_info_map = \ self._metadata.service_map[service_id][operation_id].param_info_map try: fields = { param_name: self.visit(param_info_map[str(param_name)].type, param_value) for param_name, param_value in six.iteritems(input_data) } except KeyError as e: msg = 'Unexpected parameter %s in JSON body' % e logger.exception(msg) raise werkzeug.exceptions.BadRequest(msg) return StructValue(name=OPERATION_INPUT, values=fields)
def _convert_method_def_to_data_value(method_def): """ Converts a :class:`vmware.vapi.core.MethodDefinition` object to :class:`vmware.vapi.data.value.DataValue` object :type method_def: :class:`vmware.vapi.core.MethodDefinition` :param method_def: Method definition :rtype: :class:`vmware.vapi.data.value.DataValue` :return: Data value object representing method definition """ output = StructValue( name='com.vmware.vapi.std.introspection.operation.info', values={ 'input_definition': convert_data_def_to_data_value( method_def.get_input_definition()), 'output_definition': convert_data_def_to_data_value( method_def.get_output_definition()), 'error_definitions': ListValue(values=[ convert_data_def_to_data_value(error_def) for error_def in method_def.get_error_definitions() ]) }) return output
def visit_map(self, type_info, json_value): """ Deserialize a map value :type type_info: :class:`com.vmware.vapi.metadata.metamodel_client.Type` :param type_info: Metamodel type information :type json_value: :class:`object` :param json_value: Value to be visited :rtype: :class:`vmware.vapi.data.value.StructValue` :return: DataValue created using the input """ if not isinstance(json_value, list): msg = 'Excepted list, but got %s' % type(json_value).__name__ logger.error(msg) raise werkzeug.exceptions.BadRequest(msg) try: return ListValue([ StructValue(name=MAP_ENTRY, values={ 'key': self.visit(type_info.map_key_type, value['key']), 'value': self.visit(type_info.map_value_type, value['value']) }) for value in json_value ]) except KeyError as e: msg = 'Invalid Map input, missing %s' % e logger.error(msg) raise werkzeug.exceptions.BadRequest(msg)
def test_dict(self): input_val = '{"int_field":10, "bool_field":true}' values = { 'bool_field': BooleanValue(True), 'int_field': IntegerValue(10) } expected_val = StructValue(values=values) actual_val = DataValueConverter.convert_to_data_value(input_val) self.assertEqual(expected_val, actual_val)
def invoke(self, ctx, method_id, input_value): name = method_id.get_name() if name == raise_python_exception: raise RuntimeError() elif name == return_invalid_output: return MethodResult(output=StructValue()) elif name == mock_definition: return MethodResult(output=VoidValue()) return MethodResult(error=not_found_error)
def visit_map(self, typ): """ Visit a python dict :type typ: :class:`vmware.vapi.bindings.type.MapType` :param typ: Binding type of the value """ in_value = self._in_value out_value = StructValue(MAP_STRUCT) for k, v in six.iteritems(in_value): self._in_value = k self.visit(typ.key_type) key_value = self._out_value.value self._in_value = v self.visit(typ.value_type) out_value.set_field(key_value, self._out_value) self._in_value = in_value self._out_value = out_value
def test_struct_value_with_optional_unset(self): input_val = StructValue(name='name', values={ 'val1': StringValue('val1'), 'val2': OptionalValue() }) actual_val = DataValueConverter.convert_to_json(input_val) expected_val = '{"val1":"val1"}' self.assertEqual(expected_val, actual_val) # Verify json is valid json.loads(actual_val)
def test_body(self): spec_val = StructValue(name='spec', values={ 'string_val': StringValue('string1'), }) input_val = StructValue(name='operation-input', values={'spec_val': spec_val}) rest_metadata = OperationRestMetadata(http_method='POST', url_template='/foo') url_path, actual_headers, actual_body, _ = RestSerializer.serialize_request( input_value=input_val, ctx=None, rest_metadata=rest_metadata, is_vapi_rest=True) expected_url_path = '/foo' expected_headers = {} expected_body = '{"spec_val":{"string_val":"string1"}}' self.assertEqual(expected_url_path, url_path) self.assertEqual(expected_headers, actual_headers) self.assertEqual(expected_body, actual_body)
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_struct_value_with_optional_set(self): input_val = StructValue(name='name', values={ 'val1': StringValue('val1'), 'val2': OptionalValue(StringValue('val2')) }) actual_val = DataValueConverter.convert_to_json(input_val) self.assertTrue('"val1":"val1"' in actual_val) self.assertTrue('"val2":"val2"' in actual_val) # Verify json is valid json.loads(actual_val)
def test_empty_input_no_metadata(self): input_val = StructValue(name='operation-input', values={}) url_path, headers, actual_body, cookies = \ RestSerializer.serialize_request( input_value=input_val, ctx=None, rest_metadata=None, is_vapi_rest=True) expected_body = '{}' expected_headers = {} self.assertIsNone(url_path) self.assertEqual(expected_headers, headers) self.assertIsNone(cookies) self.assertEqual(expected_body, actual_body)
def test_session_security_context(self): input_val = StructValue(name='operation-input', values={}) session_id = 'some-session-id' sec_ctx = create_session_security_context(session_id) _, actual_headers, actual_body, _ = RestSerializer.serialize_request( input_value=input_val, ctx=ExecutionContext(security_context=sec_ctx), rest_metadata=None, is_vapi_rest=True) expected_body = '{}' expected_headers = {REST_SESSION_ID_KEY: session_id} self.assertEqual(expected_headers, actual_headers) self.assertEqual(expected_body, actual_body)
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 get_service_info(self, service_id): provider = self._get_provider(service_id) if provider: ctx = ExecutionContext() struct_value = StructValue(name=OPERATION_INPUT, values={'id': StringValue(service_id)}) return provider.invoke(Introspection.SERVICE_SVC, 'get', struct_value, ctx) else: msg = message_factory.get_message( 'vapi.introspection.operation.service.not_found', service_id) error_value = make_error_value_from_msgs(not_found_def, msg) return MethodResult(error=error_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 test_string_input(self): input_val = StructValue(name='operation-input', values={ 'string_val': StringValue('string1'), }) _, actual_headers, actual_body, _ = RestSerializer.serialize_request( input_value=input_val, ctx=None, rest_metadata=None, is_vapi_rest=True) expected_body = '{"string_val":"string1"}' expected_headers = {} self.assertEqual(expected_headers, actual_headers) self.assertEqual(expected_body, actual_body)
def test_struct_value(self): input_status = 200 input_response = '{"id":"vm-100", "name":"Linux VM"}' expected_result = MethodResult(output=StructValue( values={ 'id': StringValue('vm-100'), 'name': StringValue('Linux VM') })) actual_result = RestSerializer.deserialize_response( status=input_status, response_str=input_response, is_vapi_rest=False) self.assertEqual(expected_result.output, actual_result.output) self.assertEqual(expected_result.error, actual_result.error)
def visit_user_defined(self, type_info, json_value): """ Deserialize a user defined value :type type_info: :class:`com.vmware.vapi.metadata.metamodel_client.Type` :param type_info: Metamodel type information :type json_value: :class:`object` :param json_value: Value to be visited :rtype: :class:`vmware.vapi.data.value.StructValue` or :class:`vmware.vapi.data.value.StringValue` :return: DataValue created using the input """ user_defined_type_info = type_info.user_defined_type if user_defined_type_info.resource_type == Enumeration.RESOURCE_TYPE: return StringValue(json_value) elif user_defined_type_info.resource_type == Structure.RESOURCE_TYPE: structure_info = self._metadata.structure_map[ user_defined_type_info.resource_id] struct_value = StructValue(name=user_defined_type_info.resource_id) for field_name, field_value in six.iteritems(json_value): try: field_info = structure_info[str(field_name)] field_data_value = self.visit(field_info.type, field_value) struct_value.set_field(field_name, field_data_value) except KeyError: msg = 'Unexpected field \'%s\' in request' % field_name logger.error(msg) raise werkzeug.exceptions.BadRequest(msg) return struct_value else: msg = ('Could not process the request,' 'user defined type %s is not supported' % user_defined_type_info.resource_type) logger.error(msg) raise werkzeug.exceptions.InternalServerError(msg)
def augment_method_result_with_errors(service_id, operation_id, method_result, errors_to_augment): """ Returns a new method result that is identical to `method_result` except that the `errors_definition` field in the `output` (which is of type Operation.Info from Introspection service) contains the errors from the Info structure in `method_result` plus the errors in `errors_to_augment`. This code will be executed only for "get" operation in vAPI Operation Introspection service. :type service_id: :class:`str` :param service_id: Service identifier :type operation_id: :class:`str` :param operation_id: Operation identifier :type method_result: :class:`vmware.vapi.core.MethodResult` :param method_result: Operation result :type errors_to_augment: :class:`list` of :class:`vmware.vapi.data.value.StructValue` :param errors_to_augment: Errors to augment. These are struct values of type com.vmware.vapi.std.introspection.Operation.DataDefinition whose `type` field has the value ERROR to the DataDefinition type in Introspection service IDL. :rtype: :class:`vmware.vapi.data.value.DataValue` :return: Output data value """ if method_result.success(): if (service_id == Introspection.OPERATION_SVC and operation_id == 'get'): output = method_result.output augmented_output = StructValue( 'com.vmware.vapi.std.introspection.operation.info') augmented_output.set_field('input_definition', output.get_field('input_definition')) augmented_output.set_field('output_definition', output.get_field('output_definition')) errors = ListValue() error_names = [] for error_def in output.get_field('error_definitions'): errors.add(error_def) error_names.append(error_def.get_field('name').value.value) for error_def in errors_to_augment: if error_def.get_field('name').value.value not in error_names: errors.add(error_def) augmented_output.set_field('error_definitions', errors) return MethodResult(output=augmented_output) return method_result