From fa408a969e13cd55d720916df729a2fa1933e248 Mon Sep 17 00:00:00 2001 From: Vector73 Date: Sun, 11 Aug 2024 11:35:10 +0530 Subject: [PATCH] api-docs: Handle multiple examples in `responses`. --- zerver/openapi/openapi.py | 40 ++++++++++++----------- zerver/openapi/zulip.yaml | 63 +++++++++++++++++++++++++++--------- zerver/tests/test_openapi.py | 16 ++++++--- 3 files changed, 82 insertions(+), 37 deletions(-) diff --git a/zerver/openapi/openapi.py b/zerver/openapi/openapi.py index b7a7a48745..b6de7c5de7 100644 --- a/zerver/openapi/openapi.py +++ b/zerver/openapi/openapi.py @@ -204,14 +204,20 @@ def get_schema(endpoint: str, method: str, status_code: str) -> dict[str, Any]: return schema -def get_openapi_fixture(endpoint: str, method: str, status_code: str = "200") -> dict[str, Any]: +def get_openapi_fixture( + endpoint: str, method: str, status_code: str = "200" +) -> list[dict[str, Any]]: """Fetch a fixture from the full spec object.""" - return get_schema(endpoint, method, status_code)["example"] - - -def get_openapi_fixture_description(endpoint: str, method: str, status_code: str = "200") -> str: - """Fetch a fixture from the full spec object.""" - return get_schema(endpoint, method, status_code)["description"] + if "example" not in get_schema(endpoint, method, status_code): + return openapi_spec.openapi()["paths"][endpoint][method.lower()]["responses"][status_code][ + "content" + ]["application/json"]["examples"].values() + return [ + { + "description": get_schema(endpoint, method, status_code)["description"], + "value": get_schema(endpoint, method, status_code)["example"], + } + ] def get_curl_include_exclude(endpoint: str, method: str) -> list[dict[str, Any]]: @@ -279,17 +285,15 @@ def generate_openapi_fixture(endpoint: str, method: str) -> list[str]: else: subschema_status_code = status_code fixture_dict = get_openapi_fixture(endpoint, method, subschema_status_code) - fixture_description = get_openapi_fixture_description( - endpoint, method, subschema_status_code - ).strip() - fixture_json = json.dumps( - fixture_dict, indent=4, sort_keys=True, separators=(",", ": ") - ) - - fixture.extend(fixture_description.splitlines()) - fixture.append("``` json") - fixture.extend(fixture_json.splitlines()) - fixture.append("```") + for example in fixture_dict: + fixture_json = json.dumps( + example["value"], indent=4, sort_keys=True, separators=(",", ": ") + ) + if "description" in example: + fixture.extend(example["description"].strip().splitlines()) + fixture.append("``` json") + fixture.extend(fixture_json.splitlines()) + fixture.append("```") return fixture diff --git a/zerver/openapi/zulip.yaml b/zerver/openapi/zulip.yaml index 4d418dcafb..c3e321049d 100644 --- a/zerver/openapi/zulip.yaml +++ b/zerver/openapi/zulip.yaml @@ -9265,21 +9265,54 @@ paths: Legacy property for a part of the Zephyr mirroring system. **Deprecated**. Clients should ignore this field. - example: - { - "msg": "", - "presences": - { - "10": - { - "idle_timestamp": 1656958530, - "active_timestamp": 1656958520, - }, - }, - "result": "success", - "server_timestamp": 1656958539.6287155, - "presence_last_update_id": 1000, - } + examples: + modern-presence-format-example: + description: | + Modern presence format: + value: + { + "msg": "", + "presences": + { + "10": + { + "idle_timestamp": 1656958530, + "active_timestamp": 1656958520, + }, + }, + "result": "success", + "server_timestamp": 1656958539.6287155, + "presence_last_update_id": 1000, + } + legacy-presence-format-example: + description: | + Legacy presence format: + value: + { + "msg": "", + "presences": + { + "user@example.com": + { + "aggregated": + { + "client": "website", + "status": "idle", + "timestamp": 1594825445, + }, + "website": + { + "client": "website", + "status": "idle", + "timestamp": 1594825445, + "pushable": false, + }, + }, + }, + "result": "success", + "server_timestamp": 1656958539.6287155, + "presence_last_update_id": 1000, + } /users/me/status: post: operationId: update-status diff --git a/zerver/tests/test_openapi.py b/zerver/tests/test_openapi.py index 8d04280b31..eeb0c0cb2d 100644 --- a/zerver/tests/test_openapi.py +++ b/zerver/tests/test_openapi.py @@ -73,7 +73,7 @@ class OpenAPIToolsTest(ZulipTestCase): """ def test_get_openapi_fixture(self) -> None: - actual = get_openapi_fixture(TEST_ENDPOINT, TEST_METHOD, TEST_RESPONSE_BAD_REQ) + actual = get_openapi_fixture(TEST_ENDPOINT, TEST_METHOD, TEST_RESPONSE_BAD_REQ)[0]["value"] expected = { "code": "BAD_REQUEST", "msg": "You don't have permission to edit this message", @@ -1031,9 +1031,17 @@ class OpenAPIAttributesTest(ZulipTestCase): ) continue validate_schema(schema) - assert validate_against_openapi_schema( - schema["example"], path, method, status_code - ) + if "example" not in schema: + assert "examples" in response["content"]["application/json"] + examples = response["content"]["application/json"]["examples"] + for example in examples: + assert validate_against_openapi_schema( + examples[example]["value"], path, method, status_code + ) + else: + assert validate_against_openapi_schema( + schema["example"], path, method, status_code + ) class OpenAPIRegexTest(ZulipTestCase):