Beispiel #1
0
    async def test_aiohttp_output_stream__ok__nominal_case(self, aiohttp_client, loop):
        hapic = Hapic(async_=True, processor_class=MarshmallowProcessor)

        class AsyncGenerator:
            def __init__(self):
                self._iterator = iter([{"name": "Hello, bob"}, {"name": "Hello, franck"}])

            async def __aiter__(self):
                return self

            async def __anext__(self):
                return next(self._iterator)

        class OuputStreamItemSchema(marshmallow.Schema):
            name = marshmallow.fields.String()

        @hapic.output_stream(OuputStreamItemSchema())
        async def hello(request):
            return AsyncGenerator()

        app = web.Application(debug=True)
        app.router.add_get("/", hello)
        hapic.set_context(
            AiohttpContext(app, default_error_builder=MarshmallowDefaultErrorBuilder())
        )
        client = await aiohttp_client(app)

        resp = await client.get("/")
        assert resp.status == 200

        line = await resp.content.readline()
        assert b'{"name": "Hello, bob"}\n' == line

        line = await resp.content.readline()
        assert b'{"name": "Hello, franck"}\n' == line
Beispiel #2
0
    def test_func_schema_in_doc__ok__additionals_fields__file(self):
        hapic = Hapic(processor_class=MarshmallowProcessor)
        app = AgnosticApp()
        hapic.set_context(AgnosticContext(app=app))

        class MySchema(marshmallow.Schema):
            category = marshmallow.fields.Raw(required=True,
                                              description="a description",
                                              example="00010")

        @hapic.with_api_doc()
        @hapic.input_files(MySchema())
        def my_controller():
            return

        app.route("/upload", method="POST", callback=my_controller)
        doc = hapic.generate_doc()
        assert doc
        assert "/upload" in doc["paths"]
        assert "consumes" in doc["paths"]["/upload"]["post"]
        assert "multipart/form-data" in doc["paths"]["/upload"]["post"][
            "consumes"]
        assert doc.get("paths").get("/upload").get("post").get("parameters")[0]
        field = doc.get("paths").get("/upload").get("post").get(
            "parameters")[0]
        assert field[
            "description"] == "a description\n\n*example value: 00010*"
        # INFO - G.M - 01-06-2018 - Field example not allowed here,
        # added in description instead
        assert "example" not in field
        assert field["in"] == "formData"
        assert field["type"] == "file"
        assert field["required"] is True
Beispiel #3
0
    async def test_unit__input_error__err__hook_called(self, aiohttp_client):
        hapic = Hapic(async_=True, processor_class=MarshmallowProcessor)

        class InputPathSchema(marshmallow.Schema):
            user_id = marshmallow.fields.Int(required=True)

        class MyContext(AiohttpContext):
            def __init__(self, *args, **kwargs):
                super().__init__(*args, **kwargs)
                self.hook_called = None

            def input_validation_error_caught(
                    self, request_parameters: RequestParameters,
                    process_exception: ProcessException) -> None:
                self.hook_called = request_parameters

        @hapic.with_api_doc()
        @hapic.input_path(InputPathSchema())
        async def user():
            pass

        app = web.Application(debug=True)
        context = MyContext(app)
        hapic.set_context(context)
        app.router.add_get("/user", user)
        client = await aiohttp_client(app)

        assert not context.hook_called
        await client.get("/user?foo=bar")
        assert context.hook_called.query_parameters.get("foo") == "bar"
