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.
This commit is contained in:
parent
5f9c6023c1
commit
34c2b16e19
9 changed files with 651 additions and 2 deletions
71
tests/test_router_stats.py
Normal file
71
tests/test_router_stats.py
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
"""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
|
||||
Loading…
Add table
Add a link
Reference in a new issue