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)
Exemple #7
0
 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
Exemple #8
0
 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
Exemple #9
0
    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__