Beispiel #4
0
    def test_func__input_files_doc__ok__one_file_and_text(self):
        hapic = Hapic()
        hapic.set_context(MyContext())
        app = bottle.Bottle()

        class MySchema(marshmallow.Schema):
            name = marshmallow.fields.String(required=True)

        class MyFilesSchema(marshmallow.Schema):
            file_abc = marshmallow.fields.Raw(required=True)

        @hapic.with_api_doc()
        @hapic.input_files(MyFilesSchema())
        @hapic.input_body(MySchema())
        def my_controller(hapic_data=None):
            assert hapic_data
            assert hapic_data.files

        app.route('/upload', method='POST', callback=my_controller)
        doc = hapic.generate_doc(app)

        assert doc
        assert '/upload' in doc['paths']
        assert 'consume' in doc['paths']['/upload']['post']
        assert 'multipart/form-data' in doc['paths']['/upload']['post'][
            'consume']
        assert 'parameters' in doc['paths']['/upload']['post']
        assert {
            'name': 'file_abc',
            'required': True,
            'in': 'formData',
            'type': 'file',
        } in doc['paths']['/upload']['post']['parameters']
Beispiel #5
0
    async def test_unit__output_error__err__hook_called(self, aiohttp_client):
        hapic = Hapic(async_=True, processor_class=MarshmallowProcessor)

        class OutputBodySchema(marshmallow.Schema):
            user_id = marshmallow.fields.Int(required=True)

        class MyContext(AiohttpContext):
            def __init__(self, *args, **kwargs):
                super().__init__(*args, **kwargs)
                self.hook_called = False

            def output_validation_error_caught(
                    self, hapic_data: HapicData,
                    process_exception: ProcessException) -> None:
                self.hook_called = True

        @hapic.with_api_doc()
        @hapic.output_body(OutputBodySchema())
        async def user(request):
            return {}

        app = web.Application(debug=True)
        context = MyContext(app)
        hapic.set_context(context)
        app.router.add_get("/user", user)
        client = await aiohttp_client(app)

        assert not context.hook_called
        await client.get("/user")
        assert context.hook_called
Beispiel #6
0
    async def test_aiohttp_input_body__error__incorrect_input_body(
            self, aiohttp_client, loop):
        hapic = Hapic(async_=True, processor_class=MarshmallowProcessor)

        class InputBodySchema(marshmallow.Schema):
            i = marshmallow.fields.Integer()

        @hapic.input_body(InputBodySchema())
        async def hello(request, hapic_data: HapicData):
            i = hapic_data.body.get("i")
            return web.Response(text="integer, {}".format(i))

        app = web.Application(debug=True)
        app.router.add_post("/", hello)
        hapic.set_context(
            AiohttpContext(
                app, default_error_builder=MarshmallowDefaultErrorBuilder()))
        client = await aiohttp_client(app)

        resp = await client.post("/", data={"i": "bob"})  # NOTE: should be int
        assert resp.status == 400

        error = await resp.json()
        assert "Validation error of input data" in error.get("message")
        assert {"i": ["Not a valid integer."]} == error.get("details")
Beispiel #7
0
    async def test_aiohttp_output_body__error__incorrect_output_body(
            self, aiohttp_client, loop):
        hapic = Hapic(async_=True, processor_class=MarshmallowProcessor)

        class OuputBodySchema(marshmallow.Schema):
            i = marshmallow.fields.Integer(required=True)

        @hapic.output_body(OuputBodySchema())
        async def hello(request):
            return {"i": "bob"}  # NOTE: should be integer

        app = web.Application(debug=True)
        app.router.add_get("/", hello)
        hapic.set_context(
            AiohttpContext(
                app, default_error_builder=MarshmallowDefaultErrorBuilder()))
        client = await aiohttp_client(app)

        resp = await client.get("/")
        assert resp.status == 500

        data = await resp.text()
        data = await resp.json()
        assert "Validation error of output data" == data.get("message")
        assert {
            "i": ["Missing data for required field."]
        } == data.get("details")
