decomposer: generate deliverable files for Define the service contract and project architecture for the FastAPI endpoint monitoring service.; Implement the typed monitor CRUD API and concurrency-safe in-memory state according to the service design.; Implement secure on-demand endpoint checks with status updates, latency measurement, robust error handling, and redacted structured logs.; Add operational API endpoints and environment-driven runtime configuration to the monitoring service.; Create automated tests for the monitoring service.; Package the service with Docker and developer documentation.; Validate the complete project.
Some checks failed
ci / test (push) Has been cancelled
Some checks failed
ci / test (push) Has been cancelled
This commit is contained in:
@@ -1,21 +1,38 @@
|
||||
import asyncio
|
||||
|
||||
import pytest
|
||||
|
||||
from endpoint_monitor.models import MonitorCreate
|
||||
from endpoint_monitor.store import Conflict, MonitorStore
|
||||
from app.models import CheckStatus, MonitorCreate, MonitorUpdate
|
||||
from app.store import MonitorStore
|
||||
|
||||
|
||||
async def test_concurrent_unique_name_is_atomic():
|
||||
store = MonitorStore(10)
|
||||
data = MonitorCreate(name="same", url="https://example.com")
|
||||
results = await asyncio.gather(store.create(data), store.create(data), return_exceptions=True)
|
||||
assert sum(not isinstance(item, Exception) for item in results) == 1
|
||||
assert sum(isinstance(item, Conflict) for item in results) == 1
|
||||
async def test_concurrent_creates_are_not_lost():
|
||||
store = MonitorStore()
|
||||
await asyncio.gather(*[
|
||||
store.create(MonitorCreate(name=f"m-{index}", url="https://example.com"))
|
||||
for index in range(100)
|
||||
])
|
||||
items = await store.list()
|
||||
assert len(items) == 100
|
||||
assert len({item.id for item in items}) == 100
|
||||
|
||||
|
||||
async def test_capacity():
|
||||
store = MonitorStore(1)
|
||||
await store.create(MonitorCreate(name="one", url="https://example.com"))
|
||||
with pytest.raises(Conflict, match="capacity"):
|
||||
await store.create(MonitorCreate(name="two", url="https://example.org"))
|
||||
async def test_stale_check_cannot_overwrite_updated_monitor():
|
||||
store = MonitorStore()
|
||||
item = await store.create(MonitorCreate(name="before", url="https://example.com"))
|
||||
old = await store.snapshot(item.id)
|
||||
assert old is not None
|
||||
await store.update(item.id, MonitorUpdate(name="after"))
|
||||
applied = await store.apply_status(item.id, old.revision, CheckStatus(state="up"))
|
||||
assert applied is False
|
||||
current = await store.snapshot(item.id)
|
||||
assert current is not None
|
||||
assert current.monitor.name == "after"
|
||||
assert current.monitor.status.state == "unknown"
|
||||
|
||||
|
||||
async def test_delete_wins_over_in_flight_check():
|
||||
store = MonitorStore()
|
||||
item = await store.create(MonitorCreate(name="x", url="https://example.com"))
|
||||
snapshot = await store.snapshot(item.id)
|
||||
assert snapshot is not None
|
||||
await store.delete(item.id)
|
||||
assert await store.apply_status(item.id, snapshot.revision, CheckStatus(state="up")) is False
|
||||
|
||||
Reference in New Issue
Block a user