Skip to content

Commit 19256d8

Browse files
committed
✅ Isolate tests from config
Shortcake-Parent: main
1 parent 0d97abd commit 19256d8

File tree

12 files changed

+157
-131
lines changed

12 files changed

+157
-131
lines changed

src/fastapi_cloud_cli/utils/config.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
1+
import os
12
from pathlib import Path
23

34
import typer
45

6+
CONFIG_DIR_ENV_VAR = "FASTAPI_CLOUD_CLI_CONFIG_DIR"
7+
58

69
def get_config_folder() -> Path:
10+
config_dir = os.getenv(CONFIG_DIR_ENV_VAR)
11+
12+
if config_dir:
13+
return Path(config_dir).expanduser()
14+
715
return Path(typer.get_app_dir("fastapi-cli"))
816

917

tests/conftest.py

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,35 @@
1+
import os
12
import sys
3+
import tempfile
24
from collections.abc import Generator
35
from dataclasses import dataclass
46
from pathlib import Path
5-
from unittest.mock import patch
67

78
import pytest
9+
import respx
810
from typer import rich_utils
911

12+
from fastapi_cloud_cli.config import Settings
13+
from fastapi_cloud_cli.utils.config import CONFIG_DIR_ENV_VAR
14+
1015
from .utils import create_jwt_token
1116

1217

18+
@pytest.fixture(autouse=True)
19+
def isolated_config_path() -> Generator[Path, None, None]:
20+
with tempfile.TemporaryDirectory() as tmpdir:
21+
os.environ[CONFIG_DIR_ENV_VAR] = tmpdir
22+
23+
yield Path(tmpdir)
24+
25+
26+
@pytest.fixture
27+
def temp_auth_config(
28+
isolated_config_path: Path, monkeypatch: pytest.MonkeyPatch
29+
) -> Generator[Path, None, None]:
30+
yield isolated_config_path / "auth.json"
31+
32+
1333
@pytest.fixture(autouse=True)
1434
def reset_syspath() -> Generator[None, None, None]:
1535
initial_python_path = sys.path.copy()
@@ -26,6 +46,17 @@ def setup_terminal() -> None:
2646
return
2747

2848

49+
@pytest.fixture
50+
def settings() -> Settings:
51+
return Settings.get()
52+
53+
54+
@pytest.fixture
55+
def respx_mock(settings: Settings) -> Generator[respx.MockRouter, None, None]:
56+
with respx.mock(base_url=settings.base_api_url) as mock_router:
57+
yield mock_router
58+
59+
2960
@pytest.fixture
3061
def logged_in_cli(temp_auth_config: Path) -> Generator[None, None, None]:
3162
valid_token = create_jwt_token({"sub": "test_user_12345"})
@@ -60,13 +91,3 @@ def configured_app(tmp_path: Path) -> ConfiguredApp:
6091
config_path.write_text(f'{{"app_id": "{app_id}", "team_id": "{team_id}"}}')
6192

6293
return ConfiguredApp(app_id=app_id, team_id=team_id, path=tmp_path)
63-
64-
65-
@pytest.fixture
66-
def temp_auth_config(tmp_path: Path) -> Generator[Path, None, None]:
67-
"""Provides a temporary auth config setup for testing file operations."""
68-
69-
with patch(
70-
"fastapi_cloud_cli.utils.config.get_config_folder", return_value=tmp_path
71-
):
72-
yield tmp_path / "auth.json"

tests/test_api_client.py

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
from httpx import Response
88
from time_machine import TimeMachineFixture
99

10-
from fastapi_cloud_cli.config import Settings
1110
from fastapi_cloud_cli.utils.api import (
1211
STREAM_LOGS_MAX_RETRIES,
1312
APIClient,
@@ -17,8 +16,6 @@
1716
)
1817
from tests.utils import build_logs_response
1918

20-
settings = Settings.get()
21-
2219

2320
@pytest.fixture
2421
def client() -> httpx.Client:
@@ -31,15 +28,11 @@ def deployment_id() -> str:
3128
return "test-deployment-123"
3229

3330

34-
api_mock = respx.mock(base_url=settings.base_api_url)
35-
36-
3731
@pytest.fixture
38-
def logs_route(deployment_id: str) -> respx.Route:
39-
return api_mock.get(f"/deployments/{deployment_id}/build-logs")
32+
def logs_route(respx_mock: respx.MockRouter, deployment_id: str) -> respx.Route:
33+
return respx_mock.get(f"/deployments/{deployment_id}/build-logs")
4034

4135

