"""Migration 0112's data step, DB-lane: a user who already has two Watch later lists keeps the oldest, with the other's videos moved in after its own (one it already held is not added twice), and the one-per-user index then refuses a second list. The schema half is checked by test_migrations.py; a video lost on the way is invisible there. """ from datetime import datetime, timezone import pytest from alembic import command from alembic.config import Config from sqlalchemy import text from sqlalchemy.exc import IntegrityError from app.catalog.models import Channel, Video from app.db import engine def test_a_second_watch_later_is_folded_into_the_first(db, make_user): user, other = make_user(), make_user() db.add(Channel(id="UCm", title="M")) now = datetime.now(timezone.utc) for v in ("v1", "v2", "v3"): db.add(Video(id=v, channel_id="UCm", published_at=now, duration_seconds=60)) db.commit() cfg = Config("alembic.ini") command.downgrade(cfg, "0111_audit_request_id") try: with engine.begin() as conn: ids = conn.execute( text( "INSERT INTO playlists (user_id, name, kind, position) VALUES" " (:u, 'Watch later', 'watch_later', 0), (:u, 'Watch later', 'watch_later', 1)," " (:o, 'Watch later', 'watch_later', 0) RETURNING id" ), {"u": user.id, "o": other.id}, ).scalars() first, second, theirs = list(ids) conn.execute( text( "INSERT INTO playlist_items (playlist_id, video_id, position) VALUES" " (:a, 'v1', 0), (:b, 'v2', 0), (:b, 'v1', 1), (:c, 'v3', 0)" ), {"a": first, "b": second, "c": theirs}, ) finally: command.upgrade(cfg, "head") with engine.connect() as conn: lists = conn.execute( text("SELECT id, user_id FROM playlists WHERE kind = 'watch_later' ORDER BY id") ).all() assert [tuple(r) for r in lists] == [(first, user.id), (theirs, other.id)] items = conn.execute( text( "SELECT playlist_id, video_id, position FROM playlist_items ORDER BY playlist_id, position" ) ).all() assert [tuple(r) for r in items] == [(first, "v1", 0), (first, "v2", 1), (theirs, "v3", 0)] with pytest.raises(IntegrityError), engine.begin() as conn: conn.execute( text( "INSERT INTO playlists (user_id, name, kind, position)" " VALUES (:u, 'Watch later', 'watch_later', 2)" ), {"u": user.id}, )