Ejemplo n.º 1
0
    def test_validate_headers_wrong(self):
        r = Response()
        r.status_code = 200
        r.headers = {"fake": "header"}

        with pytest.raises(test_utils.HeadersMismatchError):
            test_utils.validate_response(r, expected_headers={"fake": "wrong"})
Ejemplo n.º 2
0
    def test_validate_paging_no_urls_raises(self):
        r = Response()
        r.status_code = 200
        r.headers = {
            "paging-next": "www.url.com/next",
            "paging-previous": "www.url.com/previous",
            "paging-offset": 5,
            "paging-limit": 5,
            "paging-current-page": 2,
            "paging-total-pages": 10,
            "paging-total-items": 50,
        }

        expected_paging = PagingResp(
            next=None,
            previous=None,
            offset=5,
            limit=5,
            current_page=2,
            total_pages=10,
            total_items=50,
        )

        with pytest.raises(test_utils.PagingMismatchError):
            test_utils.validate_response(r, expected_paging=expected_paging)
Ejemplo n.º 3
0
    def test_validate_text_not_text(self):
        r = Response()
        r.status_code = 200
        r._content = bytes(10)

        with pytest.raises(test_utils.TextValidationError):
            test_utils.validate_response(r, text_value="test text")
Ejemplo n.º 4
0
    def test_validate_data_validation_error(self):
        r = Response()
        r.status_code = 200
        r._content = json.dumps({"first": "Harry"}).encode()

        with pytest.raises(test_utils.DataValidationError):
            test_utils.validate_response(r, data_schema=NameSchema())
Ejemplo n.º 5
0
    def test_validate_data_load_error(self):
        r = Response()
        r.status_code = 200
        r._content = bytes(10)

        with pytest.raises(test_utils.ContentDecodeError):
            test_utils.validate_response(r, data_schema=NameSchema())
Ejemplo n.º 6
0
    def test_use_schema_resp(
        self,
        api: SpanAPI,
        resp_dump: DumpOptions,
        data_send: Union[Name, dict],
        data_returned: dict,
        error: Optional[Type[errors_api.APIError]],
        bson: bool,
    ):
        @api.route("/test")
        class TestRoute(SpanRoute):
            @api.use_schema(resp=NameSchema(), resp_dump=resp_dump)
            async def on_get(self, req: Request, resp: Response):
                resp.media = data_send

        with api.requests as client:
            if bson:
                headers = {"accept": "application/bson"}
            else:
                headers = {}

            r = client.get("/test", headers=headers)

            if error is not None:
                validate_error(r, error)
            else:
                validate_response(r)

            if error is None:
                if bson:
                    assert dict(RawBSONDocument(r.content)) == dict(
                        RawBSONDocument(BSON.encode(data_returned))
                    )
                else:
                    assert r.json() == data_returned
Ejemplo n.º 7
0
    def test_get_paged_custom_offset(self, api: SpanAPI):
        @api.route("/test")
        class PagedTest(SpanRoute):
            @api.paged(limit=2)
            async def on_get(self, req: Request, resp: Response):
                resp.paging.total_items = 10
                resp.media = [
                    {"offset": req.paging.offset},
                    {"offset": req.paging.offset + 1},
                ]

        with api.requests as client:
            i = 5
            page = 3
            r = client.get("/test", params={"paging-offset": 5})
            page_previous = None

            while True:
                validate_response(r)

                data = r.json()
                assert isinstance(data, list)
                assert len(data) == 2
                for obj in data:
                    assert obj["offset"] == i
                    i += 1

                assert r.headers.get("paging-total-items") == "10"
                assert r.headers.get("paging-total-pages") == "5"
                assert r.headers.get("paging-limit") == "2"
                assert r.headers.get("paging-current-page") == str(page)

                if page == 5:
                    assert "paging-next" not in r.headers
                else:
                    assert r.headers.get("paging-next") == (
                        f"http://;/test?paging-offset={i}&paging-limit=2"
                    )

                if page == 3:
                    assert r.headers.get("paging-previous") == (
                        f"http://;/test?paging-offset=3&paging-limit=2"
                    )
                elif page == 4:
                    assert r.headers.get("paging-previous") == (
                        f"http://;/test?paging-offset=5&paging-limit=2"
                    )
                else:
                    assert r.headers.get("paging-previous") == page_previous

                next_page_url = r.headers.get("paging-next", None)
                if next_page_url is None:
                    break

                page += 1
                page_previous = r.url
                r = client.get(next_page_url)

        assert i == 11