Beispiel #8
0
    def test_unit__generate_output_stream_doc__ok__nominal_case(
            self, aiohttp_client, loop):
        hapic = Hapic(async_=True, processor_class=MarshmallowProcessor)

        class OuputStreamItemSchema(marshmallow.Schema):
            name = marshmallow.fields.String(required=True)

        @hapic.with_api_doc()
        @hapic.output_stream(OuputStreamItemSchema())
        async def get_users(request, hapic_data):
            pass

        app = web.Application(debug=True)
        app.router.add_get("/", get_users)
        hapic.set_context(
            AiohttpContext(
                app, default_error_builder=MarshmallowDefaultErrorBuilder()))

        doc = hapic.generate_doc("aiohttp", "testing")
        # INFO BS 2019-04-15: Prevent keep of OrderedDict
        doc = json.loads(json.dumps(doc))

        assert "/" in doc.get("paths")
        assert "get" in doc["paths"]["/"]
        assert "200" in doc["paths"]["/"]["get"].get("responses", {})
        assert {
            "items": {
                "$ref": "#/definitions/OuputStreamItemSchema"
            },
            "type": "array"
        } == doc["paths"]["/"]["get"]["responses"]["200"]["schema"]
    def test_func__catch_one_exception__ok__pyramid(self):
        from pyramid.config import Configurator

        configurator = Configurator(autocommit=True)
        context = PyramidContext(
            configurator,
            default_error_builder=MarshmallowDefaultErrorBuilder())
        hapic = Hapic(processor_class=MarshmallowProcessor)
        hapic.set_context(context)

        def my_view(context, request):
            raise ZeroDivisionError("An exception message")

        configurator.add_route("my_view", "/my-view", request_method="GET")
        configurator.add_view(my_view, route_name="my_view", renderer="json")

        # FIXME - G.M - 17-05-2018 - Verify if:
        # - other view that work/raise an other exception do not go
        # into this code for handle this exceptions.
        # - response come clearly from there, not from web framework:
        #  Check not only http code, but also body.
        # see  issue #158 (https://github.com/algoo/hapic/issues/158)
        context.handle_exception(ZeroDivisionError, http_code=400)

        app = configurator.make_wsgi_app()
        test_app = TestApp(app)
        response = test_app.get("/my-view", status="*")

        assert 400 == response.status_code
Beispiel #10
0
    async def test_aiohttp_input_path__error_wrong_input_parameter(
            self, aiohttp_client, loop):
        hapic = Hapic(async_=True, processor_class=MarshmallowProcessor)

        class InputPathSchema(marshmallow.Schema):
            i = marshmallow.fields.Integer()

        @hapic.input_path(InputPathSchema())
        async def hello(request, hapic_data: HapicData):
            i = hapic_data.path.get("i")
            return web.Response(text="integer: {}".format(str(i)))

        app = web.Application(debug=True)
        app.router.add_get("/{i}", hello)
        hapic.set_context(
            AiohttpContext(
                app, default_error_builder=MarshmallowDefaultErrorBuilder()))
        client = await aiohttp_client(app)

        resp = await client.get("/bob")  # NOTE: should be integer here
        assert resp.status == 400

        error = await resp.json()
        assert "Validation error of input data" in error.get("message")
        assert {"i": ["Not a valid integer."]} == error.get("details")
Beispiel #11
0
    async def test_unit__general_exception_handling__ok__nominal_case(
            self, aiohttp_client, loop):
        hapic = Hapic(async_=True, processor_class=MarshmallowProcessor)

        @hapic.with_api_doc()
        async def hello(request):
            return 1 / 0

        app = web.Application(debug=True)
        app.router.add_get("/", hello)
        context = AiohttpContext(
            app, default_error_builder=MarshmallowDefaultErrorBuilder())
        context.handle_exception(ZeroDivisionError, 400)
        hapic.set_context(context)

        client = await aiohttp_client(app)
        resp = await client.get("/")

        json = await resp.json()
        assert resp.status == 400
        assert {
            "details": {
                "error_detail": {}
            },
            "message": "division by zero",
            "code": None,
        } == json
