|
1 | | -"""Extends assertions for testing""" |
2 | | - |
3 | | -from http import HTTPStatus |
4 | | -from pprint import pformat |
5 | | -from typing import Any, TypeVar |
6 | | - |
7 | 1 | import httpx |
8 | | -from models_library.generics import Envelope |
9 | | -from pydantic import TypeAdapter |
10 | | -from servicelib.aiohttp import status |
11 | | -from servicelib.status_codes_utils import get_code_display_name, is_error |
12 | | - |
13 | | -T = TypeVar("T") |
14 | | - |
15 | | - |
16 | | -def assert_status( |
17 | | - response: httpx.Response, |
18 | | - expected_status_code: int, |
19 | | - response_model: type[T], |
20 | | - *, |
21 | | - expected_msg: str | None = None, |
22 | | - expected_error_code: str | None = None, |
23 | | - is_enveloped: bool = True, |
24 | | -) -> tuple[T | None, Any]: |
25 | | - """ |
26 | | - Asserts for enveloped responses |
27 | | - """ |
28 | | - # raises ValueError if cannot be converted |
29 | | - expected_status_code = HTTPStatus(expected_status_code) |
30 | | - |
31 | | - assert ( |
32 | | - response.status_code == expected_status_code |
33 | | - ), f"received {response.status_code}: {response.text}, expected {get_code_display_name(expected_status_code)}" |
34 | | - |
35 | | - # reponse |
36 | | - if is_enveloped: |
37 | | - validated_response = TypeAdapter(Envelope[response_model]).validate_json( |
38 | | - response.text |
39 | | - ) |
40 | | - data = validated_response.data |
41 | | - error = validated_response.error |
42 | | - if is_error(expected_status_code): |
43 | | - _do_assert_error( |
44 | | - data, error, expected_status_code, expected_msg, expected_error_code |
45 | | - ) |
46 | | - return data, error |
47 | | - if expected_status_code == status.HTTP_204_NO_CONTENT: |
48 | | - assert response.text == "" |
49 | | - return None, None |
50 | | - |
51 | | - if is_error(expected_status_code): |
52 | | - msg = "If you need it implement it" |
53 | | - raise NotImplementedError(msg) |
54 | | - |
55 | | - data = TypeAdapter(response_model).validate_json(response.text) |
56 | | - return data, None |
57 | | - |
58 | | - |
59 | | -def _do_assert_error( |
60 | | - data, |
61 | | - error, |
62 | | - expected_status_code: int, |
63 | | - expected_msg: str | None = None, |
64 | | - expected_error_code: str | None = None, |
65 | | -): |
66 | | - assert not data, pformat(data) |
67 | | - assert error, pformat(error) |
68 | | - |
69 | | - assert is_error(expected_status_code) |
70 | | - |
71 | | - # New versions of the error models might not have this attribute |
72 | | - details = error.get("errors", []) |
73 | | - |
74 | | - if expected_msg: |
75 | | - assert details |
76 | | - messages = [e["message"] for e in details] |
77 | | - assert expected_msg in messages |
| 2 | +from fastapi import FastAPI |
| 3 | +from yarl import URL |
78 | 4 |
|
79 | | - if expected_error_code: |
80 | | - assert details |
81 | | - codes = [e["code"] for e in details] |
82 | | - assert expected_error_code in codes |
83 | 5 |
|
84 | | - return data, error |
| 6 | +def url_from_operation_id( |
| 7 | + client: httpx.AsyncClient, app: FastAPI, operation_id: str, **path_params |
| 8 | +) -> URL: |
| 9 | + return URL(f"{client.base_url}").with_path( |
| 10 | + app.url_path_for(operation_id, **path_params) |
| 11 | + ) |
0 commit comments