예제 #1
0
def test_empty_handler_signature(
    mocker: ptm.MockFixture,
    caplog: logging.LogCaptureFixture,
) -> None:
    async def foo() -> pipeline.Response:
        ...

    handler._resolve(
        handler=foo,
        operation=list(
            parser._resolve_operations(
                components={},
                paths={
                    '/{name}': {
                        'post': {
                            'operationId': 'TestAnalysisNoParameters',
                            'responses': {
                                'default': {
                                    'description': 'fake',
                                },
                            },
                        },
                    },
                },
            ), )[0],
        request_processor=mocker.Mock(),
        response_processor=mocker.Mock(),
    )

    assert 'TestAnalysisNoParameters does not declare any parameters' in caplog.messages
def test_headers_cookies_any(
    caplog: logging.LogCaptureFixture,
    mocker: ptm.MockFixture,
) -> None:
    class R(te.TypedDict):
        headers: t.Any
        cookies: t.Any
        return_code: int

    async def test() -> R:
        ...

    handler._resolve(
        handler=test,
        operation=_make_operation({
            '204': {
                'description': 'Incorrect return type',
            },
        }),
        request_processor=mocker.Mock(),
        response_processor=mocker.Mock(),
    )

    for msg in (
            'Detected usage of "return.headers" declared as typing.Any.',
            'Detected usage of "return.cookies" declared as typing.Any.',
    ):
        assert any(
            filter(lambda m: t.cast(str, m).startswith(msg), caplog.messages))
def test_incorrect_return_http_code(
    return_code: t.Type[t.Any],
    mocker: ptm.MockFixture,
) -> None:
    test_returns = te.TypedDict(  # type: ignore
        f'ReturnWithCodeAs_{return_code}',
        {'http_code': return_code},
    )

    async def test() -> test_returns:
        ...

    with pytest.raises(handler.InvalidHandlerError) as err:
        handler._resolve(
            handler=test,
            operation=_make_operation({
                '204': {
                    'description': 'Incorrect return type',
                },
            }),
            request_processor=mocker.Mock(),
            response_processor=mocker.Mock(),
        )

    assert err
    assert err.value
    assert 1 == len(err.value)
def test_incorrect_return_type(
    return_type: t.Type[t.Any],
    mocker: ptm.MockFixture,
) -> None:
    async def test() -> return_type:  # type: ignore
        ...

    with pytest.raises(handler.InvalidHandlerError) as err:
        handler._resolve(
            handler=test,
            operation=_make_operation({
                '204': {
                    'description': 'Incorrect return type',
                },
            }),
            request_processor=mocker.Mock(),
            response_processor=mocker.Mock(),
        )

    assert err
    assert err.value
    assert 1 == len(err.value)
    assert 'return' in err.value

    assert (
        f'expected [{get_type_repr.get_repr(pipeline.Response)}], but got '
        f'{get_type_repr.get_repr(return_type if return_type else type(None))}'
    ) == err.value['return']
def test_omitted_return_code_couple_oas_resp(mocker: ptm.MockFixture) -> None:
    test_returns = te.TypedDict(  # type: ignore
        'MissingHttpCode',
        {'body': t.Dict[str, int]},
    )

    async def test() -> test_returns:
        ...

    with pytest.raises(handler.InvalidHandlerError) as err:
        handler._resolve(
            handler=test,
            operation=_make_operation({
                '200': {
                    'description': 'I am alone',
                },
                '300': {
                    'description': 'I am alone',
                },
            }),
            request_processor=mocker.Mock(),
            response_processor=mocker.Mock(),
        )

    assert err
    assert err.value
    assert 1 == len(err.value)
    assert 'return.http_code' in err.value
    assert 'missing' == err.value['return.http_code']
