feat(cloud-api): run lifecycle workers
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import time
|
||||
|
||||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
@@ -20,8 +22,20 @@ def test_create_app_returns_independent_cloud_application() -> None:
|
||||
def test_cloud_application_owns_database_lifecycle() -> None:
|
||||
events: list[str] = []
|
||||
|
||||
class FakeRepository:
|
||||
def health_check(self) -> None:
|
||||
events.append("healthy")
|
||||
|
||||
def list_queued_tasks(self) -> list[object]:
|
||||
events.append("scheduled")
|
||||
return []
|
||||
|
||||
def reap_expired_leases(self, *, now, max_attempts: int) -> list[str]:
|
||||
events.append("reaped")
|
||||
return []
|
||||
|
||||
class FakeDatabase:
|
||||
repository = object()
|
||||
repository = FakeRepository()
|
||||
|
||||
def close(self) -> None:
|
||||
events.append("closed")
|
||||
@@ -37,9 +51,9 @@ def test_cloud_application_owns_database_lifecycle() -> None:
|
||||
assert (
|
||||
app.state.cloud_services.pool.store is app.state.cloud_services.repository
|
||||
)
|
||||
assert events == []
|
||||
assert "healthy" in events
|
||||
|
||||
assert events == ["closed"]
|
||||
assert events[-1] == "closed"
|
||||
|
||||
|
||||
def test_repository_proxy_is_available_only_during_lifespan() -> None:
|
||||
@@ -47,6 +61,12 @@ def test_repository_proxy_is_available_only_during_lifespan() -> None:
|
||||
def health_check(self) -> None:
|
||||
return None
|
||||
|
||||
def list_queued_tasks(self) -> list[object]:
|
||||
return []
|
||||
|
||||
def reap_expired_leases(self, *, now, max_attempts: int) -> list[str]:
|
||||
return []
|
||||
|
||||
class FakeDatabase:
|
||||
repository = FakeRepository()
|
||||
|
||||
@@ -65,6 +85,47 @@ def test_repository_proxy_is_available_only_during_lifespan() -> None:
|
||||
app.state.cloud_services.repository.health_check()
|
||||
|
||||
|
||||
def test_lifespan_runs_scheduler_and_reaper_until_shutdown() -> None:
|
||||
events: list[str] = []
|
||||
|
||||
class FakeRepository:
|
||||
def health_check(self) -> None:
|
||||
events.append("healthy")
|
||||
|
||||
def list_queued_tasks(self) -> list[object]:
|
||||
events.append("scheduled")
|
||||
return []
|
||||
|
||||
def reap_expired_leases(self, *, now, max_attempts: int) -> list[str]:
|
||||
events.append(f"reaped:{max_attempts}")
|
||||
return []
|
||||
|
||||
class FakeDatabase:
|
||||
repository = FakeRepository()
|
||||
|
||||
def close(self) -> None:
|
||||
events.append("closed")
|
||||
|
||||
app = create_app(
|
||||
config=CloudControlConfig(
|
||||
database_url="sqlite:///:memory:",
|
||||
scheduler_interval_seconds=0.01,
|
||||
lease_reaper_interval_seconds=0.01,
|
||||
max_task_attempts=4,
|
||||
),
|
||||
database_factory=lambda _config: FakeDatabase(), # type: ignore[arg-type,return-value]
|
||||
)
|
||||
|
||||
with TestClient(app):
|
||||
time.sleep(0.04)
|
||||
assert events.count("scheduled") >= 2
|
||||
assert events.count("reaped:4") >= 2
|
||||
assert all(not task.done() for task in app.state.worker_tasks)
|
||||
|
||||
assert all(task.done() for task in app.state.worker_tasks)
|
||||
assert events[-1] == "closed"
|
||||
|
||||
|
||||
def test_production_app_rejects_missing_credentials() -> None:
|
||||
with pytest.raises(CloudConfigurationError, match="credential"):
|
||||
create_app(
|
||||
|
||||
Reference in New Issue
Block a user