def test_get_params_from_func(self): get_foo._doctor_signature = inspect.signature(get_foo) expected = Params(all=['name', 'age', 'is_alive'], optional=['is_alive'], required=['name', 'age'], logic=['name', 'age', 'is_alive']) assert expected == get_params_from_func(get_foo)
def test_add_param_annotations(self): new_params = [ RequestParamAnnotation('auth', Auth, required=True), RequestParamAnnotation('is_deleted', IsDeleted) ] actual = add_param_annotations(get_foo, new_params) # auth and is_deleted should be added to `all`. # auth should be added to `required`. # is_deleted should be added to `optional`. # `logic` should be unmodified. expected_params = Params( all=['name', 'age', 'is_alive', 'auth', 'is_deleted'], logic=['name', 'age', 'is_alive'], required=['name', 'age', 'auth'], optional=['is_alive', 'is_deleted']) assert expected_params == actual._doctor_params # verify `auth` added to the doctor_signature. expected = Parameter('auth', Parameter.KEYWORD_ONLY, default=Parameter.empty, annotation=Auth) auth = actual._doctor_signature.parameters['auth'] assert expected == auth # verify `is_deleted` added to the doctor signature. expected = Parameter('is_deleted', Parameter.KEYWORD_ONLY, default=None, annotation=IsDeleted) is_deleted = actual._doctor_signature.parameters['is_deleted'] assert expected == is_deleted
def test_handle_http_decorator_adds_param_annotations(mock_request, mock_get_logic): """ This test verifies if a decorator uses doctor.utils.add_param_annotations to add params to the logic function that we fail to validate if the added params are missing or invalid. """ mock_request.method = 'GET' mock_request.content_type = 'application/x-www-form-urlencoded' mock_request.values = {'item_id': '1'} mock_handler = mock.Mock() logic = check_auth(add_doctor_attrs(get_item)) expected_params = Params(all=['item_id', 'include_deleted', 'auth'], optional=['include_deleted'], required=['item_id', 'auth'], logic=['item_id', 'include_deleted']) assert expected_params == logic._doctor_params with pytest.raises(HTTP400Exception, match='auth is required'): handle_http(mock_handler, (), {}, logic) # Add auth and it should validate mock_request.values = {'item_id': '1', 'auth': 'auth'} actual = handle_http(mock_handler, (), {}, logic) assert actual == ({'item_id': 1}, 200)
def test_add_param_annotations_mutliple_calls(self): """ This test verifies if we call this function multiple times with the same logic function that it doesn't squash parameters added from the previous call. This is a regression test. """ delattr(get_foo, '_doctor_signature') new_params = [ RequestParamAnnotation('auth', Auth, required=True), ] actual = add_param_annotations(get_foo, new_params) expected_params = Params(all=['name', 'age', 'is_alive', 'auth'], logic=['name', 'age', 'is_alive'], required=['name', 'age', 'auth'], optional=['is_alive']) assert expected_params == actual._doctor_params # verify `auth` added to the doctor_signature. expected = Parameter('auth', Parameter.KEYWORD_ONLY, default=Parameter.empty, annotation=Auth) auth = actual._doctor_signature.parameters['auth'] assert expected == auth # Now call again adding the is_deleted param. It should add to and # not replace the auth param we added previously. new_params = [RequestParamAnnotation('is_deleted', IsDeleted)] actual = add_param_annotations(get_foo, new_params) expected_params = Params( all=['name', 'age', 'is_alive', 'auth', 'is_deleted'], logic=['name', 'age', 'is_alive'], required=['name', 'age', 'auth'], optional=['is_alive', 'is_deleted']) assert expected_params == actual._doctor_params # verify `is_deleted` added to the doctor signature. expected = Parameter('is_deleted', Parameter.KEYWORD_ONLY, default=None, annotation=IsDeleted) is_deleted = actual._doctor_signature.parameters['is_deleted'] assert expected == is_deleted
def test_get_params_from_func_decorated_func(self): """ Verifies that we don't include the `extra` param as required since it's not a sublcass of `SuperType` and is passed to the function by a decorator. """ decorated_func._doctor_signature = inspect.signature(decorated_func) expected = Params(all=['extra', 'name', 'is_alive'], required=['name'], optional=['is_alive'], logic=['extra', 'name', 'is_alive']) assert expected == get_params_from_func(decorated_func)
def test_get_params_from_func_no_params(self): # no signature passed or defined on the function expected = Params([], [], [], []) assert expected == get_params_from_func(no_params) # signature passed in signature = inspect.signature(no_params) assert expected == get_params_from_func(no_params, signature) # signature attached to logic function no_params._doctor_signature = inspect.signature(no_params) assert expected == get_params_from_func(no_params)
def test_httpmethod(self): m = HTTPMethod('get', get_foo, allowed_exceptions=[ValueError], title='Retrieve') assert 'get' == m.method assert inspect.signature(get_foo) == m.logic._doctor_signature expected = Params(all=['name', 'age', 'is_alive'], optional=['is_alive'], required=['name', 'age'], logic=['name', 'age', 'is_alive']) assert expected == m.logic._doctor_params assert [ValueError] == m.logic._doctor_allowed_exceptions assert 'Retrieve' == m.logic._doctor_title assert m.logic._doctor_req_obj_type is None
def test_httpmethod_with_req_obj_type(self): m = HTTPMethod('get', get_foo, allowed_exceptions=[ValueError], title='Retrieve', req_obj_type=FooInstance) assert 'get' == m.method assert inspect.signature(get_foo) == m.logic._doctor_signature expected = Params(all=['foo', 'foo_id'], optional=['foo'], required=['foo_id'], logic=['foo', 'foo_id']) assert expected == m.logic._doctor_params assert [ValueError] == m.logic._doctor_allowed_exceptions assert 'Retrieve' == m.logic._doctor_title assert FooInstance == m.logic._doctor_req_obj_type
def test_create_routes(self): class MyHandler(Resource): pass routes = ( Route('^/foo/?$', (get(get_foos, title='Retrieve List'), post(create_foo)), base_handler_class=MyHandler, handler_name='MyHandler', heading='Foo'), Route('^/foo/<int:foo_id>/?$', (delete(delete_foo), get(get_foo), put(update_foo)), heading='Foo'), Route('^/foos/?$', (put(lambda: 'put'), ), heading='Foo'), ) actual = create_routes(routes, handle_http, Resource) # 2 routes created assert 3 == len(actual) # verify the first route route, handler = actual[0] assert r'^/foo/?$' == route # verify it's an instance of our base handler class. assert issubclass(handler, MyHandler) # verify it used our custom handler name assert 'MyHandler' == handler.__name__ # verify each http method was added assert hasattr(handler, 'get') assert hasattr(handler, 'post') # verify heading attr was added to handler assert handler._doctor_heading == 'Foo' # verify params for get params = handler.get._doctor_params expected = Params(all=['is_alive'], required=[], optional=['is_alive'], logic=['is_alive']) assert expected == params # verify signature sig = handler.get._doctor_signature expected = inspect.signature(get_foos) assert expected == sig # verify custom title assert 'Retrieve List' == handler.get._doctor_title # verify params for post params = handler.post._doctor_params expected = Params(all=['name'], required=['name'], optional=[], logic=['name']) assert expected == params # verify signature sig = handler.post._doctor_signature expected = inspect.signature(create_foo) assert expected == sig # verify the second route route, handler = actual[1] assert '^/foo/<int:foo_id>/?$' == route # verify each http method was added assert hasattr(handler, 'get') assert hasattr(handler, 'delete') assert hasattr(handler, 'put') # verify it generated an appropriate class handler name assert 'FooHandler' == handler.__name__ # Verify the 3rd handler which would have had a conflicting handler # name has a number appended to the end of it. route, handler = actual[2] assert 'FooHandler2' == handler.__name__