예제 #6
0
def test_not_empty_signature(
    caplog: logging.LogCaptureFixture,
    mocker: ptm.MockFixture,
) -> None:
    async def foo(
        name: str,
        foo: str,
        bar: str,
        lorem_ipsum: t.List[str],
    ) -> pipeline.Response:
        ...

    with pytest.raises(handler.InvalidHandlerError) as err:
        handler._resolve(
            handler=foo,
            operation=list(
                parser._resolve_operations(
                    components={},
                    paths={
                        '/{name}': {
                            'parameters': [
                                {
                                    'name': 'name',
                                    'in': 'path',
                                    'required': True,
                                    'schema': {
                                        'type': 'string',
                                    },
                                },
                            ],
                            'post': {
                                'operationId': 'Thor',
                                'responses': {
                                    'default': {
                                        'description': 'fake',
                                    },
                                },
                            },
                        },
                    },
                ), )[0],
            request_processor=mocker.Mock(),
            response_processor=mocker.Mock(),
        )

    assert len(err.value) == 3

    assert err.value['foo'] == 'unexpected'
    assert err.value['bar'] == 'unexpected'
    assert err.value['lorem_ipsum'] == 'unexpected'

    assert (
        'Unconsumed arguments [foo, bar, lorem_ipsum] detected in Thor handler signature'
        in caplog.messages)
def test_signature_empty_oas_cookies(
    mocker: ptm.MockFixture,
    caplog: logging.LogCaptureFixture,
) -> None:
    async def foo(name: str) -> pipeline.Response:
        ...

    hdrl = handler._resolve(
        foo,
        next(filter(lambda op: op.id == 'cookies_op', operations)),
        request_processor=mocker.Mock(),
        response_processor=mocker.Mock(),
    )

    msg = (
        '"cookies" found in operation but not in signature. '
        'Please double check that. axion cannot infer a correctness of '
        'this situations. If you wish to access any "cookies" defined in '
        'specification, they have to be present in your handler '
        'as '
    )

    assert id(hdrl.user_handler) == id(foo)
    assert not hdrl.cookie_params
    assert any(filter(lambda m: t.cast(str, m).startswith(msg), caplog.messages))
def test_valid_cookies_any_type(
    the_type: t.Type[t.Any],
    caplog: logging.LogCaptureFixture,
    mocker: ptm.MockFixture,
) -> None:
    async def foo(name: str, cookies: the_type) -> pipeline.Response:  # type: ignore
        ...

    hdrl = handler._resolve(
        foo,
        next(filter(lambda op: op.id == 'cookies_op', operations)),
        request_processor=mocker.Mock(),
        response_processor=mocker.Mock(),
    )

    assert id(hdrl.user_handler) == id(foo)
    assert hdrl.cookie_params
    assert len(hdrl.cookie_params) == 2
    assert ('csrftoken', 'csrftoken') in hdrl.cookie_params.items()
    assert ('debug', 'debug') in hdrl.cookie_params.items()
    msg = (
        'Detected usage of "cookies" declared as typing.Any. '
        'axion will allow such declaration but be warned that '
        'you will loose all the help linters (like mypy) offer.'
    )
    assert msg in caplog.messages
def test_signature_all_missing(mocker: ptm.MockFixture) -> None:
    async def foo() -> pipeline.Response:
        ...

    with pytest.raises(handler.InvalidHandlerError) as err:
        handler._resolve(
            handler=foo,
            operation=operation,
            request_processor=mocker.Mock(),
            response_processor=mocker.Mock(),
        )

    assert err.value.operation_id == 'TestAnalysisParameters'
    assert len(err.value) == 4
    for key in ('id', 'limit', 'page', 'includeExtra'):
        assert key in err.value
        assert err.value[key] == 'missing'
def test_signature_set_bad_oas_cookies_unknown(
    the_type: t.Type[t.Any],
    extra_param: str,
    mocker: ptm.MockFixture,
) -> None:
    async def foo(name: str, cookies: the_type) -> pipeline.Response:  # type: ignore
        ...

    with pytest.raises(handler.InvalidHandlerError) as err:
        handler._resolve(
            foo,
            next(filter(lambda op: op.id == 'cookies_op', operations)),
            request_processor=mocker.Mock(),
            response_processor=mocker.Mock(),
        )

    assert len(err.value) == 1
    assert f'cookies.{extra_param}' in err.value
    assert err.value[f'cookies.{extra_param}'] == 'unknown'
def test_correct_handler_no_oas_body(
    response_code: int,
    return_type: t.Type[t.Any],
    mocker: ptm.MockFixture,
) -> None:
    async def test() -> return_type:  # type: ignore
        ...

    operation = _make_operation({
        f'{response_code}': {
            'description': f'Returning {return_type}',
        },
    })
    handler._resolve(
        handler=test,
        operation=operation,
        request_processor=mocker.Mock(),
        response_processor=mocker.Mock(),
    )
