Skip to content

Commit cd795b3

Browse files
authored
Merge pull request #941 from tisnik/lcore-1070-better-docstrings-in-integration-tests
LCORE-1070: Updated docstrings in integration tests
2 parents 0d69f91 + 0b66fd0 commit cd795b3

5 files changed

Lines changed: 204 additions & 26 deletions

File tree

tests/integration/conftest.py

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ def test_config_fixture() -> Generator:
3737
3838
This fixture loads the actual configuration file used in testing,
3939
demonstrating integration with the configuration system.
40+
41+
Yields:
42+
The `configuration` module with the loaded settings.
4043
"""
4144
config_path = (
4245
Path(__file__).parent.parent / "configuration" / "lightspeed-stack.yaml"
@@ -56,6 +59,9 @@ def current_config_fixture() -> Generator:
5659
5760
This fixture loads the actual configuration file from project root (current configuration),
5861
demonstrating integration with the configuration system.
62+
63+
Yields:
64+
configuration: The loaded configuration object.
5965
"""
6066
config_path = Path(__file__).parent.parent.parent / "lightspeed-stack.yaml"
6167
assert config_path.exists(), f"Config file not found: {config_path}"
@@ -73,6 +79,9 @@ def test_db_engine_fixture() -> Generator:
7379
7480
This provides a real database (not mocked) for integration tests.
7581
Each test gets a fresh database.
82+
83+
Yields:
84+
engine (Engine): A SQLAlchemy Engine connected to a new in-memory SQLite database.
7685
"""
7786
# Create in-memory SQLite database
7887
engine = create_engine(
@@ -96,6 +105,10 @@ def test_db_session_fixture(test_db_engine: Engine) -> Generator[Session, None,
96105
"""Create a database session for testing.
97106
98107
Provides a real database session connected to the in-memory test database.
108+
109+
Yields:
110+
session (Session): A database session bound to the test engine; the
111+
fixture closes the session after the test.
99112
"""
100113
session_local = sessionmaker(autocommit=False, autoflush=False, bind=test_db_engine)
101114
session = session_local()
@@ -107,7 +120,12 @@ def test_db_session_fixture(test_db_engine: Engine) -> Generator[Session, None,
107120

108121
@pytest.fixture(name="test_request")
109122
def test_request_fixture() -> Request:
110-
"""Create a test FastAPI Request object with proper scope."""
123+
"""Create a test FastAPI Request object with proper scope.
124+
125+
Returns:
126+
request (fastapi.Request): A Request object whose scope has `"type":
127+
"http"`, an empty `query_string`, and no headers.
128+
"""
111129
return Request(
112130
scope={
113131
"type": "http",
@@ -119,7 +137,11 @@ def test_request_fixture() -> Request:
119137

120138
@pytest.fixture(name="test_response")
121139
def test_response_fixture() -> Response:
122-
"""Create a test FastAPI Response object with proper scope."""
140+
"""Create a test FastAPI Response object with proper scope.
141+
142+
Returns:
143+
Response: Response with empty content, status 200, and media_type "application/json".
144+
"""
123145
return Response(content="", status_code=200, media_type="application/json")
124146

125147

@@ -129,6 +151,9 @@ async def test_auth_fixture(test_request: Request) -> AuthTuple:
129151
130152
This uses the actual NoopAuthDependency instead of mocking,
131153
making this a true integration test.
154+
155+
Returns:
156+
AuthTuple: Authentication information produced by NoopAuthDependency.
132157
"""
133158
noop_auth = NoopAuthDependency()
134159
return await noop_auth(test_request)

tests/integration/test_configuration.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,19 @@ def test_default_configuration() -> None:
2121

2222

2323
def test_loading_proper_configuration(configuration_filename: str) -> None:
24-
"""Test the configuration loading."""
24+
"""Test the configuration loading.
25+
26+
Validate that loading the given configuration YAML populates all expected sections and values.
27+
28+
Loads configuration from the provided file and asserts presence and
29+
correctness of top-level sections (configuration, service, llama_stack,
30+
user_data_collection, mcp_servers) and selected field values including
31+
service host and flags, CORS settings, llama stack URL and API key secret,
32+
user data collection settings, and three MCP server entries.
33+
34+
Parameters:
35+
configuration_filename (str): Path to the YAML configuration file used for the test.
36+
"""
2537
cfg = configuration
2638
cfg.load_configuration(configuration_filename)
2739

