"""Migration 0103's data step, DB-lane: the fileless "expired" rows of the old retention go, every other job stays. An expired file now leaves the library (`downloads.gc`); before, it stayed as a done job with no asset. Left in place, those rows would sit unseen in no listing forever. """ from alembic import command from alembic.config import Config from sqlalchemy import text from app.db import engine def test_the_fileless_expired_rows_go_and_every_other_job_stays(db, make_user): uid = make_user().id cfg = Config("alembic.ini") command.downgrade(cfg, "0102_file_folders") try: with engine.begin() as conn: folder = conn.execute( text( "INSERT INTO file_folders (user_id, kind, source_key, retention_days)" " VALUES (:u, 'source', 'youtube', 30) RETURNING id" ), {"u": uid}, ).scalar_one() asset = conn.execute( text( "INSERT INTO media_assets (source_kind, source_ref, format_sig, status, ref_count)" " VALUES ('youtube', 'abcdefghijk', 'sig', 'ready', 1) RETURNING id" ) ).scalar_one() def job(status, asset_id): return conn.execute( text( "INSERT INTO download_jobs (user_id, asset_id, source_kind, source_ref," " profile_snapshot, status, folder_id) VALUES (:u, :a, 'youtube'," " 'abcdefghijk', '{}', :s, :f) RETURNING id" ), {"u": uid, "a": asset_id, "s": status, "f": folder}, ).scalar_one() expired = job("done", None) alive = job("done", asset) failed = job("error", None) # a failed job has no file either, and is not expired queued = job("queued", None) finally: command.upgrade(cfg, "head") with engine.connect() as conn: left = set(conn.execute(text("SELECT id FROM download_jobs")).scalars()) has_hash = conn.execute( text( "SELECT count(*) FROM information_schema.columns" " WHERE table_name = 'media_assets' AND column_name = 'sha256'" ) ).scalar() assert left == {alive, failed, queued} assert expired not in left assert has_hash == 1