chore: import upstream snapshot with attribution
CI / lint (push) Has been cancelled
CI / js-syntax (push) Successful in 10m24s
CI / deps-audit (push) Has been cancelled
CI / test (push) Failing after 24m55s
CI / sast-bandit (push) Failing after 11m13s
CI / trivy (push) Failing after 9m32s
Docker Publish / build-and-push (push) Failing after 34m3s
CI / lint (push) Has been cancelled
CI / js-syntax (push) Successful in 10m24s
CI / deps-audit (push) Has been cancelled
CI / test (push) Failing after 24m55s
CI / sast-bandit (push) Failing after 11m13s
CI / trivy (push) Failing after 9m32s
Docker Publish / build-and-push (push) Failing after 34m3s
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import time
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from app.core.models import Job
|
||||
from app.core.registry import _jobs
|
||||
from app.pipeline.collect import sweep_old_jobs
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _isolate_registry():
|
||||
_jobs.clear()
|
||||
yield
|
||||
_jobs.clear()
|
||||
|
||||
|
||||
def _mkdir(jobs_dir: Path, name: str) -> Path:
|
||||
d = jobs_dir / name
|
||||
d.mkdir(parents=True)
|
||||
(d / "marker").write_bytes(b"x")
|
||||
return d
|
||||
|
||||
|
||||
def test_skip_active_job_even_if_old(tmp_path: Path):
|
||||
"""An active (non-terminal) job's directory must never be swept,
|
||||
even if its created_at predates the TTL cutoff."""
|
||||
d = _mkdir(tmp_path, "abcdefabcdef")
|
||||
job = Job(id="abcdefabcdef")
|
||||
job.status = "separating"
|
||||
job.created_at = time.time() - 999_999 # ancient
|
||||
_jobs[job.id] = job
|
||||
|
||||
with patch("app.pipeline.collect.JOB_TTL_SECONDS", 60):
|
||||
sweep_old_jobs(tmp_path)
|
||||
|
||||
assert d.is_dir()
|
||||
assert job.id in _jobs
|
||||
|
||||
|
||||
def test_sweeps_terminal_old_job(tmp_path: Path):
|
||||
d = _mkdir(tmp_path, "abcdefabcdee")
|
||||
job = Job(id="abcdefabcdee")
|
||||
job.status = "done"
|
||||
job.created_at = time.time() - 999_999
|
||||
_jobs[job.id] = job
|
||||
|
||||
with patch("app.pipeline.collect.JOB_TTL_SECONDS", 60):
|
||||
sweep_old_jobs(tmp_path)
|
||||
|
||||
assert not d.exists()
|
||||
assert job.id not in _jobs
|
||||
|
||||
|
||||
def test_sweep_disabled_under_desktop(monkeypatch):
|
||||
"""The desktop shell (STEMDECK_DESKTOP=1) opts out of the TTL sweep so a
|
||||
user's curated library isn't purged; the server/Docker default keeps it."""
|
||||
from app.main import _sweep_disabled
|
||||
|
||||
monkeypatch.delenv("STEMDECK_PERSIST_LIBRARY", raising=False)
|
||||
monkeypatch.setenv("STEMDECK_DESKTOP", "1")
|
||||
assert _sweep_disabled() is True
|
||||
monkeypatch.delenv("STEMDECK_DESKTOP", raising=False)
|
||||
assert _sweep_disabled() is False
|
||||
|
||||
|
||||
def test_sweep_disabled_under_persistent_library(monkeypatch):
|
||||
"""A self-hosted server (run.sh) opts into a persistent library
|
||||
(STEMDECK_PERSIST_LIBRARY=1) so its processed tracks aren't purged."""
|
||||
from app.main import _sweep_disabled
|
||||
|
||||
monkeypatch.delenv("STEMDECK_DESKTOP", raising=False)
|
||||
monkeypatch.setenv("STEMDECK_PERSIST_LIBRARY", "1")
|
||||
assert _sweep_disabled() is True
|
||||
monkeypatch.delenv("STEMDECK_PERSIST_LIBRARY", raising=False)
|
||||
assert _sweep_disabled() is False
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_sweep_loop_returns_immediately_under_desktop(monkeypatch):
|
||||
"""In desktop mode the loop returns at once instead of entering the hourly
|
||||
cycle (wait_for would time out if it looped)."""
|
||||
import asyncio
|
||||
|
||||
from app.main import _sweep_loop
|
||||
|
||||
monkeypatch.setenv("STEMDECK_DESKTOP", "1")
|
||||
await asyncio.wait_for(_sweep_loop(), timeout=2)
|
||||
|
||||
|
||||
def test_keeps_recent_terminal_job(tmp_path: Path):
|
||||
d = _mkdir(tmp_path, "abcdefabcded")
|
||||
job = Job(id="abcdefabcded")
|
||||
job.status = "done"
|
||||
job.created_at = time.time() # fresh
|
||||
_jobs[job.id] = job
|
||||
|
||||
with patch("app.pipeline.collect.JOB_TTL_SECONDS", 60):
|
||||
sweep_old_jobs(tmp_path)
|
||||
|
||||
assert d.is_dir()
|
||||
assert job.id in _jobs
|
||||
|
||||
|
||||
def test_orphan_dir_falls_back_to_mtime(tmp_path: Path):
|
||||
"""Directories with no registry entry (e.g. left over from a prior
|
||||
server run) still get swept by mtime."""
|
||||
d = _mkdir(tmp_path, "abcdefabcdec")
|
||||
# Backdate the directory.
|
||||
old = time.time() - 999_999
|
||||
import os
|
||||
|
||||
os.utime(d, (old, old))
|
||||
|
||||
with patch("app.pipeline.collect.JOB_TTL_SECONDS", 60):
|
||||
sweep_old_jobs(tmp_path)
|
||||
|
||||
assert not d.exists()
|
||||
Reference in New Issue
Block a user