Beispiel #12
0
    def test_func__schema_in_doc__ok__many_case(self):
        hapic = Hapic(processor_class=MarshmallowProcessor)
        app = AgnosticApp()
        hapic.set_context(AgnosticContext(app=app))

        class MySchema(marshmallow.Schema):
            name = marshmallow.fields.String(required=True)

        @hapic.with_api_doc()
        @hapic.input_body(MySchema(many=True))
        def my_controller():
            return {"name": "test"}

        app.route("/paper", method="POST", callback=my_controller)
        doc = hapic.generate_doc()

        assert doc.get("definitions", {}).get("MySchema", {})
        schema_def = doc.get("definitions", {}).get("MySchema", {})
        assert schema_def.get("properties", {}).get("name", {}).get("type")

        assert doc.get("paths").get("/paper").get("post").get("parameters")[0]
        schema_ref = doc.get("paths").get("/paper").get("post").get(
            "parameters")[0]
        assert schema_ref.get("in") == "body"
        assert schema_ref.get("name") == "body"
        assert schema_ref["schema"] == {
            "items": {
                "$ref": "#/definitions/MySchema"
            },
            "type": "array",
        }
Beispiel #13
0
    async def test_unit__global_exception__ok__hook_called(
            self, aiohttp_client):
        hapic = Hapic(async_=True, processor_class=MarshmallowProcessor)

        class MyContext(AiohttpContext):
            def __init__(self, *args, **kwargs):
                super().__init__(*args, **kwargs)
                self.hook_called = False

            def global_exception_caught(self, exc: Exception, *args,
                                        **kwargs) -> None:
                self.hook_called = True

        @hapic.with_api_doc()
        async def divide_by_zero(request):
            raise ZeroDivisionError()

        app = web.Application(debug=True)
        context = MyContext(app)
        hapic.set_context(context)
        context.handle_exception(ZeroDivisionError,
                                 http_code=HTTPStatus.BAD_REQUEST)
        app.router.add_get("/", divide_by_zero)
        client = await aiohttp_client(app)

        assert not context.hook_called
        await client.get("/")
        assert context.hook_called
Beispiel #14
0
    def test_func__errors__http_status_as_int_description(self):
        hapic = Hapic(processor_class=MarshmallowProcessor)
        app = AgnosticApp()
        hapic.set_context(AgnosticContext(app=app))

        class MyException(Exception):
            pass

        @hapic.with_api_doc()
        @hapic.handle_exception(MyException, http_code=400)
        def my_controller(hapic_data=None):
            assert hapic_data

        app.route("/upload", method="POST", callback=my_controller)
        doc = hapic.generate_doc()

        assert doc.get("paths")
        assert "/upload" in doc["paths"]
        assert "post" in doc["paths"]["/upload"]
        assert "responses" in doc["paths"]["/upload"]["post"]
        assert "400" in doc["paths"]["/upload"]["post"]["responses"]
        assert {
            "description": "400",
            "schema": {
                "$ref": "#/definitions/DefaultErrorSchema"
            },
        } == doc["paths"]["/upload"]["post"]["responses"]["400"]
Beispiel #15
0
    async def test_unit__post_file__ok__put_success(self, aiohttp_client,
                                                    loop):
        hapic = Hapic(async_=True, processor_class=MarshmallowProcessor)

        class InputFilesSchema(marshmallow.Schema):
            avatar = marshmallow.fields.Raw()

        @hapic.with_api_doc()
        @hapic.input_files(InputFilesSchema())
        async def update_avatar(request: Request, hapic_data: HapicData):
            avatar = hapic_data.files["avatar"]
            assert isinstance(avatar, FileField)
            assert b"text content of file" == avatar.file.read()
            return Response(body="ok")

        app = web.Application(debug=True)
        app.router.add_put("/avatar", update_avatar)
        hapic.set_context(
            AiohttpContext(
                app, default_error_builder=MarshmallowDefaultErrorBuilder()))
        client = await aiohttp_client(app)

        resp = await client.put(
            "/avatar", data={"avatar": io.StringIO("text content of file")})
        assert resp.status == 200
