reddit-media-collector/tests/test_router_stats.py
Richard Nixon 34c2b16e19 test: cover routers, auth, rate limit, config_manager, imgur extractor
- tests/test_auth.py: enable/disable via env, valid/invalid creds
- tests/test_rate_limit.py: bucket math + window expiry
- tests/test_router_media.py: path traversal (file/thumb), paginated subreddits/authors, blacklist preview shape, DELETE flow, cleanup-by-type 400 paths
- tests/test_router_stats.py: cache TTL, .json exclusion, missing dir
- tests/test_router_favorites.py: paginated favorites/authors, no N+1 (query count), favorites_only filter
- tests/test_router_config.py: CRUD subreddits/users/blacklist
- tests/test_config_manager.py: case-insensitive dedupe, blacklist removes from collection, domain normalization
- tests/test_extractors_imgur.py: i.imgur direct, gifv->mp4, albums/galleries -> None

src/database.py: resolve RMC_DB_PATH lazily in Database() so tests can monkeypatch the env per case (no more module-import capture)

Result: 135 passed (was 77). Coverage 55% global; 100% on auth/imgur, 96% rate_limit, 84% stats router, 80% config_manager.
2026-05-17 11:54:40 +01:00

71 lines
2.3 KiB
Python

"""Tests for /api/stats router (cache, async scan)."""
from __future__ import annotations
import asyncio
import pytest
from fastapi.testclient import TestClient
from src.web import deps
from src.web.app import app
from src.web.routers import stats as stats_router
@pytest.fixture
def client(tmp_path, monkeypatch):
downloads = tmp_path / "downloads"
downloads.mkdir()
monkeypatch.setattr(deps, "DOWNLOADS_DIR", downloads)
monkeypatch.setattr(stats_router, "DOWNLOADS_DIR", downloads)
stats_router._reset_stats_cache()
monkeypatch.setenv("RMC_DB_PATH", str(tmp_path / "media.db"))
return TestClient(app)
def test_stats_endpoint_returns_expected_keys(client):
response = client.get("/api/stats")
assert response.status_code == 200
data = response.json()
for key in ("file_count", "disk_size_bytes", "disk_size_mb", "disk_size_gb", "disk_free_gb"):
assert key in data
def test_stats_counts_files_excluding_json(client, tmp_path):
# Create some media + a sidecar
downloads = tmp_path / "downloads"
(downloads / "a.jpg").write_bytes(b"x" * 100)
(downloads / "b.mp4").write_bytes(b"y" * 200)
(downloads / "a.jpg.json").write_bytes(b"{}") # sidecar should not count
stats_router._reset_stats_cache()
response = client.get("/api/stats")
data = response.json()
assert data["file_count"] == 2
assert data["disk_size_bytes"] == 300
def test_stats_cache_serves_stale_within_ttl(client, tmp_path):
downloads = tmp_path / "downloads"
(downloads / "a.jpg").write_bytes(b"x" * 100)
stats_router._reset_stats_cache()
first = client.get("/api/stats").json()
assert first["file_count"] == 1
# Add another file but don't reset cache; expect cached value
(downloads / "b.jpg").write_bytes(b"y" * 50)
second = client.get("/api/stats").json()
assert second["file_count"] == 1 # cached
# After cache reset, the new file is reflected
stats_router._reset_stats_cache()
third = client.get("/api/stats").json()
assert third["file_count"] == 2
def test_scan_downloads_handles_missing_dir(tmp_path):
stats_router._reset_stats_cache()
missing = tmp_path / "nope"
size, count = asyncio.run(stats_router._scan_downloads_cached(missing))
assert size == 0
assert count == 0