Ejemplo n.º 8
0
    def test_load_bool(self, api: SpanAPI, value_in: str, value_parsed: bool):
        @api.route("/test/{value}")
        class PagedTest(SpanRoute):
            async def on_get(self, req: Request, resp: Response, *, value: bool):
                assert value == value_parsed

        with api.requests as client:
            r = client.get(f"/test/{value_in}")
            validate_response(r)
Ejemplo n.º 9
0
    def test_basic(self, capsys):
        r = Response()
        r.status_code = 200

        test_utils.validate_response(r)

        captured = capsys.readouterr()

        assert captured.out.startswith("RESPONSE: <Response [200]>\n")
Ejemplo n.º 10
0
    def test_no_media(self, api: SpanAPI):
        @api.route("/test")
        class TestRoute(SpanRoute):
            async def on_post(self, req: Request, resp: Response):
                media = await req.media()
                assert media is None

        with api.requests as client:
            r = client.post("/test")
            validate_response(r)
Ejemplo n.º 11
0
    def test_req_load_text(self, api: SpanAPI):
        @api.route("/test")
        class TestRoute(SpanRoute):
            @api.use_schema(req=MimeType.TEXT)
            async def on_post(self, req: Request, resp: Response):
                assert await req.media_loaded() == "test_text"

        with api.requests as client:
            r = client.post("/test", data="test_text")
            validate_response(r)
Ejemplo n.º 12
0
    def test_req_load_schema_class(self, api: SpanAPI):
        @api.route("/test")
        class TestRoute(SpanRoute):
            @api.use_schema(req=NameSchema)
            async def on_post(self, req: Request, resp: Response):
                assert await req.media_loaded() == HARRY

        with api.requests as client:
            r = client.post("/test", json=HARRY_DUMPED)
            validate_response(r)
Ejemplo n.º 13
0
    def test_use_schema_resp_text(self, api: SpanAPI):
        @api.route("/test")
        class TestRoute(SpanRoute):
            @api.use_schema(resp=MimeType.TEXT)
            async def on_get(self, req: Request, resp: Response):
                resp.text = "response_text"

        with api.requests as client:
            r = client.get("/test")
            validate_response(r)
            assert r.text == "response_text"
Ejemplo n.º 14
0
    def test_req_load_bson_list(self, api: SpanAPI, data):
        @api.route("/test")
        class TestRoute(SpanRoute):
            @api.use_schema(req=NameSchema(many=True))
            async def on_post(self, req: Request, resp: Response):
                assert await req.media_loaded() == [HARRY, HARRY]

        with api.requests as client:
            headers = {"Content-Type": "application/bson"}
            r = client.post("/test", data=encode_bson(data), headers=headers)
            validate_response(r)
Ejemplo n.º 15
0
    def test_body(self, capsys):
        r = Response()
        r.status_code = 200
        r._content = json.dumps({"key": "value"}).encode()

        test_utils.validate_response(r)

        captured = capsys.readouterr()

        assert '"key": "value"' in captured.out
        assert "JSON:" in captured.out
Ejemplo n.º 16
0
    def test_text(self, capsys):
        r = Response()
        r.status_code = 200
        r._content = "test text".encode()

        test_utils.validate_response(r, text_value="test text")

        captured = capsys.readouterr()

        assert "CONTENT:" in captured.out
        assert "test text" in captured.out
Ejemplo n.º 17
0
    def test_body_not_json(self, capsys):
        r = Response()
        r.status_code = 200
        r._content = bytes(10)

        test_utils.validate_response(r)

        captured = capsys.readouterr()

        assert "CONTENT:" in captured.out
        assert str(bytes(10)) in captured.out
Ejemplo n.º 18
0
    def test_mimetype_unknown(self, api: SpanAPI):
        @api.route("/test")
        class TestRoute(SpanRoute):
            async def on_post(self, req: Request, resp: Response):
                assert req.mimetype == "application/unknown"

        with api.requests as client:
            headers = dict()
            MimeType.add_to_headers(headers, "application/unknown")

            r = client.post("/test", headers=headers)
            validate_response(r)
Ejemplo n.º 19
0
    def test_paging_attrs(self, api: SpanAPI):
        @api.route("/test")
        class PagedTest(SpanRoute):
            @api.paged(limit=2)
            async def on_get(self, req: Request, resp: Response):
                assert req.paging is not resp.paging
                assert req.paging.offset == resp.paging.offset == 0
                assert req.paging.limit == resp.paging.limit == 2

        with api.requests as client:
            r = client.get("/test")
            validate_response(r)