Beispiel #16
0
    def test_func__input_files_doc__ok__one_file(self):
        hapic = Hapic(processor_class=MarshmallowProcessor)
        app = AgnosticApp()
        hapic.set_context(AgnosticContext(app=app))

        class MySchema(marshmallow.Schema):
            file_abc = marshmallow.fields.Raw(required=True)

        @hapic.with_api_doc()
        @hapic.input_files(MySchema())
        def my_controller(hapic_data=None):
            assert hapic_data
            assert hapic_data.files

        app.route("/upload", method="POST", callback=my_controller)
        doc = hapic.generate_doc()

        assert doc
        assert "/upload" in doc["paths"]
        assert "consumes" in doc["paths"]["/upload"]["post"]
        assert "multipart/form-data" in doc["paths"]["/upload"]["post"][
            "consumes"]
        assert "parameters" in doc["paths"]["/upload"]["post"]
        assert {
            "name": "file_abc",
            "required": True,
            "in": "formData",
            "type": "file"
        } in doc["paths"]["/upload"]["post"]["parameters"]
Beispiel #17
0
    async def test_unit__post_file__ok__missing_file(self, aiohttp_client,
                                                     loop):
        hapic = Hapic(async_=True, processor_class=MarshmallowProcessor)

        class InputFilesSchema(marshmallow.Schema):
            avatar = marshmallow.fields.Raw(required=True)

        @hapic.with_api_doc()
        @hapic.input_files(InputFilesSchema())
        async def update_avatar(request: Request, hapic_data: HapicData):
            raise AssertionError("Test should no pass here")

        app = web.Application(debug=True)
        app.router.add_put("/avatar", update_avatar)
        hapic.set_context(
            AiohttpContext(
                app, default_error_builder=MarshmallowDefaultErrorBuilder()))
        client = await aiohttp_client(app)

        resp = await client.put("/avatar")
        assert resp.status == 400
        json_ = await resp.json()
        assert {
            "details": {
                "avatar": ["Missing data for required field"]
            },
            "message": "Validation error of input data",
            "code": None,
        } == json_
    def test_unit__input_files__ok__file_is_not_present(self):
        hapic = Hapic(processor_class=MarshmallowProcessor)
        hapic.set_context(
            AgnosticContext(
                app=None,
                files_parameters={
                    # No file here
                },
            )
        )

        class MySchema(marshmallow.Schema):
            file_abc = marshmallow.fields.Raw(required=True)

        @hapic.input_files(MySchema())
        def my_controller(hapic_data=None):
            assert hapic_data
            assert hapic_data.files
            return "OK"

        result = my_controller()
        assert HTTPStatus.BAD_REQUEST == result.status_code
        assert {
            "http_code": 400,
            "original_error": {
                "details": {"file_abc": ["Missing data for required field"]},
                "message": "Validation error of input data",
            },
        } == json.loads(result.body)
Beispiel #19
0
    async def test_aiohttp_output_stream__error__interrupt_py37(
            self, aiohttp_client, loop):
        hapic = Hapic(async_=True, processor_class=MarshmallowProcessor)

        class OuputStreamItemSchema(marshmallow.Schema):
            name = marshmallow.fields.String(required=True)

        from .py37.stream import get_func_with_output_stream_and_error

        hello = get_func_with_output_stream_and_error(hapic,
                                                      OuputStreamItemSchema,
                                                      ignore_on_error=False)

        app = web.Application(debug=True)
        app.router.add_get("/", hello)
        hapic.set_context(
            AiohttpContext(
                app, default_error_builder=MarshmallowDefaultErrorBuilder()))
        client = await aiohttp_client(app)

        resp = await client.get("/")
        assert resp.status == 200

        line = await resp.content.readline()
        assert b'{"name": "Hello, bob"}\n' == line

        line = await resp.content.readline()
        assert b"" == line