tests/integration/test_openapi_json.py

Lines changed: 108 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,20 @@
2222

2323

2424
def _load_openapi_spec_from_file() -> dict[str, Any]:
25-
"""Load OpenAPI specification from configured path."""
25+
"""Load OpenAPI specification from configured path.
26+
27+
Load and return the OpenAPI JSON document from the configured file path.
28+
29+
If the configured file is present, its contents are parsed as JSON and
30+
returned as a dictionary.
31+
If the file is missing, the running test is failed via pytest.fail.
32+
33+
Returns:
34+
spec (dict[str, Any]): Parsed OpenAPI specification.
35+
36+
Raises:
37+
AssertionError: Causes the test to fail through pytest.fail when the file is not found.
38+
"""
2639
path = Path(OPENAPI_FILE)
2740
if path.is_file():
2841
with path.open("r", encoding="utf-8") as f:
@@ -33,7 +46,13 @@ def _load_openapi_spec_from_file() -> dict[str, Any]:
3346

3447

3548
def _load_openapi_spec_from_url() -> dict[str, Any]:
36-
"""Load OpenAPI specification from URL."""
49+
"""Load OpenAPI specification from URL.
50+
51+
Retrieve the OpenAPI specification by requesting the application's /openapi.json endpoint.
52+
53+
Returns:
54+
dict[str, Any]: The parsed OpenAPI specification as a dictionary.
55+
"""
3756
configuration_filename = "tests/configuration/lightspeed-stack-proper-name.yaml"
3857
cfg = configuration
3958
cfg.load_configuration(configuration_filename)
@@ -52,18 +71,42 @@ def _load_openapi_spec_from_url() -> dict[str, Any]:
5271

5372
@pytest.fixture(scope="module", name="spec_from_file")
5473
def open_api_spec_from_file() -> dict[str, Any]:
55-
"""Fixture containing OpenAPI specification represented as a dictionary."""
74+
"""Fixture containing OpenAPI specification represented as a dictionary.
75+
76+
Provides the parsed OpenAPI specification as a dictionary for tests.
77+
78+
Returns:
79+
openapi_spec (dict[str, Any]): The OpenAPI document parsed from docs/openapi.json.
80+
"""
5681
return _load_openapi_spec_from_file()
5782

5883

5984
@pytest.fixture(scope="module", name="spec_from_url")
6085
def open_api_spec_from_url() -> dict[str, Any]:
61-
"""Fixture containing OpenAPI specification represented as a dictionary."""
86+
"""Fixture containing OpenAPI specification represented as a dictionary.
87+
88+
Provides the OpenAPI specification loaded from the running application's
89+
/openapi.json endpoint.
90+
91+
Returns:
92+
dict: The OpenAPI document parsed into a dictionary.
93+
"""
6294
return _load_openapi_spec_from_url()
6395

6496

6597
def _check_openapi_top_level_info(spec: dict[str, Any]) -> None:
66-
"""Check all top level informations stored in OpenAPI specification."""
98+
"""Check all top level informations stored in OpenAPI specification.
99+
100+
Checks that the OpenAPI version, info section (title and version), contact, and license
101+
(name and URL) match the expected values used by the project.
102+
103+
Parameters:
104+
spec (dict): Parsed OpenAPI specification document.
105+
106+
Raises:
107+
AssertionError: If any required top-level field is missing or does not
108+
match the expected value.
109+
"""
67110
assert spec.get("openapi") == "3.1.0"
68111

69112
info = spec.get("info") or {}
@@ -79,7 +122,14 @@ def _check_openapi_top_level_info(spec: dict[str, Any]) -> None:
79122

80123

81124
def _check_server_section_present(spec: dict[str, Any]) -> None:
82-
"""Check if the servers section stored in OpenAPI specification."""
125+
"""Check if the servers section stored in OpenAPI specification.
126+
127+
Parameters:
128+
spec (dict[str, Any]): Parsed OpenAPI specification.
129+
130+
Raises:
131+
AssertionError: If the 'servers' field is missing, not a list, or empty.
132+
"""
83133
servers = spec.get("servers")
84134
assert isinstance(servers, list) and servers, "servers must be a non-empty list"
85135