Ejemplo n.º 20
0
    def test_decode_media_loaded(self, api: SpanAPI):
        @api.route("/test")
        class TestRoute(SpanRoute):
            async def on_post(self, req: Request, resp: Response):
                loaded = await req.media_loaded()
                media = await req.media()

                assert media is loaded

        with api.requests as client:
            headers = dict()
            MimeType.add_to_headers(headers, MimeType.JSON)

            r = client.post("/test", headers=headers, json={"key": "value"})
            validate_response(r)
Ejemplo n.º 21
0
    def test_validate_data_schema(self):
        r = Response()
        r.status_code = 200
        r._content = json.dumps({"first": "Harry", "last": "Potter"}).encode()

        name: Name = test_utils.validate_response(r, data_schema=NameSchema())
        assert name == Name("Harry", "Potter")
Ejemplo n.º 22
0
    def test_data_schema_bson(self):
        r = Response()
        r.status_code = 200
        r._content = encode_bson({"first": "Harry", "last": "Potter"})
        r.headers = {"Content-Type": "application/bson"}

        name: Name = test_utils.validate_response(r, data_schema=NameSchema())
        assert name == Name("Harry", "Potter")
Ejemplo n.º 23
0
    def test_paging_req_error(self, api: SpanAPI, test_obj_name):
        @api.route("/test")
        class PagedTest(SpanRoute):
            async def on_get(self, req: Request, resp: Response):
                error = None
                test_obj = req if test_obj_name == "req" else resp

                try:
                    _ = test_obj.paging
                except TypeError as exc:
                    error = exc

                assert isinstance(error, TypeError)

        with api.requests as client:
            r = client.get("/test")
            validate_response(r)
Ejemplo n.º 24
0
    def test_req_schema_class_marshmallow(self, api: SpanAPI):
        class NameSchemaM(marshmallow.Schema):
            id = marshmallow.fields.UUID()
            first = marshmallow.fields.Str()
            last = marshmallow.fields.Str()

        harry_loaded = NameSchemaM().load(HARRY_DUMPED)

        @api.route("/test")
        class TestRoute(SpanRoute):
            @api.use_schema(req=NameSchemaM())
            async def on_post(self, req: Request, resp: Response):
                assert await req.media_loaded() == harry_loaded

        with api.requests as client:
            r = client.post("/test", json=HARRY_DUMPED)
            validate_response(r)
Ejemplo n.º 25
0
    def test_lru_cache_hits(self, api: SpanAPI):
        run = 0

        @api.route("/test")
        class TestRoute(SpanRoute):
            @api.use_schema(resp=NameSchema())
            async def on_get(self, req: Request, resp: Response):
                hits = max(0, run - 2)

                assert (
                    resp._projection_builder._build_projection_schema.cache_info().hits
                ) == hits
                resp.media = HARRY

        @api.route("/test2")
        class TestRoute(SpanRoute):
            @api.use_schema(resp=NameSchema())
            async def on_get(self, req: Request, resp: Response):
                # We need to check that the first request for this endpoint does not
                # trigger a hit.
                if run < 2:
                    hits = 9
                else:
                    hits = 9 + run - 2

                assert (
                    resp._projection_builder._build_projection_schema.cache_info().hits
                ) == hits
                resp.media = HARRY

        with api.requests as client:
            for _ in range(10):
                run += 1
                r = client.get("/test", params={"project.id": 1})
                _ = validate_response(r, data_schema=NameSchema(only=["id"]))

            run = 0

            # Check that the cache is endpoint-specific
            for _ in range(10):
                run += 1
                r = client.get("/test2", params={"project.id": 1})
                _ = validate_response(r, data_schema=NameSchema(only=["id"]))
