|
1 | 1 | import json |
| 2 | +from unittest.mock import patch |
2 | 3 |
|
3 | 4 | import httpx |
4 | 5 | import pytest |
|
7 | 8 |
|
8 | 9 | from fastapi_cloud_cli.cli import cloud_app as app |
9 | 10 | from fastapi_cloud_cli.config import Settings |
| 11 | +from fastapi_cloud_cli.utils.api import TooManyRetriesError |
10 | 12 | from tests.conftest import ConfiguredApp |
11 | 13 | from tests.utils import changing_dir |
12 | 14 |
|
@@ -270,3 +272,53 @@ def test_skips_invalid_json_lines( |
270 | 272 |
|
271 | 273 | assert result.exit_code == 0 |
272 | 274 | assert "Valid log message" in result.output |
| 275 | + |
| 276 | + |
| 277 | +@pytest.mark.respx(base_url=settings.base_api_url) |
| 278 | +def test_skips_heartbeat_messages( |
| 279 | + logged_in_cli: None, respx_mock: respx.MockRouter, configured_app: ConfiguredApp |
| 280 | +) -> None: |
| 281 | + log_lines = [ |
| 282 | + json.dumps({"type": "heartbeat"}), |
| 283 | + json.dumps( |
| 284 | + { |
| 285 | + "timestamp": "2025-12-05T14:32:01.123000Z", |
| 286 | + "message": "Real log message", |
| 287 | + "level": "info", |
| 288 | + } |
| 289 | + ), |
| 290 | + ] |
| 291 | + response_content = "\n".join(log_lines) |
| 292 | + |
| 293 | + respx_mock.get(url__regex=rf"/apps/{configured_app.app_id}/logs/stream.*").mock( |
| 294 | + return_value=httpx.Response(200, content=response_content) |
| 295 | + ) |
| 296 | + |
| 297 | + with changing_dir(configured_app.path): |
| 298 | + result = runner.invoke(app, ["logs", "--no-follow"]) |
| 299 | + |
| 300 | + assert result.exit_code == 0 |
| 301 | + assert "Real log message" in result.output |
| 302 | + assert "heartbeat" not in result.output.lower() |
| 303 | + |
| 304 | + |
| 305 | +@pytest.mark.parametrize( |
| 306 | + "error", |
| 307 | + [TooManyRetriesError, TimeoutError], |
| 308 | +) |
| 309 | +def test_handles_connection_loss( |
| 310 | + logged_in_cli: None, |
| 311 | + configured_app: ConfiguredApp, |
| 312 | + error: type[Exception], |
| 313 | +) -> None: |
| 314 | + with ( |
| 315 | + changing_dir(configured_app.path), |
| 316 | + patch( |
| 317 | + "fastapi_cloud_cli.utils.api.APIClient.stream_app_logs", |
| 318 | + side_effect=error("Connection lost"), |
| 319 | + ), |
| 320 | + ): |
| 321 | + result = runner.invoke(app, ["logs", "--no-follow"]) |
| 322 | + |
| 323 | + assert result.exit_code == 1 |
| 324 | + assert "Lost connection to log stream" in result.output |
0 commit comments