42-
@api_mock
4336
def test_stream_build_logs_successful(
4437
logs_route: respx.Route,
4538
client: APIClient,
@@ -69,7 +62,6 @@ def test_stream_build_logs_successful(
6962
assert logs[2].type == "complete"
7063

7164

72-
@api_mock
7365
def test_stream_build_logs_failed(
7466
logs_route: respx.Route, client: APIClient, deployment_id: str
7567
) -> None:
@@ -91,7 +83,6 @@ def test_stream_build_logs_failed(
9183

9284

9385
@pytest.mark.parametrize("terminal_type", ["complete", "failed"])
94-
@api_mock
9586
def test_stream_build_logs_stop_after_terminal_state(
9687
logs_route: respx.Route,
9788
client: APIClient,
@@ -116,7 +107,6 @@ def test_stream_build_logs_stop_after_terminal_state(
116107
assert logs[1].type == terminal_type
117108

118109

119-
@api_mock
120110
def test_stream_build_logs_internal_messages_are_skipped(
121111
logs_route: respx.Route,
122112
client: APIClient,
@@ -140,7 +130,6 @@ def test_stream_build_logs_internal_messages_are_skipped(
140130
assert logs[1].type == "complete"
141131

142132

143-
@api_mock
144133
def test_stream_build_logs_malformed_json_is_skipped(
145134
logs_route: respx.Route, client: APIClient, deployment_id: str
146135
) -> None:
@@ -161,7 +150,6 @@ def test_stream_build_logs_malformed_json_is_skipped(
161150
assert logs[1].type == "complete"
162151

163152

164-
@api_mock
165153
def test_stream_build_logs_unknown_log_type_is_skipped(
166154
logs_route: respx.Route, client: APIClient, deployment_id: str
167155
) -> None:
@@ -188,7 +176,6 @@ def test_stream_build_logs_unknown_log_type_is_skipped(
188176
"network_error",
189177
[httpx.NetworkError, httpx.TimeoutException, httpx.RemoteProtocolError],
190178
)
191-
@api_mock
192179
def test_stream_build_logs_network_error_retry(
193180
logs_route: respx.Route,
194181
client: APIClient,
@@ -216,7 +203,6 @@ def test_stream_build_logs_network_error_retry(
216203
assert logs[0].message == "Success after retry"
217204

218205

219-
@api_mock
220206
def test_stream_build_logs_server_error_retry(
221207
logs_route: respx.Route, client: APIClient, deployment_id: str
222208
) -> None:
@@ -237,7 +223,6 @@ def test_stream_build_logs_server_error_retry(
237223
assert logs[0].type == "complete"
238224

239225

240-
@api_mock
241226
def test_stream_build_logs_client_error_raises_immediately(
242227
logs_route: respx.Route, client: APIClient, deployment_id: str
243228
) -> None:
@@ -247,7 +232,6 @@ def test_stream_build_logs_client_error_raises_immediately(
247232
list(client.stream_build_logs(deployment_id))
248233

249234

250-
@api_mock
251235
def test_stream_build_logs_max_retries_exceeded(
252236
logs_route: respx.Route, client: APIClient, deployment_id: str
253237
) -> None:
@@ -261,7 +245,6 @@ def test_stream_build_logs_max_retries_exceeded(
261245
list(client.stream_build_logs(deployment_id))
262246

263247

264-
@api_mock
265248
def test_stream_build_logs_empty_lines_are_skipped(
266249
logs_route: respx.Route, client: APIClient, deployment_id: str
267250
) -> None:
@@ -284,7 +267,6 @@ def test_stream_build_logs_empty_lines_are_skipped(
284267
assert logs[1].type == "complete"
285268

286269

287-
@respx.mock(base_url=settings.base_api_url)
288270
def test_stream_build_logs_continue_after_timeout(
289271
respx_mock: respx.MockRouter,
290272
client: APIClient,
@@ -328,7 +310,6 @@ def test_stream_build_logs_continue_after_timeout(
328310
assert next(logs).type == "complete"
329311

330312

331-
@api_mock
332313
def test_stream_build_logs_connection_closed_without_complete_failed_or_timeout(
333314
logs_route: respx.Route, client: APIClient, deployment_id: str
334315
) -> None:
@@ -348,7 +329,6 @@ def test_stream_build_logs_connection_closed_without_complete_failed_or_timeout(
348329
next(logs)
349330

350331

351-
@api_mock
352332
def test_stream_build_logs_retry_timeout(
353333
logs_route: respx.Route,
354334
client: APIClient,

0 commit comments

Comments
 (0)