Skip to content

Commit 827524d

Browse files
committed
Elementary OpenAPI integration tests
1 parent 2e39274 commit 827524d

File tree

1 file changed

+89
-0
lines changed

1 file changed

+89
-0
lines changed
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import json
2+
from pathlib import Path
3+
import typing as t
4+
5+
import pytest
6+
7+
# Strategy:
8+
# - Load the OpenAPI document from docs/openapi.json
9+
# - Validate critical structure based on the PR diff:
10+
# * openapi version, info, servers
11+
# * presence of paths/methods and key response codes
12+
# * presence and key attributes of important component schemas (enums, required fields)
13+
14+
OPENAPI_FILE = "docs/openapi.json"
15+
16+
17+
def _load_openapi_spec() -> dict:
18+
"""Load OpenAPI specification from configured path."""
19+
path = Path(OPENAPI_FILE)
20+
if path.is_file():
21+
with path.open("r", encoding="utf-8") as f:
22+
return json.load(f)
23+
24+
pytest.fail("OpenAPI spec not found")
25+
26+
27+
@pytest.fixture(scope="module")
28+
def spec() -> dict:
29+
"""Fixture containing OpenAPI specification represented as a dictionary."""
30+
return _load_openapi_spec()
31+
32+
33+
def test_openapi_top_level_info(spec: dict):
34+
"""Test all top level informations stored in OpenAPI specification."""
35+
assert spec.get("openapi") == "3.1.0"
36+
37+
info = spec.get("info") or {}
38+
assert info.get("title") == "Lightspeed Core Service (LCS) service - OpenAPI"
39+
assert "version" in info
40+
41+
contact = info.get("contact") or {}
42+
assert contact is not None
43+
44+
license = info.get("license") or {}
45+
assert license.get("name") == "Apache 2.0"
46+
assert "apache.org/licenses" in (license.get("url") or "")
47+
48+
49+
def test_servers_section_present(spec: dict):
50+
"""Test the servers section stored in OpenAPI specification."""
51+
servers = spec.get("servers")
52+
assert isinstance(servers, list) and servers, "servers must be a non-empty list"
53+
54+
55+
@pytest.mark.parametrize(
56+
"path,method,expected_codes",
57+
[
58+
("/", "get", {"200"}),
59+
("/v1/info", "get", {"200", "500"}),
60+
("/v1/models", "get", {"200", "503"}),
61+
("/v1/query", "post", {"200", "400", "403", "503", "422"}),
62+
("/v1/streaming_query", "post", {"200", "422"}),
63+
("/v1/config", "get", {"200", "503"}),
64+
("/v1/feedback", "post", {"200", "401", "403", "500", "422"}),
65+
("/v1/feedback/status", "get", {"200"}),
66+
("/v1/feedback/status", "put", {"200", "422"}),
67+
("/v1/conversations", "get", {"200", "503"}),
68+
("/v1/conversations/{conversation_id}", "get", {"200", "404", "503", "422"}),
69+
("/v1/conversations/{conversation_id}", "delete", {"200", "404", "503", "422"}),
70+
("/readiness", "get", {"200", "503"}),
71+
("/liveness", "get", {"200", "503"}),
72+
("/authorized", "post", {"200", "400", "403"}),
73+
("/metrics", "get", {"200"}),
74+
],
75+
)
76+
def test_paths_and_responses_exist(
77+
spec: dict, path: str, method: str, expected_codes: t.Set[str]
78+
):
79+
"""Tests all paths defined in OpenAPI specification."""
80+
paths = spec.get("paths") or {}
81+
assert path in paths, f"Missing path: {path}"
82+
op = (paths[path] or {}).get(method)
83+
assert isinstance(op, dict), f"Missing method {method.upper()} for path {path}"
84+
responses = op.get("responses") or {}
85+
got_codes = set(responses.keys())
86+
for code in expected_codes:
87+
assert (
88+
code in got_codes
89+
), f"Missing response code {code} for {method.upper()} {path}"

0 commit comments

Comments
 (0)