def set_operation_params(self, optional=False): """ This is the main entry point. We return a set with the required and optional parameters for the provided operation / specification. :param optional: Should we set the values for the optional parameters? """ self._fix_common_spec_issues() # Make a copy of the operation operation = Operation.from_spec(self.operation.swagger_spec, self.operation.path_name, self.operation.http_method, self.operation.op_spec) for parameter_name, parameter in operation.params.iteritems(): # We make sure that all parameters have a fill attribute parameter.fill = None if self._should_skip_setting_param_value(parameter, optional): continue self._set_param_value(parameter) return operation
def build_resources(swagger_spec): """Transforms the REST resources in the json-like swagger_spec into rich :Resource: objects that have associated :Operation:s. :type swagger_spec: :class:`bravado_core.spec.Spec` :returns: dict where (key,value) = (resource name, Resource) """ # Map operations to resources using operation tags if available. # - If an operation has multiple tags, it will be associated with multiple # resources! # - If an operation has no tags, its resource name will be derived from its # path # key = tag_name value = { operation_id : Operation } tag_to_operations = defaultdict(dict) paths = swagger_spec.spec_dict['paths'] for path_name, path_spec in iteritems(paths): for http_method, operation_spec in iteritems(path_spec): if http_method == 'parameters': continue operation = Operation.from_spec( swagger_spec, path_name, http_method, operation_spec) tags = operation_spec.get('tags', []) if not tags: tags.append(convert_path_to_resource(path_name)) for tag in tags: tag_to_operations[tag][operation.operation_id] = operation resources = {} for tag, operations in iteritems(tag_to_operations): resources[tag] = Resource(tag, operations) return resources
def test_simple(mock_marshal_param, minimal_swagger_spec, getPetById_spec, request_dict): request_dict['url'] = '/pet/{petId}' op = CallableOperation(Operation.from_spec( minimal_swagger_spec, '/pet/{petId}', 'get', getPetById_spec)) construct_params(op, request_dict, op_kwargs={'petId': 34, 'api_key': 'foo'}) assert 2 == mock_marshal_param.call_count
def test_consumes_on_op_overrides_consumes_from_swagger_spec( minimal_swagger_dict): op_spec = {'consumes': ['application/x-www-form-urlencoded']} minimal_swagger_dict['consumes'] = ['multipart/form-data'] minimal_swagger_spec = Spec.from_dict(minimal_swagger_dict) op = Operation(minimal_swagger_spec, '/foo', 'get', op_spec) assert ['application/x-www-form-urlencoded'] == op.consumes
def test_with_mocks(mock_marshal_param): get_op = minimal_swagger_spec.spec_dict['paths']['/pet/{petId}']['get'] del get_op['parameters'][0] op = Operation.from_spec( minimal_swagger_spec, '/pet/{petId}', 'get', {}) op.construct_params(request_dict, op_kwargs={}) assert 0 == mock_marshal_param.call_count
def test_path_param_and_op_param(minimal_swagger_dict): op_spec = { 'operationId': 'get_pet_by_id', 'parameters': [{ 'name': 'pet_id', 'in': 'query', 'required': True, 'type': 'integer', }], 'responses': { '200': {} } } path_spec = { 'get': op_spec, 'parameters': [{ 'name': 'sort_key', 'in': 'query', 'required': False, 'type': 'string', }], } minimal_swagger_dict['paths']['/pets'] = path_spec swagger_spec = Spec(minimal_swagger_dict) op = Operation(swagger_spec, '/pets', 'get', op_spec) params = build_params(op) assert len(params) == 2 assert 'pet_id' in params assert 'sort_key' in params
def test_op_param_overrides_path_param(minimal_swagger_dict): # Override 'required' to be True for the sort_key param op_spec = { 'operationId': 'get_pet_by_id', 'parameters': [{ 'name': 'sort_key', 'in': 'query', 'required': True, 'type': 'string', }], 'responses': { '200': {} } } path_spec = { 'get': op_spec, 'parameters': [{ 'name': 'sort_key', 'in': 'query', 'required': False, 'type': 'string', }], } minimal_swagger_dict['paths']['/pets'] = path_spec swagger_spec = Spec(minimal_swagger_dict) op = Operation(swagger_spec, '/pets', 'get', op_spec) params = build_params(op) assert len(params) == 1 assert 'sort_key' in params assert params['sort_key'].required
def test_sanitized_param(minimal_swagger_dict): op_spec = { 'operationId': 'get_pet_by_id', # op params would go here 'responses': { '200': {} } } path_spec = { 'get': op_spec, 'parameters': [{ 'name': 'pet-id', 'in': 'headers', 'required': 'true', 'type': 'integer', }], } minimal_swagger_dict['paths']['/pets'] = path_spec swagger_spec = Spec(minimal_swagger_dict) op = Operation(swagger_spec, '/pets', 'get', op_spec) params = build_params(op) assert len(params) == 1 assert [p for p in params] == ['pet_id'] assert 'pet-id' in params assert params['pet_id'] is params['pet-id']
def test_with_timeouts(mock_marshal_param, minimal_swagger_spec, getPetById_spec, request_dict, timeout_kv): request_dict["url"] = "/pet/{petId}" op = CallableOperation(Operation.from_spec(minimal_swagger_spec, "/pet/{petId}", "get", getPetById_spec)) k, v = timeout_kv request = construct_request(op, request_options={k: v}, petId=34) assert request[k] == v assert mock_marshal_param.call_count == 1
def test_path_param_only(minimal_swagger_dict): op_spec = { 'operationId': 'get_pet_by_id', # op params would go here 'responses': { '200': {}, }, } path_spec = { 'get': op_spec, 'parameters': [ { 'name': 'pet_id', 'in': 'query', 'required': 'true', 'type': 'integer', }, ], } minimal_swagger_dict['paths']['/pets'] = path_spec swagger_spec = Spec(minimal_swagger_dict) op = Operation(swagger_spec, '/pets', 'get', op_spec) params = build_params(op) assert len(params) == 1 assert 'pet_id' in params
def test_success_msgpack_response(minimal_swagger_spec): response_spec = { 'description': 'Address', 'schema': { 'type': 'object', 'properties': { 'first_name': { 'type': 'string', }, 'last_name': { 'type': 'string', }, }, }, } op = Operation( minimal_swagger_spec, '/foo', 'get', op_spec={'produces': [APP_MSGPACK]}, ) response = Mock( spec=OutgoingResponse, content_type=APP_MSGPACK, raw_bytes=msgpack.dumps( { 'first_name': 'darwin', 'last_name': 'niwrad', }, use_bin_type=True, ), ) validate_response_body(op, response_spec, response)
def test_raise_error_when_no_default_and_no_status_code_match( empty_swagger_spec, op_spec): del op_spec['responses']['default'] op = Operation(empty_swagger_spec, '/pet/{petId}', 'get', op_spec) with pytest.raises(MatchingResponseNotFound) as excinfo: get_response_spec(404, op) assert 'not found' in str(excinfo.value)
def test_returns_consumes_from_op(minimal_swagger_dict): op_spec = { 'consumes': ['multipart/form-data'], } minimal_swagger_spec = Spec.from_dict(minimal_swagger_dict) op = Operation(minimal_swagger_spec, '/foo', 'get', op_spec) assert ['multipart/form-data'] == op.consumes
def build_resources(swagger_spec): """Transforms the REST resources in the json-like swagger_spec into rich :Resource: objects that have associated :Operation:s. :type swagger_spec: :class:`bravado_core.spec.Spec` :returns: dict where (key,value) = (resource name, Resource) """ # Map operations to resources using operation tags if available. # - If an operation has multiple tags, it will be associated with multiple # resources! # - If an operation has no tags, its resource name will be derived from its # path # key = tag_name value = { operation_id : Operation } tag_to_operations = defaultdict(dict) paths = swagger_spec.spec_dict['paths'] for path_name, path_spec in iteritems(paths): for http_method, operation_spec in iteritems(path_spec): if http_method == 'parameters': continue operation = Operation.from_spec(swagger_spec, path_name, http_method, operation_spec) tags = operation_spec.get('tags', []) if not tags: tags.append(convert_path_to_resource(path_name)) for tag in tags: tag_to_operations[tag][operation.operation_id] = operation resources = {} for tag, operations in iteritems(tag_to_operations): resources[tag] = Resource(tag, operations) return resources
def test_simple(mock_marshal_param, minimal_swagger_spec, getPetById_spec, request_dict): request_dict['url'] = '/pet/{petId}' op = CallableOperation(Operation.from_spec( minimal_swagger_spec, '/pet/{petId}', 'get', getPetById_spec)) construct_params(op, request_dict, op_kwargs={'petId': 34}) assert 1 == mock_marshal_param.call_count
def mock_operation(simple_operation_dict): return Operation( swagger_spec=mock.Mock(), path_name='/endpoint', http_method='get', op_spec=simple_operation_dict, )
def test_success_json_response(minimal_swagger_spec): response_spec = { 'description': 'Address', 'schema': { 'type': 'object', 'properties': { 'first_name': { 'type': 'string', }, 'last_name': { 'type': 'string', }, }, }, } op = Operation( minimal_swagger_spec, '/foo', 'get', op_spec={'produces': ['application/json']}, ) response = Mock( spec=OutgoingResponse, content_type='application/json', json=Mock( spec=dict, return_value={ 'first_name': 'darwin', 'last_name': 'niwrad', }, ), ) validate_response_body(op, response_spec, response)
def test_produces_on_op_overrides_produces_from_swagger_spec( minimal_swagger_dict, ): op_spec = {'produces': ['application/xml']} minimal_swagger_dict['produces'] = ['application/json'] minimal_swagger_spec = Spec.from_dict(minimal_swagger_dict) op = Operation(minimal_swagger_spec, '/foo', 'get', op_spec) assert ['application/xml'] == op.produces
def op(minimal_swagger_spec): return Operation( minimal_swagger_spec, '/foo', 'get', op_spec={'produces': ['application/json']}, )
def test_with_mocks(mock_marshal_param): del getPetById_spec['parameters'][0]['required'] getPetById_spec['parameters'][0]['default'] = 99 request_dict['url'] = '/pet/{petId}' op = OperationDecorator(Operation.from_spec( minimal_swagger_spec, '/pet/{petId}', 'get', getPetById_spec)) op.construct_params(request_dict, op_kwargs={}) assert 1 == mock_marshal_param.call_count
def test_no_params(mock_marshal_param, minimal_swagger_spec, request_dict): get_op = minimal_swagger_spec.spec_dict['paths']['/pet/{petId}']['get'] del get_op['parameters'][0] op = CallableOperation( Operation.from_spec(minimal_swagger_spec, '/pet/{petId}', 'get', {})) construct_params(op, request_dict, op_kwargs={}) assert 0 == mock_marshal_param.call_count assert 0 == len(request_dict)
def test_with_mocks(mock_marshal_param): get_op = minimal_swagger_spec.spec_dict['paths']['/pet/{petId}']['get'] del get_op['parameters'][0] op = OperationDecorator(Operation.from_spec( minimal_swagger_spec, '/pet/{petId}', 'get', {})) op.construct_params(request_dict, op_kwargs={}) assert 0 == mock_marshal_param.call_count assert 0 == len(request_dict)
def test_required_parameter_missing( minimal_swagger_spec, getPetById_spec, request_dict): request_dict['url'] = '/pet/{petId}' op = CallableOperation(Operation.from_spec( minimal_swagger_spec, '/pet/{petId}', 'get', getPetById_spec)) with pytest.raises(SwaggerMappingError) as excinfo: construct_params(op, request_dict, op_kwargs={}) assert 'required parameter' in str(excinfo.value)
def test_with_mocks(mock_marshal_param): del getPetById_spec['parameters'][0]['required'] getPetById_spec['parameters'][0]['default'] = 99 request_dict['url'] = '/pet/{petId}' op = CallableOperation(Operation.from_spec( minimal_swagger_spec, '/pet/{petId}', 'get', getPetById_spec)) op.construct_params(request_dict, op_kwargs={}) assert 1 == mock_marshal_param.call_count
def test_with_timeouts(_1, minimal_swagger_spec, getPetById_spec, request_dict, timeout_kv): request_dict['url'] = '/pet/{petId}' op = CallableOperation(Operation.from_spec( minimal_swagger_spec, '/pet/{petId}', 'get', getPetById_spec)) key, value = timeout_kv request = op.construct_request(petId=34, _request_options={key: value}) assert request[key] == value
def test_no_params(mock_marshal_param, minimal_swagger_spec, request_dict): get_op = minimal_swagger_spec.spec_dict['paths']['/pet/{petId}']['get'] del get_op['parameters'][0] op = CallableOperation(Operation.from_spec( minimal_swagger_spec, '/pet/{petId}', 'get', {})) construct_params(op, request_dict, op_kwargs={}) assert 0 == mock_marshal_param.call_count assert 0 == len(request_dict)
def test_with_timeouts(mock_marshal_param, minimal_swagger_spec, getPetById_spec, request_dict, timeout_kv): request_dict['url'] = '/pet/{petId}' op = CallableOperation(Operation.from_spec( minimal_swagger_spec, '/pet/{petId}', 'get', getPetById_spec)) k, v = timeout_kv request = construct_request(op, request_options={k: v}, petId=34, api_key='foo') assert request[k] == v assert mock_marshal_param.call_count == 2
def test_with_not_string_headers( minimal_swagger_dict, getPetById_spec, request_dict, swagger_type, swagger_format, header_name, header_value, ): url = '/pet/{petId}' parameter = { 'name': header_name, 'in': 'header', 'required': False, 'type': swagger_type, } if swagger_format: parameter['format'] = swagger_format minimal_swagger_dict['paths'][url]['get']['parameters'].append(parameter) minimal_swagger_spec = build_swagger_spec(minimal_swagger_dict) request_dict['url'] = url operation = Operation.from_spec( swagger_spec=minimal_swagger_spec, path_name='/pet/{petId}', http_method='get', op_spec=getPetById_spec, ) petId = 34 api_key = 'foo' request = construct_request( operation=operation, request_options={'headers': { header_name: header_value }}, petId=petId, api_key=api_key, ) # To unmarshall a request bravado-core needs the request to be wrapped # by an object with a specific list of attributes request_object = type( 'IncomingRequest', (IncomingRequest, ), { 'path': { 'petId': petId }, 'query': {}, 'form': {}, 'headers': request['headers'], 'files': mock.Mock(), }) assert request['headers'][header_name] == str(header_value) unmarshalled_request = unmarshal_request(request_object, operation) assert unmarshalled_request[header_name] == header_value
def test_operation_id_raises_when_missing_operation_id_and_possible_sanitization_results_in_empty_string( http_method): spec = Spec(spec_dict={}) operation_spec = {} operation = Operation(spec, '/', http_method, operation_spec) with pytest.raises(ValueError) as excinfo: operation.operation_id assert 'empty operation id starting from operation_id=None, http_method={} and path_name=/'.format( http_method, ) in str(excinfo.value)
def test_validate_header_parameter_from_request_options( mock_marshal_param, minimal_swagger_spec, getPetById_spec, request_dict): request_dict['url'] = '/pet/{petId}' request_dict['headers']['api_key'] = 'api_key' op = CallableOperation(Operation.from_spec( minimal_swagger_spec, '/pet/{petId}', 'delete', getPetById_spec)) construct_params(op, request_dict, op_kwargs={'petId': 1}) assert 2 == mock_marshal_param.call_count
def test_consumes_not_present_on_swagger_spec_returns_empty_array( minimal_swagger_dict, ): # The point being, None should never be returned op_spec = { # 'consumes' left out intentionally } minimal_swagger_spec = Spec.from_dict(minimal_swagger_dict) op = Operation(minimal_swagger_spec, '/foo', 'get', op_spec) assert [] == op.consumes
def test_returns_consumes_from_swagger_spec_when_not_present_on_op( minimal_swagger_dict, ): op_spec = { # 'consumes' left out intentionally } minimal_swagger_dict['consumes'] = ['multipart/form-data'] minimal_swagger_spec = Spec.from_dict(minimal_swagger_dict) op = Operation(minimal_swagger_spec, '/foo', 'get', op_spec) assert ['multipart/form-data'] == op.consumes
def test_success_spec_empty_and_body_empty(minimal_swagger_spec): response_spec = { 'description': 'I do not return anything hence I have no "schema" key', } for empty_body in EMPTY_BODIES: response = Mock(spec=OutgoingResponse, text=empty_body) op = Operation(minimal_swagger_spec, '/foo', 'get', op_spec={}) # no exception raised == success validate_response_body(op, response_spec, response)
def test_returns_produces_from_swagger_spec_when_not_present_on_op( minimal_swagger_dict, ): op_spec = { # 'produces' left out intentionally } minimal_swagger_dict['produces'] = ['application/json'] minimal_swagger_spec = Spec.from_dict(minimal_swagger_dict) op = Operation(minimal_swagger_spec, '/foo', 'get', op_spec) assert ['application/json'] == op.produces
def test_success_text_plain_response(minimal_swagger_spec): response_spec = {'description': 'Plain Text Response', 'schema': {}} op = Operation(minimal_swagger_spec, '/foo', 'get', op_spec={'produces': ['text/plain']}) response = Mock(spec=OutgoingResponse, content_type='text/plain', text="Plain Text") validate_response_body(op, response_spec, response)
def test_with_timeouts( mock_marshal_param, minimal_swagger_spec, getPetById_spec, request_dict, timeout_kv, ): request_dict['url'] = '/pet/{petId}' op = CallableOperation(Operation.from_spec( minimal_swagger_spec, '/pet/{petId}', 'get', getPetById_spec)) k, v = timeout_kv request = construct_request(op, request_options={k: v}, petId=34, api_key='foo') assert request[k] == v assert mock_marshal_param.call_count == 2
def test_non_required_parameter_with_default_used( mock_marshal_param, minimal_swagger_spec, getPetById_spec, request_dict): del getPetById_spec['parameters'][0]['required'] getPetById_spec['parameters'][0]['default'] = 99 request_dict['url'] = '/pet/{petId}' op = CallableOperation(Operation.from_spec( minimal_swagger_spec, '/pet/{petId}', 'get', getPetById_spec)) construct_params(op, request_dict, op_kwargs={'api_key': 'foo'}) assert 2 == mock_marshal_param.call_count
def test_no_description(op_spec, empty_swagger_spec): expected = \ "[GET] Finds Pets by status\n\n" \ ":param status: the status, yo! (Default: available) (optional)\n" \ ":type status: array\n" \ ":returns: 200: successful operation\n" \ ":rtype: array:#/definitions/Pet\n" \ ":returns: 400: Invalid status value\n" del op_spec['description'] op = Operation(empty_swagger_spec, '/pet', 'get', op_spec) assert expected == create_operation_docstring(op)
def test_with_not_string_headers( minimal_swagger_dict, getPetById_spec, request_dict, swagger_type, swagger_format, header_name, header_value, ): url = '/pet/{petId}' parameter = { 'name': header_name, 'in': 'header', 'required': False, 'type': swagger_type, } if swagger_format: parameter['format'] = swagger_format minimal_swagger_dict['paths'][url]['get']['parameters'].append(parameter) minimal_swagger_spec = build_swagger_spec(minimal_swagger_dict) request_dict['url'] = url operation = Operation.from_spec( swagger_spec=minimal_swagger_spec, path_name='/pet/{petId}', http_method='get', op_spec=getPetById_spec, ) petId = 34 api_key = 'foo' request = construct_request( operation=operation, request_options={'headers': {header_name: header_value}}, petId=petId, api_key=api_key, ) # To unmarshall a request bravado-core needs the request to be wrapped # by an object with a specific list of attributes request_object = type('IncomingRequest', (IncomingRequest,), { 'path': {'petId': petId}, 'query': {}, 'form': {}, 'headers': request['headers'], 'files': mock.Mock(), }) expected_header_value = str(header_value) # we need to handle a backwards-incompatible change in bravado-core 5.0.5 if swagger_type == 'boolean': assert request['headers'][header_name] in (expected_header_value, expected_header_value.lower()) else: assert request['headers'][header_name] == expected_header_value unmarshalled_request = unmarshal_request(request_object, operation) assert unmarshalled_request[header_name] == header_value
def test_use_msgpack( minimal_swagger_spec, getPetById_spec, ): op = CallableOperation( Operation.from_spec( minimal_swagger_spec, '/pet/{petId}', 'get', getPetById_spec ) ) request = construct_request( op, request_options={ 'use_msgpack': True, }, petId=1, ) assert request['headers']['Accept'] == 'application/msgpack'
def build_resources(swagger_spec): """Transforms the REST resources in the json-like swagger_spec into rich :Resource: objects that have associated :Operation:s. :type swagger_spec: :class:`bravado_core.spec.Spec` :returns: dict where (key,value) = (resource name, Resource) """ # Map operations to resources using operation tags if available. # - If an operation has multiple tags, it will be associated with multiple # resources! # - If an operation has no tags, its resource name will be derived from its # path # key = tag_name value = { operation_id : Operation } tag_to_ops = defaultdict(dict) deref = swagger_spec.deref spec_dict = deref(swagger_spec._internal_spec_dict) paths_spec = deref(spec_dict.get('paths', {})) for path_name, path_spec in iteritems(paths_spec): path_spec = deref(path_spec) for http_method, op_spec in iteritems(path_spec): op_spec = deref(op_spec) # vendor extensions and parameters that are shared across all # operations for a given path are also defined at this level - we # just need to skip over them. if http_method.startswith('x-') or http_method == 'parameters': continue op = Operation.from_spec(swagger_spec, path_name, http_method, op_spec) tags = deref(op_spec.get('tags', [])) if not tags: tags.append(convert_path_to_resource(path_name)) for tag in tags: tag_to_ops[deref(tag)][op.operation_id] = op resources = {} for tag, ops in iteritems(tag_to_ops): resources[tag] = Resource(tag, ops) return resources
def call_on_each_endpoint(self, callback): """Find all server endpoints defined in the swagger spec and calls 'callback' for each, with an instance of EndpointData as argument. """ if 'paths' not in self.swagger_dict: return for path, d in self.swagger_dict['paths'].items(): for method, op_spec in d.items(): data = EndpointData(path, method) # Which server method handles this endpoint? if 'x-bind-server' not in op_spec: if 'x-no-bind-server' in op_spec: # That route should not be auto-generated log.info("Skipping generation of %s %s" % (method, path)) continue else: raise Exception("Swagger api defines no x-bind-server for %s %s" % (method, path)) data.handler_server = op_spec['x-bind-server'] # Make sure that endpoint only produces 'application/json' if 'produces' not in op_spec: raise Exception("Swagger api has no 'produces' section for %s %s" % (method, path)) if len(op_spec['produces']) != 1: raise Exception("Expecting only one type under 'produces' for %s %s" % (method, path)) if op_spec['produces'][0] == 'application/json': data.produces_json = True elif op_spec['produces'][0] == 'text/html': data.produces_html = True else: raise Exception("Only 'application/json' or 'text/html' are supported. See %s %s" % (method, path)) # Which client method handles this endpoint? if 'x-bind-client' in op_spec: data.handler_client = op_spec['x-bind-client'] # Should we decorate the server handler? if 'x-decorate-server' in op_spec: data.decorate_server = op_spec['x-decorate-server'] # Should we manipulate the requests parameters? if 'x-decorate-request' in op_spec: data.decorate_request = op_spec['x-decorate-request'] # Generate a bravado-core operation object data.operation = Operation.from_spec(self.spec, path, method, op_spec) # Figure out how parameters are passed: one json in body? one or # more values in query? if 'parameters' in op_spec: params = op_spec['parameters'] for p in params: if p['in'] == 'body': data.param_in_body = True if p['in'] == 'query': data.param_in_query = True if p['in'] == 'path': data.param_in_path = True if data.param_in_path: # Substitute {...} with <...> in path, to make a Flask friendly path data.path = data.path.replace('{', '<').replace('}', '>') if data.param_in_body and data.param_in_query: raise Exception("Cannot support params in both body and param (%s %s)" % (method, path)) else: data.no_params = True callback(data)
def test_extra_parameter_error(minimal_swagger_spec, request_dict): op = CallableOperation(Operation.from_spec( minimal_swagger_spec, '/pet/{petId}', 'get', {})) with pytest.raises(SwaggerMappingError) as excinfo: construct_params(op, request_dict, op_kwargs={'extra_param': 'bar'}) assert 'does not have parameter' in str(excinfo.value)
def test_success(minimal_swagger_spec, getPetById_spec, request_dict): request_dict['url'] = '/pet/{petId}' op = CallableOperation(Operation.from_spec( minimal_swagger_spec, '/pet/{petId}', 'get', getPetById_spec)) assert op.__doc__.startswith('[GET] Find pet by ID')
def test_with_mocks(mock_marshal_param): request_dict['url'] = '/pet/{petId}' op = Operation.from_spec( minimal_swagger_spec, '/pet/{petId}', 'get', getPetById_spec) op.construct_params(request_dict, op_kwargs={'petId': 34}) assert 1 == mock_marshal_param.call_count