Ctrl K
ComunidadGuías…

backend/tests/test_foreign_track_scan_store.py

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
"""Tests for the foreign-track scan repository."""

import os

import pytest

from db.models import foreign_tracks as ft


@pytest.fixture()
def app(tmp_path):
    """Create a Flask app with an isolated SQLite DB for testing."""
    from app import create_app
    from config import reload_settings

    db_path = str(tmp_path / "test.db")
    os.environ["SUBLARR_DB_PATH"] = db_path
    os.environ["SUBLARR_API_KEY"] = ""
    os.environ["SUBLARR_LOG_LEVEL"] = "ERROR"

    reload_settings()

    application = create_app(testing=True)
    application.config["TESTING"] = True

    with application.app_context():
        yield application

    os.environ.pop("SUBLARR_DB_PATH", None)
    os.environ.pop("SUBLARR_API_KEY", None)
    os.environ.pop("SUBLARR_LOG_LEVEL", None)


@pytest.fixture
def repo(app):
    from db.repositories.foreign_track_scan import ForeignTrackScanRepository

    return ForeignTrackScanRepository()


def test_upsert_inserts_a_new_path_as_pending(repo):
    repo.upsert_seen("/media/a.mkv", 100, 1.0, generation=1)
    rows = repo.next_pending(limit=10)
    assert [r.path for r in rows] == ["/media/a.mkv"]
    assert rows[0].state == ft.STATE_PENDING


def test_upsert_keeps_the_verdict_when_size_and_mtime_are_unchanged(repo):
    repo.upsert_seen("/media/a.mkv", 100, 1.0, generation=1)
    repo.mark_probed("/media/a.mkv", [])
    repo.upsert_seen("/media/a.mkv", 100, 1.0, generation=2)
    assert repo.next_pending(limit=10) == []
    assert repo.counts_by_state()[ft.STATE_CLEAN] == 1


def test_upsert_resets_the_verdict_when_the_file_changed(repo):
    repo.upsert_seen("/media/a.mkv", 100, 1.0, generation=1)
    repo.mark_probed("/media/a.mkv", [])
    repo.upsert_seen("/media/a.mkv", 200, 2.0, generation=2)
    assert [r.path for r in repo.next_pending(limit=10)] == ["/media/a.mkv"]


def test_upsert_resets_attempts_when_the_file_changed(repo):
    repo.upsert_seen("/media/a.mkv", 100, 1.0, generation=1)
    repo.mark_failed("/media/a.mkv", "boom", ft.ERROR_PROBE)
    repo.upsert_seen("/media/a.mkv", 200, 2.0, generation=2)
    rows = repo.next_pending(limit=10)
    assert rows[0].attempts == 0


def test_prune_stale_removes_rows_from_older_generations(repo):
    repo.upsert_seen("/media/gone.mkv", 1, 1.0, generation=1)
    repo.upsert_seen("/media/here.mkv", 1, 1.0, generation=2)
    assert repo.prune_stale(generation=2) == 1
    assert [r.path for r in repo.next_pending(limit=10)] == ["/media/here.mkv"]


def test_mark_probed_with_languages_becomes_affected(repo):
    repo.upsert_seen("/media/a.mkv", 1, 1.0, generation=1)
    repo.mark_probed("/media/a.mkv", ["spa", "ita"])
    row = repo.claim_next_affected()
    assert row.path == "/media/a.mkv"
    assert row.track_count == 2
    assert row.state == ft.STATE_STRIPPING


def test_claim_returns_none_when_nothing_is_affected(repo):
    assert repo.claim_next_affected() is None


def test_release_stripping_returns_abandoned_rows_to_affected(repo):
    repo.upsert_seen("/media/a.mkv", 1, 1.0, generation=1)
    repo.mark_probed("/media/a.mkv", ["spa"])
    repo.claim_next_affected()
    assert repo.release_stripping() == 1
    assert repo.claim_next_affected().path == "/media/a.mkv"


def test_mark_failed_parks_the_row_after_the_attempt_cap(repo):
    repo.upsert_seen("/media/a.mkv", 1, 1.0, generation=1)
    for _ in range(ft.MAX_ATTEMPTS):
        repo.mark_failed("/media/a.mkv", "boom", ft.ERROR_PROBE)
    assert repo.counts_by_state()[ft.STATE_FAILED] == 1
    assert repo.next_pending(limit=10) == []


def test_mark_failed_on_a_claimed_row_returns_it_to_affected_for_retry(repo):
    repo.upsert_seen("/media/a.mkv", 1, 1.0, generation=1)
    repo.mark_probed("/media/a.mkv", ["spa"])
    repo.claim_next_affected()
    repo.mark_failed("/media/a.mkv", "remux boom", ft.ERROR_REMUX)
    assert repo.counts_by_state()[ft.STATE_AFFECTED] == 1
    row = repo.claim_next_affected()
    assert row.path == "/media/a.mkv"
    assert row.attempts == 1


def test_verify_failures_park_immediately(repo):
    repo.upsert_seen("/media/a.mkv", 1, 1.0, generation=1)
    repo.mark_failed("/media/a.mkv", "bad", ft.ERROR_VERIFY)
    assert repo.counts_by_state()[ft.STATE_FAILED] == 1


def test_mark_probed_on_a_missing_path_is_a_no_op(repo):
    repo.mark_probed("/media/missing.mkv", ["spa"])
    assert repo.counts_by_state() == {}


def test_mark_stripped_on_a_missing_path_is_a_no_op(repo):
    repo.mark_stripped("/media/missing.mkv")
    assert repo.counts_by_state() == {}


def test_mark_failed_on_a_missing_path_is_a_no_op(repo):
    repo.mark_failed("/media/missing.mkv", "boom", ft.ERROR_PROBE)
    assert repo.counts_by_state() == {}


def test_reset_all_to_pending_includes_stripped_rows(repo):
    repo.upsert_seen("/media/a.mkv", 1, 1.0, generation=1)
    repo.mark_probed("/media/a.mkv", ["spa"])
    repo.claim_next_affected()
    repo.mark_stripped("/media/a.mkv")
    assert repo.reset_all_to_pending() == 1
    assert [r.path for r in repo.next_pending(limit=10)] == ["/media/a.mkv"]


def test_sample_affected_reports_paths_and_languages(repo):
    repo.upsert_seen("/media/a.mkv", 1, 1.0, generation=1)
    repo.mark_probed("/media/a.mkv", ["spa", "ita"])
    sample = repo.sample_affected(limit=5)
    assert sample == [
        {"path": "/media/a.mkv", "tracks": 2, "langs": ["ita", "spa"], "verdicts": []}
    ]