Beispiel #20
0
    def test_func__schema_with_many__ok__with_exclude(self):
        hapic = Hapic(processor_class=MarshmallowProcessor)
        app = AgnosticApp()
        hapic.set_context(AgnosticContext(app=app))

        class MySchema(marshmallow.Schema):
            first_name = marshmallow.fields.String(required=True)
            last_name = marshmallow.fields.String(required=False)

        @hapic.with_api_doc()
        @hapic.output_body(MySchema(many=True, exclude=("last_name", )))
        def my_controller(hapic_data=None):
            pass

        app.route("/", method="GET", callback=my_controller)
        doc = hapic.generate_doc()

        assert {
            "MySchema_without_last_name": {
                "type": "object",
                "properties": {
                    "first_name": {
                        "type": "string"
                    }
                },
                "required": ["first_name"],
            }
        } == doc["definitions"]
Beispiel #21
0
    def test_unit__generate_doc__ok__nominal_case(self, aiohttp_client, loop):
        hapic = Hapic(async_=True, processor_class=MarshmallowProcessor)

        class InputPathSchema(marshmallow.Schema):
            username = marshmallow.fields.String(required=True)

        class InputQuerySchema(marshmallow.Schema):
            show_deleted = marshmallow.fields.Boolean(required=False)

        class UserSchema(marshmallow.Schema):
            name = marshmallow.fields.String(required=True)

        @hapic.with_api_doc()
        @hapic.input_path(InputPathSchema())
        @hapic.input_query(InputQuerySchema())
        @hapic.output_body(UserSchema())
        async def get_user(request, hapic_data):
            pass

        @hapic.with_api_doc()
        @hapic.input_path(InputPathSchema())
        @hapic.output_body(UserSchema())
        async def post_user(request, hapic_data):
            pass

        app = web.Application(debug=True)
        app.router.add_get("/{username}", get_user)
        app.router.add_post("/{username}", post_user)
        hapic.set_context(
            AiohttpContext(app, default_error_builder=MarshmallowDefaultErrorBuilder())
        )

        doc = hapic.generate_doc("aiohttp", "testing")
        # INFO BS 2019-04-15: Prevent keep of OrderedDict
        doc = json.loads(json.dumps(doc))

        assert "UserSchema" in doc.get("definitions")
        assert {"name": {"type": "string"}} == doc["definitions"]["UserSchema"].get("properties")
        assert "/{username}" in doc.get("paths")
        assert "get" in doc["paths"]["/{username}"]
        assert "post" in doc["paths"]["/{username}"]

        assert [
            {"name": "username", "in": "path", "required": True, "type": "string"},
            {"name": "show_deleted", "in": "query", "required": False, "type": "boolean"},
        ] == doc["paths"]["/{username}"]["get"]["parameters"]
        assert {
            "200": {"schema": {"$ref": "#/definitions/UserSchema"}, "description": "200"}
        } == doc["paths"]["/{username}"]["get"]["responses"]

        assert [{"name": "username", "in": "path", "required": True, "type": "string"}] == doc[
            "paths"
        ]["/{username}"]["post"]["parameters"]
        assert {
            "200": {"schema": {"$ref": "#/definitions/UserSchema"}, "description": "200"}
        } == doc["paths"]["/{username}"]["get"]["responses"]