Ejemplo n.º 26
0
    def test_req_load_schema(
        self,
        api: SpanAPI,
        req_load: LoadOptions,
        data_post: dict,
        data_passed: Union[Name, dict],
        error: Optional[Type[errors_api.APIError]],
        bson: bool,
    ):
        if bson and isinstance(data_passed, dict):
            data_passed = RawBSONDocument(BSON.encode(data_passed))

        @api.route("/test")
        class TestRoute(SpanRoute):
            @api.use_schema(req=NameSchema(), req_load=req_load)
            async def on_post(
                self, req: Request[dict, Union[Name, dict]], resp: Response
            ):
                data = await req.media_loaded()
                if req_load is LoadOptions.IGNORE:
                    assert data == data_passed
                    assert await req.media() == data_passed
                else:
                    assert isinstance(data, type(data_passed))
                    assert data == data_passed

        with api.requests as client:
            if bson:
                if isinstance(data_post, dict):
                    data_post = BSON.encode(data_post)

                r = client.post(
                    "/test",
                    data=data_post,
                    headers={"Content-Type": "application/bson"},
                )
            else:
                r = client.post("/test", json=data_post)

            if error is not None:
                validate_error(r, error)
            else:
                validate_response(r)
Ejemplo n.º 27
0
    def test_data_schema_bson_many_single(self):
        r = Response()
        r.status_code = 200
        r._content = encode_bson([{"first": "Harry", "last": "Potter"}])
        r.headers = {"Content-Type": "application/bson"}

        names: List[Name] = test_utils.validate_response(
            r, data_schema=NameSchema(many=True, normalize_many=True)
        )
        assert names[0] == Name("Harry", "Potter")
        assert len(names) == 1
Ejemplo n.º 28
0
    def test_resp_schema_class(self, api: SpanAPI):
        @api.route("/test")
        class TestRoute(SpanRoute):
            @api.use_schema(resp=NameSchema)
            async def on_get(self, req: Request, resp: Response):
                resp.media = HARRY

        with api.requests as client:
            r = client.get("/test")
            name: Name = validate_response(r, data_schema=NameSchema())
            assert name == HARRY
Ejemplo n.º 29
0
    def test_return_bson_types(self, api: SpanAPI):
        uuid_value = uuid.uuid4()
        # bytes_value = b"Some data"
        dt_value = datetime.datetime.utcnow()
        dt_value = dt_value.replace(microsecond=0)
        info_value = {"key": "value"}
        array_value = ["one", "two", "three"]

        @dataclass
        class ResponseData:
            id: uuid.UUID
            dt: datetime.datetime
            # binary: str
            info: Dict[str, str]
            array: List[str]
            empty: Dict[str, str]

        @schema_for(ResponseData)
        class ResponseSchema(DataSchema[ResponseData]):
            pass

        @api.route("/test")
        class TestRoute(SpanRoute):
            @api.use_schema(resp=ResponseSchema(), resp_dump=DumpOptions.IGNORE)
            async def on_get(self, req: Request, resp: Response):
                resp.media = RawBSONDocument(
                    BSON.encode(
                        {
                            "id": uuid_value,
                            "dt": dt_value,
                            # "binary": bytes_value,
                            "info": info_value,
                            "array": array_value,
                            "empty": {},
                        }
                    )
                )

        with api.requests as client:
            r = client.get("/test")
            loaded: ResponseData = validate_response(
                r,
                data_schema=ResponseSchema(),
                expected_headers={"Content-Type": "application/json"},
            )

            assert loaded.id == uuid_value
            assert loaded.dt == dt_value
            # assert bytes.fromhex(loaded.binary) == bytes_value
            assert loaded.info == info_value
            assert loaded.array == array_value
            assert loaded.empty == {}
Ejemplo n.º 30
0
    def test_register_mimetype_encoders(self, api: SpanAPI):
        data = [{"key": "value1"}, {"key": "value2"}]

        def csv_encode(data: List[dict]) -> bytes:
            encoded = io.StringIO()
            headers = list(data[0].keys())
            writer = csv.DictWriter(encoded, fieldnames=headers)
            writer.writeheader()
            writer.writerows(data)
            return encoded.getvalue().encode()

        def csv_decode(data: bytes) -> List[Dict[str, Any]]:
            csv_file = io.StringIO(data.decode())
            reader = csv.DictReader(csv_file)
            return [row for row in reader]

        api.register_mimetype("text/csv", encoder=csv_encode, decoder=csv_decode)

        @api.route("/test")
        class TestRoute(SpanRoute):
            async def on_post(self, req: Request, resp: Response):
                loaded = await req.media_loaded()
                media = await req.media()

                assert media is loaded
                assert media == loaded == data

                resp.media = media
                resp.mimetype = "text/csv"

        req_data = csv_encode(data)
        r = api.requests.post(
            "/test", headers={"Content-Type": "text/csv"}, data=req_data
        )

        validate_response(r, expected_headers={"Content-Type": "text/csv"})

        resp_data = csv_decode(r.content)
        assert resp_data == data