feat: initial scaffold + JobStore (v0.1.0)
This commit is contained in:
110
tests/test_jobs.py
Normal file
110
tests/test_jobs.py
Normal file
@@ -0,0 +1,110 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
|
||||
import pytest
|
||||
|
||||
from platform_common.jobs import (
|
||||
InMemoryJobStore,
|
||||
JobNotFoundError,
|
||||
JobRecord,
|
||||
JobStatus,
|
||||
JobStore,
|
||||
make_job_store,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def store() -> InMemoryJobStore:
|
||||
return InMemoryJobStore()
|
||||
|
||||
|
||||
def test_protocol_conformance(store: InMemoryJobStore) -> None:
|
||||
assert isinstance(store, JobStore)
|
||||
|
||||
|
||||
async def test_create_and_get(store: InMemoryJobStore) -> None:
|
||||
record = await store.create("j1", {"input": "hello"}, ttl_seconds=60)
|
||||
assert record.id == "j1"
|
||||
assert record.status is JobStatus.PENDING
|
||||
assert record.payload == {"input": "hello"}
|
||||
fetched = await store.get("j1")
|
||||
assert fetched is not None
|
||||
assert fetched.payload == {"input": "hello"}
|
||||
|
||||
|
||||
async def test_create_duplicate_raises(store: InMemoryJobStore) -> None:
|
||||
await store.create("j1", ttl_seconds=60)
|
||||
with pytest.raises(ValueError, match="already exists"):
|
||||
await store.create("j1", ttl_seconds=60)
|
||||
|
||||
|
||||
async def test_get_missing_returns_none(store: InMemoryJobStore) -> None:
|
||||
assert await store.get("nope") is None
|
||||
|
||||
|
||||
async def test_update_patches_fields(store: InMemoryJobStore) -> None:
|
||||
await store.create("j1", {"a": 1}, ttl_seconds=60)
|
||||
updated = await store.update("j1", status=JobStatus.RUNNING, result={"out": 42})
|
||||
assert updated.status is JobStatus.RUNNING
|
||||
assert updated.result == {"out": 42}
|
||||
assert updated.payload == {"a": 1}
|
||||
assert updated.updated_at >= updated.created_at
|
||||
|
||||
|
||||
async def test_update_missing_raises(store: InMemoryJobStore) -> None:
|
||||
with pytest.raises(JobNotFoundError):
|
||||
await store.update("nope", status=JobStatus.FAILED)
|
||||
|
||||
|
||||
async def test_delete(store: InMemoryJobStore) -> None:
|
||||
await store.create("j1", ttl_seconds=60)
|
||||
assert await store.delete("j1") is True
|
||||
assert await store.delete("j1") is False
|
||||
assert await store.get("j1") is None
|
||||
|
||||
|
||||
async def test_ttl_expiry(store: InMemoryJobStore) -> None:
|
||||
await store.create("j1", ttl_seconds=1)
|
||||
assert await store.exists("j1")
|
||||
await asyncio.sleep(1.1)
|
||||
assert await store.get("j1") is None
|
||||
assert await store.exists("j1") is False
|
||||
|
||||
|
||||
async def test_invalid_ttl(store: InMemoryJobStore) -> None:
|
||||
with pytest.raises(ValueError, match="positive"):
|
||||
await store.create("j1", ttl_seconds=0)
|
||||
|
||||
|
||||
async def test_lru_capacity() -> None:
|
||||
store = InMemoryJobStore(max_records=3)
|
||||
for i in range(5):
|
||||
await store.create(f"j{i}", ttl_seconds=60)
|
||||
ids = await store.list_ids()
|
||||
assert set(ids) == {"j2", "j3", "j4"}
|
||||
|
||||
|
||||
async def test_record_roundtrip() -> None:
|
||||
record = JobRecord(id="j1", status=JobStatus.SUCCEEDED, payload={"k": "v"}, result={"r": 1})
|
||||
restored = JobRecord.from_dict(record.to_dict())
|
||||
assert restored == record
|
||||
|
||||
|
||||
def test_make_job_store_default(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
monkeypatch.delenv("JOB_STORE_URL", raising=False)
|
||||
assert isinstance(make_job_store(), InMemoryJobStore)
|
||||
|
||||
|
||||
def test_make_job_store_memory_explicit() -> None:
|
||||
assert isinstance(make_job_store("memory://"), InMemoryJobStore)
|
||||
|
||||
|
||||
def test_make_job_store_redis_not_yet_implemented() -> None:
|
||||
with pytest.raises(NotImplementedError, match=r"v0\.2"):
|
||||
make_job_store("redis://localhost:6379/0")
|
||||
|
||||
|
||||
def test_make_job_store_unknown_scheme() -> None:
|
||||
with pytest.raises(ValueError, match="unsupported"):
|
||||
make_job_store("kafka://broker")
|
||||
Reference in New Issue
Block a user