@@ -89,14 +139,14 @@ def _check_paths_and_responses_exist(
89139
) -> None:
90140
"""Checks if the specified paths and responses exist in the API specification.
91141
92-
Args:
93-
spec (dict): The API specification.
94-
path (str): The API endpoint path to check.
95-
method (str): The HTTP method to check.
96-
expected_codes (set[str]): The set of expected HTTP status codes.
142+
Parameters:
143+
spec (dict): The API specification.
144+
path (str): The API endpoint path to check.
145+
method (str): The HTTP method to check.
146+
expected_codes (set[str]): The set of expected HTTP status codes.
97147
98-
Raises:
99-
AssertionError: If the path, method, or any of the expected response codes are missing.
148+
Raises:
149+
AssertionError: If the path, method, or any of the expected response codes are missing.
100150
"""
101151
paths = spec.get("paths") or {}
102152
assert path in paths, f"Missing path: {path}"
@@ -111,12 +161,29 @@ def _check_paths_and_responses_exist(
111161

112162

113163
def test_openapi_top_level_info_from_file(spec_from_file: dict[str, Any]) -> None:
114-
"""Test all top level informations stored in OpenAPI specification."""
164+
"""Test all top level informations stored in OpenAPI specification.
165+
166+
Asserts that the OpenAPI version, info (title and version), contact, and
167+
license fields meet the repository's expected values.
168+
169+
Parameters:
170+
spec_from_file (dict[str, Any]): OpenAPI specification dictionary
171+
loaded from docs/openapi.json.
172+
"""
115173
_check_openapi_top_level_info(spec_from_file)
116174

117175

118176
def test_openapi_top_level_info_from_url(spec_from_url: dict[str, Any]) -> None:
119-
"""Test all top level informations stored in OpenAPI specification."""
177+
"""Test all top level informations stored in OpenAPI specification.
178+
179+
Asserts that the OpenAPI version, info section (including title, version,
180+
and contact), and license (name and URL) meet the project's expectations
181+
used by the tests.
182+
183+
Parameters:
184+
spec_from_url (dict[str, Any]): OpenAPI document parsed from the
185+
application's /openapi.json endpoint.
186+
"""
120187
_check_openapi_top_level_info(spec_from_url)
121188

122189

@@ -196,7 +263,19 @@ def test_servers_section_present_from_url(spec_from_url: dict[str, Any]) -> None
196263
def test_paths_and_responses_exist_from_file(
197264
spec_from_file: dict, path: str, method: str, expected_codes: set[str]
198265
) -> None:
199-
"""Tests all paths defined in OpenAPI specification."""
266+
"""Tests all paths defined in OpenAPI specification.
267+
268+
Verify that the given path and HTTP method are defined in the provided
269+
OpenAPI specification and that the operation contains all expected response
270+
status codes.
271+
272+
Parameters:
273+
spec_from_file (dict): OpenAPI specification document loaded from the local file.
274+
path (str): API path to check (e.g., "/items/{id}").
275+
method (str): HTTP method to check for the path (e.g., "get", "post").
276+
expected_codes (set[str]): Set of expected HTTP response status codes
277+
as strings (e.g., {"200", "404"}).
278+
"""
200279
_check_paths_and_responses_exist(spec_from_file, path, method, expected_codes)
201280

202281

@@ -266,5 +345,17 @@ def test_paths_and_responses_exist_from_file(
266345
def test_paths_and_responses_exist_from_url(
267346
spec_from_url: dict, path: str, method: str, expected_codes: set[str]
268347
) -> None:
269-
"""Tests all paths defined in OpenAPI specification."""
348+
"""Tests all paths defined in OpenAPI specification.
349+
350+
Verify that the OpenAPI spec served at /openapi.json contains the given
351+
path and HTTP method and that the operation declares the specified response
352+
status codes.
353+
354+
Parameters:
355+
path (str): OpenAPI path string to check (for example, "/items/{id}").
356+
method (str): HTTP method name for the operation to check (e.g., "get",
357+
"post"); case-insensitive.
358+
expected_codes (set[str]): Set of response status code strings expected
359+
to be present for the operation (for example, {"200", "404"}).
360+
"""
270361
_check_paths_and_responses_exist(spec_from_url, path, method, expected_codes)

tests/integration/test_rh_identity_integration.py

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,14 @@
1515

1616
@pytest.fixture
1717
def client() -> Generator[TestClient, None, None]:
18-
"""Create test client for FastAPI app with RH Identity config."""
18+
"""Create test client for FastAPI app with RH Identity config.
19+
20+
Provides a TestClient for the FastAPI application configured with the RH
21+
Identity test configuration.
22+
23+
Yields:
24+
TestClient: A test client instance for the FastAPI app.
25+
"""
1926
# Save original env var if it exists
2027
original_config = os.environ.get("LIGHTSPEED_STACK_CONFIG_PATH")
2128

@@ -63,7 +70,16 @@ def user_identity_json() -> dict:
6370

6471
@pytest.fixture
6572
def system_identity_json() -> dict:
66-
"""Fixture providing valid System identity JSON."""
73+
"""Fixture providing valid System identity JSON.
74+
75+
Provide a valid RH Identity "System" payload suitable for tests.
76+
77+
Returns:
78+
dict: JSON with keys:
79+
- "identity": contains "account_number", "org_id", "type" set to
80+
"System", and "system" with "cn".
81+
- "entitlements": contains "rhel" with "is_entitled" and "is_trial" boolean flags.
82+
"""
6783
return {
6884
"identity": {
6985
"account_number": "456",
@@ -78,7 +94,14 @@ def system_identity_json() -> dict:
7894

7995

8096
def encode_identity(identity_json: dict) -> str:
81-
"""Encode identity JSON to base64."""
97+
"""Encode identity JSON to base64.
98+
99+
Parameters:
100+
identity_json (dict): JSON-serializable identity payload to encode.
101+
102+
Returns:
103+
str: Base64-encoded UTF-8 string representation of the JSON payload.
104+
"""
82105
json_str = json.dumps(identity_json)
83106
return base64.b64encode(json_str.encode("utf-8")).decode("utf-8")
84107

@@ -89,7 +112,15 @@ class TestRHIdentityIntegration:
89112
def test_valid_user_identity(
90113
self, client: TestClient, user_identity_json: dict
91114
) -> None:
92-
"""Test successful request with valid User identity."""
115+
"""Test successful request with valid User identity.
116+
117+
Verify that a GET to /api/v1/conversations with a valid User RH
118+
Identity is accepted.
119+
120+
Sends the provided User identity encoded in the `x-rh-identity` header
121+
and asserts the response status code is `200` (success) or `404` (no
122+
conversations).
123+
"""
93124
headers = {"x-rh-identity": encode_identity(user_identity_json)}
94125

95126
response = client.get("/api/v1/conversations", headers=headers)

tests/integration/test_version.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,19 @@
66

77

88
def read_version_from_pyproject() -> str:
9-
"""Read version from pyproject.toml file."""
9+
"""Read version from pyproject.toml file.
10+
11+
Retrieve the project's version as reported by the PDM tool.
12+
13+
Invokes the `pdm show --version` command and returns the resulting version string
14+
decoded as UTF-8 with surrounding whitespace removed.
15+
16+
Returns:
17+
version (str): The project version reported by PDM.
18+
19+
Raises:
20+
subprocess.CalledProcessError: If the `pdm` command exits with a non-zero status.
21+
"""
1022
# it is not safe to just try to read version from pyproject.toml file directly
1123
# the PDM tool itself is able to retrieve the version, even if the version
1224
# is generated dynamically
@@ -19,7 +31,14 @@ def read_version_from_pyproject() -> str:
1931

2032

2133
def test_version_handling() -> None:
22-
"""Test how version is handled by the project."""
34+
"""Test how version is handled by the project.
35+
36+
Verify that the package's source __version__ matches the version reported by the project tool.
37+
38+
Raises:
39+
AssertionError: If the source version and the project-reported version
40+
differ; the message includes both versions.
41+
"""
2342
source_version = __version__
2443
project_version = read_version_from_pyproject()
2544
assert (

0 commit comments

Comments
 (0)