fc3d: DownloadService finalize hook — Source.consecutive_failures/last_error/last_checked_at
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -272,3 +272,101 @@ async def test_patreon_retry_caches_campaign_id(
|
||||
select(Source.config_overrides).where(Source.id == source.id)
|
||||
).scalar_one()
|
||||
assert overrides.get("patreon_campaign_id") == "99"
|
||||
|
||||
|
||||
# --- FC-3d: finalize hook updates Source health columns -------------------
|
||||
|
||||
|
||||
async def _seed_source_with_health(db, *, failures=0, last_error=None, suffix="fz"):
|
||||
artist = Artist(name=f"alice-{suffix}", slug=f"alice-{suffix}")
|
||||
db.add(artist)
|
||||
await db.flush()
|
||||
source = Source(
|
||||
artist_id=artist.id, platform="patreon",
|
||||
url=f"https://patreon.com/alice-{suffix}", enabled=True,
|
||||
consecutive_failures=failures, last_error=last_error,
|
||||
)
|
||||
db.add(source)
|
||||
await db.flush()
|
||||
event = DownloadEvent(source_id=source.id, status="running")
|
||||
db.add(event)
|
||||
await db.commit()
|
||||
return source.id, event.id
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_finalize_ok_resets_failures_and_clears_error(db):
|
||||
from backend.app.services.download_service import DownloadService
|
||||
|
||||
source_id, event_id = await _seed_source_with_health(
|
||||
db, failures=3, last_error="prev", suffix="ok",
|
||||
)
|
||||
svc = DownloadService(
|
||||
async_session=db, sync_session=None,
|
||||
gdl=None, importer=None, cred_service=None,
|
||||
)
|
||||
await svc._finalize_event_and_source(
|
||||
event_id=event_id, source_id=source_id, status="ok",
|
||||
error_message=None,
|
||||
)
|
||||
|
||||
row = (await db.execute(
|
||||
select(
|
||||
Source.consecutive_failures, Source.last_error, Source.last_checked_at,
|
||||
).where(Source.id == source_id)
|
||||
)).one()
|
||||
assert row.consecutive_failures == 0
|
||||
assert row.last_error is None
|
||||
assert row.last_checked_at is not None
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_finalize_error_increments_failures_and_sets_error(db):
|
||||
from backend.app.services.download_service import DownloadService
|
||||
|
||||
source_id, event_id = await _seed_source_with_health(
|
||||
db, failures=2, last_error=None, suffix="err",
|
||||
)
|
||||
svc = DownloadService(
|
||||
async_session=db, sync_session=None,
|
||||
gdl=None, importer=None, cred_service=None,
|
||||
)
|
||||
await svc._finalize_event_and_source(
|
||||
event_id=event_id, source_id=source_id, status="error",
|
||||
error_message="boom",
|
||||
)
|
||||
|
||||
row = (await db.execute(
|
||||
select(
|
||||
Source.consecutive_failures, Source.last_error, Source.last_checked_at,
|
||||
).where(Source.id == source_id)
|
||||
)).one()
|
||||
assert row.consecutive_failures == 3
|
||||
assert row.last_error == "boom"
|
||||
assert row.last_checked_at is not None
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_finalize_skipped_preserves_failures_clears_error(db):
|
||||
from backend.app.services.download_service import DownloadService
|
||||
|
||||
source_id, event_id = await _seed_source_with_health(
|
||||
db, failures=4, last_error="stale", suffix="skip",
|
||||
)
|
||||
svc = DownloadService(
|
||||
async_session=db, sync_session=None,
|
||||
gdl=None, importer=None, cred_service=None,
|
||||
)
|
||||
await svc._finalize_event_and_source(
|
||||
event_id=event_id, source_id=source_id, status="skipped",
|
||||
error_message=None,
|
||||
)
|
||||
|
||||
row = (await db.execute(
|
||||
select(
|
||||
Source.consecutive_failures, Source.last_error, Source.last_checked_at,
|
||||
).where(Source.id == source_id)
|
||||
)).one()
|
||||
assert row.consecutive_failures == 4
|
||||
assert row.last_error is None
|
||||
assert row.last_checked_at is not None
|
||||
|
||||
Reference in New Issue
Block a user