Beispiel #22
0
    def test_func__errors__multiple_same_http_status_description(self):
        hapic = Hapic(processor_class=MarshmallowProcessor)
        app = AgnosticApp()
        hapic.set_context(AgnosticContext(app=app))

        class MyFirstException(Exception):
            pass

        class MySecondException(Exception):
            "Just a docstring"

        class MyThirdException(Exception):
            "Docstring not used"
            pass

        class MyFourthException(Exception):
            pass

        @hapic.with_api_doc()
        @hapic.handle_exception(MyFirstException,
                                http_code=HTTPStatus.BAD_REQUEST)
        @hapic.handle_exception(MySecondException,
                                http_code=HTTPStatus.BAD_REQUEST)
        @hapic.handle_exception(MyThirdException,
                                http_code=HTTPStatus.BAD_REQUEST,
                                description="explicit description")
        @hapic.handle_exception(MyFourthException, http_code=400)
        def my_controller(hapic_data=None):
            assert hapic_data

        app.route("/upload", method="POST", callback=my_controller)
        doc = hapic.generate_doc()

        assert doc.get("paths")
        assert "/upload" in doc["paths"]
        assert "post" in doc["paths"]["/upload"]
        assert "responses" in doc["paths"]["/upload"]["post"]
        assert "400" in doc["paths"]["/upload"]["post"]["responses"]
        assert "description"

        assert doc["paths"]["/upload"]["post"]["responses"]["400"][
            "description"]
        descriptions = doc["paths"]["/upload"]["post"]["responses"]["400"][
            "description"].split("\n\n")
        assert "BAD_REQUEST: Bad request syntax or unsupported method" in descriptions
        assert "explicit description" in descriptions
        assert "400" in descriptions
        assert "Just a docstring" in descriptions
        assert "Docstring not used" not in descriptions
        assert doc["paths"]["/upload"]["post"]["responses"]["400"]["schema"]
        assert {
            "$ref": "#/definitions/DefaultErrorSchema"
        } == doc["paths"]["/upload"]["post"]["responses"]["400"]["schema"]
Beispiel #23
0
    async def test_unit__handle_exception__ok__nominal_case(self, aiohttp_client):
        hapic = Hapic(async_=True, processor_class=MarshmallowProcessor)

        @hapic.with_api_doc()
        @hapic.handle_exception(ZeroDivisionError, http_code=HTTPStatus.BAD_REQUEST)
        async def divide_by_zero(request):
            raise ZeroDivisionError()

        app = web.Application(debug=True)
        hapic.set_context(AiohttpContext(app))
        app.router.add_get("/", divide_by_zero)
        client = await aiohttp_client(app)
        response = await client.get("/")

        assert 400 == response.status
    def test_unit__input_files__ok__file_is_present(self):
        hapic = Hapic(processor_class=MarshmallowProcessor)
        hapic.set_context(AgnosticContext(app=None, files_parameters={"file_abc": "10101010101"}))

        class MySchema(marshmallow.Schema):
            file_abc = marshmallow.fields.Raw(required=True)

        @hapic.input_files(MySchema())
        def my_controller(hapic_data=None):
            assert hapic_data
            assert hapic_data.files
            return "OK"

        result = my_controller()
        assert "OK" == result
Beispiel #25
0
    def test_unit__decoration__ok__method(self):
        hapic = Hapic()

        class MyControllers(object):
            @hapic.with_api_doc()
            def controller_a(self):
                pass

        my_controllers = MyControllers()
        class_method_token = getattr(
            MyControllers.controller_a,
            DECORATION_ATTRIBUTE_NAME,
            None,
        )
        assert class_method_token
        instance_method_token = getattr(
            my_controllers.controller_a,
            DECORATION_ATTRIBUTE_NAME,
            None,
        )
        assert instance_method_token

        assert hapic.controllers
        assert 1 == len(hapic.controllers)
        reference = hapic.controllers[0].reference

        assert class_method_token == reference.token
        assert instance_method_token == reference.token

        assert MyControllers.controller_a == reference.wrapper
        assert MyControllers.controller_a != reference.wrapped
        assert my_controllers.controller_a != reference.wrapper
        assert my_controllers.controller_a != reference.wrapped
