Simplify OpenAPI generation

This commit is contained in:
gabdevele
2026-06-03 02:04:56 +02:00 Unverified
parent 21883a4a8f
commit 25c280f38b
25 changed files with 2695 additions and 1944 deletions
+84
View File
@@ -0,0 +1,84 @@
from __future__ import annotations
import importlib.util
import tempfile
import unittest
from pathlib import Path
SCRIPT_PATH = Path(__file__).with_name("generate_openapi.py")
SPEC = importlib.util.spec_from_file_location("generate_openapi", SCRIPT_PATH)
generate_openapi = importlib.util.module_from_spec(SPEC)
assert SPEC.loader is not None
SPEC.loader.exec_module(generate_openapi)
class GenerateOpenApiTest(unittest.TestCase):
def test_extracts_drogon_route(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
controllers = Path(tmp)
(controllers / "SampleController.h").write_text(
"""
class SampleController {
METHOD_LIST_BEGIN
ADD_METHOD_TO(SampleController::detail,
"/api/v1/samples/{1}",
drogon::Get);
METHOD_LIST_END
};
""",
encoding="utf-8",
)
routes = generate_openapi.parse_routes(controllers)
operation = routes[("/api/v1/samples/{id}", "get")]
self.assertEqual(operation["operationId"], "SampleController.detail")
self.assertEqual(operation["parameters"][0]["name"], "id")
def test_manual_operation_overrides_generated_defaults(self) -> None:
generated = {
("/api/v1/samples", "get"): {
"tags": ["Sample"],
"operationId": "SampleController.list",
"summary": "List",
"parameters": [],
"responses": {"200": {"description": "Response"}},
}
}
manual = {
"openapi": "3.0.3",
"info": {"title": "Manual", "version": "1.0.0"},
"paths": {
"/api/v1/samples": {
"get": {
"summary": "Manual summary",
"responses": {"200": {"description": "Manual response"}},
}
}
},
}
spec = generate_openapi.merge_openapi(
generated, manual, "Generated", "0.1.0", "http://localhost"
)
operation = spec["paths"]["/api/v1/samples"]["get"]
self.assertEqual(operation["summary"], "Manual summary")
self.assertEqual(operation["operationId"], "SampleController.list")
def test_stale_manual_operation_fails_unless_marked_manual_only(self) -> None:
manual = {
"paths": {
"/api/v1/stale": {
"get": {"responses": {"200": {"description": "Stale"}}}
}
}
}
with self.assertRaisesRegex(ValueError, "no matching Drogon route"):
generate_openapi.merge_openapi({}, manual, "API", "0.1.0", "http://x")
manual["paths"]["/api/v1/stale"]["get"]["x-manual-only"] = True
spec = generate_openapi.merge_openapi({}, manual, "API", "0.1.0", "http://x")
self.assertIn("/api/v1/stale", spec["paths"])
self.assertNotIn("x-manual-only", spec["paths"]["/api/v1/stale"]["get"])
if __name__ == "__main__":
unittest.main()