def test_signature_mismatch_missing(mocker: ptm.MockFixture) -> None:
    async def foo(
        limit: t.Optional[int],
        page: t.Optional[float],
        include_extra: t.Optional[bool],
    ) -> pipeline.Response:
        ...

    with pytest.raises(handler.InvalidHandlerError) as err:
        handler._resolve(
            handler=foo,
            operation=operation,
            request_processor=mocker.Mock(),
            response_processor=mocker.Mock(),
        )

    assert err.value.operation_id == 'TestAnalysisParameters'
    assert len(err.value) == 1
    assert 'id' in err.value
    assert err.value['id'] == 'missing'
def test_signature_set_no_oas_cookies(
    the_type: t.Type[t.Any],
    caplog: logging.LogCaptureFixture,
    mocker: ptm.MockFixture,
) -> None:
    async def foo(name: str, cookies: the_type) -> pipeline.Response:  # type: ignore
        ...

    with pytest.raises(handler.InvalidHandlerError) as err:
        handler._resolve(
            foo,
            next(filter(lambda op: op.id == 'no_cookies_op', operations)),
            request_processor=mocker.Mock(),
            response_processor=mocker.Mock(),
        )

    assert len(err.value) == 1
    assert 'cookies' in err.value
    assert err.value['cookies'] == 'unexpected'
    assert '"cookies" found in signature but not in operation' in caplog.messages
def test_signature_set_bad_oas_cookies_type_mismatch(
    the_type: t.Type[t.Any],
    expected_errors: t.List[t.Tuple[str, str]],
    mocker: ptm.MockFixture,
) -> None:
    async def foo(name: str, cookies: the_type) -> pipeline.Response:  # type: ignore
        ...

    with pytest.raises(handler.InvalidHandlerError) as err:
        handler._resolve(
            foo,
            next(filter(lambda op: op.id == 'cookies_op', operations)),
            request_processor=mocker.Mock(),
            response_processor=mocker.Mock(),
        )

    assert len(err.value) == len(expected_errors)
    for param_key, error_msg in expected_errors:
        assert f'cookies.{param_key}' in err.value
        assert err.value[f'cookies.{param_key}'] == error_msg
def test_missing_return_annotation(mocker: ptm.MockFixture) -> None:
    async def test():  # type: ignore
        ...

    with pytest.raises(handler.InvalidHandlerError) as err:
        handler._resolve(
            handler=test,
            operation=_make_operation({
                '204': {
                    'description': 'It will not work anyway',
                },
            }),
            request_processor=mocker.Mock(),
            response_processor=mocker.Mock(),
        )

    assert err
    assert err.value
    assert 1 == len(err.value)
    assert 'return' in err.value
    assert 'missing' == err.value['return']
def test_omitted_return_code_single_oas_resp(
    response_code: t.Union[str, te.Literal['default']],
    mocker: ptm.MockFixture,
) -> None:
    test_returns = te.TypedDict(  # type: ignore
        'MissingHttpCode',
        {'body': t.Dict[str, int]},
    )

    async def test() -> test_returns:
        ...

    handler._resolve(
        handler=test,
        operation=_make_operation({
            f'{response_code}': {
                'description': 'I am alone',
            },
        }),
        request_processor=mocker.Mock(),
        response_processor=mocker.Mock(),
    )
def test_incorrect_cookies_type(
    cookies_type: t.Type[t.Any],
    mocker: ptm.MockFixture,
) -> None:
    test_returns = te.TypedDict(  # type: ignore
        'RV_Bad_Cookies',
        {
            'http_code': int,
            'cookies': cookies_type
        },  # type: ignore
    )

    async def test() -> test_returns:
        ...

    with pytest.raises(handler.InvalidHandlerError) as err:
        handler._resolve(
            handler=test,
            operation=_make_operation({
                '204': {
                    'description': 'Incorrect return type',
                },
            }),
            request_processor=mocker.Mock(),
            response_processor=mocker.Mock(),
        )

    assert err
    assert err.value
    assert 1 == len(err.value)
    assert 'return.cookies' in err.value

    assert (f'expected ['
            f'typing.Mapping[str, typing.Any],'
            f'typing.Dict[str, typing.Any],'
            f'typing_extensions.TypedDict], '
            f'but got '
            f'{get_type_repr.get_repr(cookies_type)}'
            ) == err.value['return.cookies']
