mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-11-10 23:07:03 +01:00
The last six over-cap files split into eleven new modules, in two passes since the first cut left five still over. python_pkg has no violations left at all, down from 50 when this effort started. Each split carries the whole preamble including the module's pytest fixtures - started, toolkit and session are taken as parameters and resolve lexically, so a hand-written import block would have missed them. ruff then pruned 82 unused imports. Pass count is 277 before and after, checked after both passes. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011w2Pj4Ek3ZNMQVYcFHgXDY
212 lines
6.1 KiB
Python
212 lines
6.1 KiB
Python
"""Tests for the composition root and verdict application."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import queue
|
|
import threading
|
|
from typing import TYPE_CHECKING
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
import pytest
|
|
|
|
from python_pkg.wsg_grabber import (
|
|
app,
|
|
db,
|
|
downloader,
|
|
paths,
|
|
review,
|
|
store,
|
|
)
|
|
from python_pkg.wsg_grabber.models import RemoteFile, Verdict
|
|
from python_pkg.wsg_grabber.states import FileState
|
|
|
|
if TYPE_CHECKING:
|
|
from collections.abc import Callable, Iterator
|
|
|
|
_MD5 = "Nz9OEKdMuMZEdYE6eLTKmA=="
|
|
|
|
|
|
@pytest.fixture
|
|
def session() -> Iterator[app.Session]:
|
|
"""Build a session over a sandboxed index, with no worker running.
|
|
|
|
Yields:
|
|
app.Session: Session whose connection is closed afterwards.
|
|
"""
|
|
paths.ensure_dirs()
|
|
conn = db.open_index(paths.db_path())
|
|
built = app.Session(conn=conn, events=queue.SimpleQueue(), stop=threading.Event())
|
|
try:
|
|
yield built
|
|
finally:
|
|
conn.close()
|
|
|
|
|
|
def _downloaded(session: app.Session, name: str = "clip") -> None:
|
|
"""Put one downloaded, unreviewed file into the index and on disk.
|
|
|
|
Args:
|
|
session: The session to populate.
|
|
name: Local filename stem.
|
|
"""
|
|
store.record_files(
|
|
session.conn,
|
|
[
|
|
RemoteFile(
|
|
md5=_MD5,
|
|
tim=1,
|
|
ext=".webm",
|
|
orig_name=name,
|
|
fsize=5,
|
|
width=4,
|
|
height=3,
|
|
thread_no=7,
|
|
post_no=1,
|
|
),
|
|
],
|
|
)
|
|
local = f"{name}.webm"
|
|
(paths.incoming_dir() / local).write_bytes(b"video")
|
|
store.mark_downloaded(session.conn, _MD5, local)
|
|
|
|
|
|
def test_keep_moves_the_file_and_records_it(session: app.Session) -> None:
|
|
_downloaded(session)
|
|
state = app.initial_state(session)
|
|
result = session.commit(state, Verdict.KEEP)
|
|
|
|
assert (paths.keep_dir() / "clip.webm").exists()
|
|
assert not (paths.incoming_dir() / "clip.webm").exists()
|
|
assert store.state_of(session.conn, _MD5) is FileState.KEPT
|
|
assert result.kept == 1
|
|
|
|
|
|
def test_pass_moves_to_trash_and_never_deletes(session: app.Session) -> None:
|
|
"""The whole point of trash/: a pass is reversible until the user says so."""
|
|
_downloaded(session)
|
|
state = app.initial_state(session)
|
|
result = session.commit(state, Verdict.SKIP)
|
|
|
|
assert (paths.trash_dir() / "clip.webm").exists()
|
|
assert (paths.trash_dir() / "clip.webm").read_bytes() == b"video"
|
|
assert store.state_of(session.conn, _MD5) is FileState.PASSED
|
|
assert result.passed == 1
|
|
|
|
|
|
def test_a_name_collision_in_the_destination_is_resolved(
|
|
session: app.Session,
|
|
) -> None:
|
|
_downloaded(session)
|
|
(paths.keep_dir() / "clip.webm").write_bytes(b"older")
|
|
session.commit(app.initial_state(session), Verdict.KEEP)
|
|
|
|
assert (paths.keep_dir() / "clip.webm").read_bytes() == b"older"
|
|
assert (paths.keep_dir() / "clip-2.webm").read_bytes() == b"video"
|
|
|
|
|
|
def test_a_verdict_on_a_vanished_file_writes_it_off(session: app.Session) -> None:
|
|
_downloaded(session)
|
|
state = app.initial_state(session)
|
|
(paths.incoming_dir() / "clip.webm").unlink()
|
|
|
|
result = session.commit(state, Verdict.KEEP)
|
|
assert store.state_of(session.conn, _MD5) is FileState.GONE
|
|
assert result.kept == 0
|
|
assert result.current is None
|
|
|
|
|
|
def test_a_verdict_with_nothing_showing_is_ignored(session: app.Session) -> None:
|
|
state = review.initial_state(0, [])
|
|
assert session.commit(state, Verdict.KEEP) is state
|
|
assert session.missing(state) is state
|
|
|
|
|
|
def test_initial_state_resumes_a_previous_run(session: app.Session) -> None:
|
|
_downloaded(session)
|
|
state = app.initial_state(session)
|
|
assert state.current is not None
|
|
assert state.current.md5 == _MD5
|
|
assert state.indexed == 1
|
|
|
|
|
|
def test_shutdown_stops_the_worker_and_closes_the_index() -> None:
|
|
paths.ensure_dirs()
|
|
conn = db.open_index(paths.db_path())
|
|
worker = MagicMock()
|
|
worker.is_alive.return_value = False
|
|
built = app.Session(
|
|
conn=conn,
|
|
events=queue.SimpleQueue(),
|
|
stop=threading.Event(),
|
|
worker=worker,
|
|
)
|
|
built.shutdown()
|
|
assert built.stop.is_set()
|
|
worker.join.assert_called_once()
|
|
assert built.worker is None
|
|
|
|
|
|
def test_shutdown_without_a_worker() -> None:
|
|
paths.ensure_dirs()
|
|
conn = db.open_index(paths.db_path())
|
|
built = app.Session(conn=conn, events=queue.SimpleQueue(), stop=threading.Event())
|
|
built.shutdown()
|
|
assert built.stop.is_set()
|
|
|
|
|
|
def test_open_session_starts_a_worker_owning_its_own_connection() -> None:
|
|
"""sqlite forbids sharing a connection across threads, so the factory must
|
|
build one on the worker's side of the boundary."""
|
|
captured: list[downloader.WorkerDeps] = []
|
|
|
|
def fake_start(
|
|
build: Callable[[], downloader.WorkerDeps],
|
|
_on_failure: Callable[[str], None] = lambda _m: None,
|
|
) -> MagicMock:
|
|
deps = build()
|
|
captured.append(deps)
|
|
deps.conn.close()
|
|
deps.session.close()
|
|
return MagicMock()
|
|
|
|
with patch.object(downloader, "start", side_effect=fake_start):
|
|
built = app.open_session(include_archive=False)
|
|
try:
|
|
assert captured
|
|
assert captured[0].incoming == paths.incoming_dir()
|
|
assert not captured[0].include_archive
|
|
assert paths.incoming_dir().is_dir()
|
|
assert paths.trash_dir().is_dir()
|
|
finally:
|
|
built.shutdown()
|
|
|
|
|
|
def test_open_session_recovers_interrupted_downloads() -> None:
|
|
paths.ensure_dirs()
|
|
conn = db.open_index(paths.db_path())
|
|
store.record_files(
|
|
conn,
|
|
[
|
|
RemoteFile(
|
|
md5=_MD5,
|
|
tim=1,
|
|
ext=".webm",
|
|
orig_name="x",
|
|
fsize=1,
|
|
width=1,
|
|
height=1,
|
|
thread_no=1,
|
|
post_no=1,
|
|
),
|
|
],
|
|
)
|
|
store.claim_next(conn)
|
|
conn.close()
|
|
|
|
with patch.object(downloader, "start", return_value=MagicMock()):
|
|
built = app.open_session()
|
|
try:
|
|
assert store.pending_downloads(built.conn) == 1
|
|
finally:
|
|
built.shutdown()
|