Beispiel #26
0
    def test_func_schema_in_doc__ok__additionals_fields__forms__string(self):
        hapic = Hapic(processor_class=MarshmallowProcessor)
        app = AgnosticApp()
        hapic.set_context(AgnosticContext(app=app))

        class MySchema(marshmallow.Schema):
            category = marshmallow.fields.String(
                required=True,
                description="a description",
                example="00010",
                format="binary",
                enum=["01000", "11111"],
                maxLength=5,
                minLength=5,
                # Theses none string specific parameters should disappear
                # in query/path
                maximum=400,
                # exclusiveMaximun=False,
                # minimum=0,
                # exclusiveMinimum=True,
                # multipleOf=1,
            )

        @hapic.with_api_doc()
        @hapic.input_forms(MySchema())
        def my_controller():
            return

        app.route("/paper", method="POST", callback=my_controller)
        doc = hapic.generate_doc()
        assert "multipart/form-data" in doc["paths"]["/paper"]["post"][
            "consumes"]
        assert doc.get("paths").get("/paper").get("post").get("parameters")[0]
        field = doc.get("paths").get("/paper").get("post").get("parameters")[0]
        assert field[
            "description"] == "a description\n\n*example value: 00010*"
        # INFO - G.M - 01-06-2018 - Field example not allowed here,
        # added in description instead
        assert "example" not in field
        assert field["format"] == "binary"
        assert field["in"] == "formData"
        assert field["type"] == "string"
        assert field["maxLength"] == 5
        assert field["minLength"] == 5
        assert field["required"] is True
        assert field["enum"] == ["01000", "11111"]
        assert "maximum" not in field
Beispiel #27
0
    def test_func__tags__ok__nominal_case(self):
        hapic = Hapic(processor_class=MarshmallowProcessor)
        app = AgnosticApp()
        hapic.set_context(AgnosticContext(app=app))

        @hapic.with_api_doc(tags=["foo", "bar"])
        def my_controller(hapic_data=None):
            assert hapic_data
            assert hapic_data.files

        app.route("/upload", method="POST", callback=my_controller)
        doc = hapic.generate_doc()

        assert doc.get("paths")
        assert "/upload" in doc["paths"]
        assert "post" in doc["paths"]["/upload"]
        assert "tags" in doc["paths"]["/upload"]["post"]
        assert ["foo", "bar"] == doc["paths"]["/upload"]["post"]["tags"]
Beispiel #28
0
    def test_func__output_file_doc__ok__nominal_case(self):
        hapic = Hapic(processor_class=MarshmallowProcessor)
        app = AgnosticApp()
        hapic.set_context(AgnosticContext(app=app))

        @hapic.with_api_doc()
        @hapic.output_file(["image/jpeg"])
        def my_controller():
            return b"101010100101"

        app.route("/avatar", method="GET", callback=my_controller)
        doc = hapic.generate_doc()

        assert doc
        assert "/avatar" in doc["paths"]
        assert "produces" in doc["paths"]["/avatar"]["get"]
        assert "image/jpeg" in doc["paths"]["/avatar"]["get"]["produces"]
        assert "200" in doc["paths"]["/avatar"]["get"]["responses"]
Beispiel #29
0
    def test_func__output_file_doc__ok__nominal_case(self):
        hapic = Hapic()
        hapic.set_context(MyContext())
        app = bottle.Bottle()

        @hapic.with_api_doc()
        @hapic.output_file('image/jpeg')
        def my_controller():
            return b'101010100101'

        app.route('/avatar', method='GET', callback=my_controller)
        doc = hapic.generate_doc(app)

        assert doc
        assert '/avatar' in doc['paths']
        assert 'produce' in doc['paths']['/avatar']['get']
        assert 'image/jpeg' in doc['paths']['/avatar']['get']['produce']
        assert 200 in doc['paths']['/avatar']['get']['responses']
Beispiel #30
0
    async def test_request_header__ok__lowercase_key(self, aiohttp_client):
        hapic = Hapic(async_=True, processor_class=MarshmallowProcessor)

        class HeadersSchema(marshmallow.Schema):
            foo = marshmallow.fields.String(required=True)

        @hapic.with_api_doc()
        @hapic.input_headers(HeadersSchema())
        async def hello(request, hapic_data: HapicData):
            return web.json_response(hapic_data.headers)

        app = web.Application(debug=True)
        hapic.set_context(AiohttpContext(app))
        app.router.add_get("/", hello)
        client = await aiohttp_client(app)
        response = await client.get("/", headers={"FOO": "bar"})
        assert 200 == response.status
        json_ = await response.json()
        assert {"foo": "bar"} == json_