def test_invalid_cookies_type(
    op_id: str,
    the_type: t.Type[t.Any],
    mocker: ptm.MockFixture,
) -> None:
    async def foo(name: str, cookies: the_type) -> pipeline.Response:  # type: ignore
        ...

    with pytest.raises(handler.InvalidHandlerError) as err:
        handler._resolve(
            foo,
            next(filter(lambda op: op.id == op_id, operations)),
            request_processor=mocker.Mock(),
            response_processor=mocker.Mock(),
        )

    assert len(err.value) == 1
    assert 'cookies' in err.value
    assert err.value['cookies'] == (
        f'expected [typing.Mapping[str, typing.Any],'
        f'typing.Dict[str, typing.Any],typing_extensions.TypedDict]'
        f', but got {get_type_repr.get_repr(the_type)}'
    )
def test_signature_all_bad_type(mocker: ptm.MockFixture) -> None:
    async def foo(
        id: float,
        limit: t.Optional[t.Union[float, int]],
        page: t.Optional[t.AbstractSet[bool]],
        include_extra: t.Union[int, str],
    ) -> pipeline.Response:
        ...

    with pytest.raises(handler.InvalidHandlerError) as err:
        handler._resolve(
            handler=foo,
            operation=operation,
            request_processor=mocker.Mock(),
            response_processor=mocker.Mock(),
        )

    assert err.value.operation_id == 'TestAnalysisParameters'
    assert len(err.value) == 4
    for mismatch in err.value:
        actual_msg = err.value[mismatch.param_name]
        expected_msg = None

        if mismatch.param_name == 'id':
            expected_msg = 'expected [str], but got float'
        elif mismatch.param_name == 'limit':
            expected_msg = ('expected [typing.Optional[int]], but got '
                            'typing.Optional[typing.Union[float, int]]')
        elif mismatch.param_name == 'page':
            expected_msg = ('expected [typing.Optional[float]], but got '
                            'typing.Optional[typing.AbstractSet[bool]]')
        elif mismatch.param_name == 'includeExtra':
            expected_msg = ('expected [typing.Optional[bool]], but got '
                            'typing.Union[int, str]')

        assert expected_msg is not None
        assert actual_msg == expected_msg
def test_signature_empty_no_oas_cookies(
    mocker: ptm.MockFixture,
    caplog: logging.LogCaptureFixture,
) -> None:
    async def foo(name: str) -> pipeline.Response:
        ...

    hdrl = handler._resolve(
        foo,
        next(filter(lambda op: op.id == 'no_cookies_op', operations)),
        request_processor=mocker.Mock(),
        response_processor=mocker.Mock(),
    )

    assert id(hdrl.user_handler) == id(foo)
    assert not hdrl.cookie_params
    assert 'No "cookies" in signature and operation parameters' in caplog.messages
def test_signature_match(mocker: ptm.MockFixture) -> None:
    async def test_handler(
        id: str,
        limit: t.Optional[int],
        page: t.Optional[float],
        include_extra: t.Optional[bool],
    ) -> pipeline.Response:
        ...

    hdrl = handler._resolve(
        handler=test_handler,
        operation=operation,
        request_processor=mocker.Mock(),
        response_processor=mocker.Mock(),
    )

    assert len(hdrl.path_params) == 1
    assert len(hdrl.query_params) == 3
def test_signature_set_oas_cookies(
    the_type: t.Type[t.Any],
    caplog: logging.LogCaptureFixture,
    mocker: ptm.MockFixture,
) -> None:
    async def foo(name: str, cookies: the_type) -> pipeline.Response:  # type: ignore
        ...

    hdrl = handler._resolve(
        foo,
        next(filter(lambda op: op.id == 'cookies_op', operations)),
        request_processor=mocker.Mock(),
        response_processor=mocker.Mock(),
    )

    assert id(hdrl.user_handler) == id(foo)
    assert hdrl.cookie_params

    assert ('csrftoken', 'csrftoken') in hdrl.cookie_params.items()
    assert ('debug', 'debug') in hdrl.cookie_params.items()

    assert '"cookies" found both in signature and operation' in caplog.messages