Files
ObsiGate/tests/test_media_indexing.py
bruno e2417cb5ab
CI / lint (push) Successful in 1m58s
CI / security (push) Successful in 1m22s
CI / test (push) Successful in 4m32s
CI / build (push) Successful in 2m6s
CI / e2e (push) Successful in 12m57s
feat: support audio & vidéo — lecteurs HTML5 intégrés #109
2026-09-23 09:14:34 -04:00

92 lines
3.5 KiB
Python

# tests/test_media_indexing.py — Audio/video in the tree & index (roadmap #109-A/F2)
import asyncio
from pathlib import Path
from backend.indexer import _index_single_file_sync, _scan_vault
from backend.services.vaults import browse_directory
from backend.watcher import VaultEventHandler
MEDIA_BYTES = b"ID3\x03\x00\x00\x00\x00\x00\x00" + bytes(range(256)) * 16
def _make_vault(tmp_path: Path) -> Path:
vault = tmp_path / "Vault"
vault.mkdir()
(vault / "note.md").write_text("# Note\n", encoding="utf-8")
(vault / "note-vocale.mp3").write_bytes(MEDIA_BYTES)
(vault / "clip.mp4").write_bytes(MEDIA_BYTES)
assets = vault / "assets"
assets.mkdir()
(assets / "ambiance.flac").write_bytes(MEDIA_BYTES)
return vault
class TestScanVaultMedia:
def test_audio_video_indexed_without_content(self, tmp_path):
vault = _make_vault(tmp_path)
result = _scan_vault("V", str(vault))
by_path = {f["path"]: f for f in result["files"]}
for path in ("note-vocale.mp3", "clip.mp4", "assets/ambiance.flac"):
assert path in by_path, path
entry = by_path[path]
assert entry["content"] == "" # never read the bytes (#109-A1)
assert entry["content_preview"] == ""
assert entry["size"] > 0
def test_media_present_in_paths(self, tmp_path):
vault = _make_vault(tmp_path)
result = _scan_vault("V", str(vault))
files = {p["path"] for p in result["paths"] if p["type"] == "file"}
assert "note-vocale.mp3" in files
assert "clip.mp4" in files
assert "assets/ambiance.flac" in files
def test_no_binary_content_leaks(self, tmp_path):
vault = _make_vault(tmp_path)
result = _scan_vault("V", str(vault))
for f in result["files"]:
if f["extension"] in (".mp3", ".mp4", ".flac"):
assert f["content"] == ""
class TestSingleFileMedia:
def test_metadata_only(self, tmp_path):
vault = _make_vault(tmp_path)
info = _index_single_file_sync("V", str(vault), str(vault / "note-vocale.mp3"))
assert info is not None
assert info["content"] == ""
assert info["extension"] == ".mp3"
assert info["path"] == "note-vocale.mp3"
class TestWatcherRelevance:
def test_media_extensions_relevant(self, tmp_path):
handler = VaultEventHandler("V", asyncio.Queue(), asyncio.new_event_loop())
for name in ("a.mp3", "a.flac", "a.opus", "a.mp4", "a.webm", "a.mov"):
assert handler._is_relevant(str(tmp_path / name)) is True, name
assert handler._is_relevant(str(tmp_path / "a.mkv")) is False
class TestBrowseAndSearch:
def test_browse_lists_media(self, client):
resp = client.get("/api/browse/TestVault")
assert resp.status_code == 200
items = resp.json()["items"]
names = {i["name"]: i for i in items}
assert "sample-audio.mp3" in names
assert names["sample-audio.mp3"]["type"] == "file"
assert names["sample-audio.mp3"]["extension"] == ".mp3"
def test_ext_filter_returns_audio(self, client):
resp = client.get("/api/search/advanced", params={"q": "ext:mp3"})
assert resp.status_code == 200
paths = [r["path"] for r in resp.json()["results"]]
assert any(p.endswith(".mp3") for p in paths)
class TestBrowseService:
def test_browse_directory_service(self, app_with_vault, test_vault_dir):
data = browse_directory("TestVault", "")
names = [i["name"] for i in data["items"]]
assert "sample-audio.mp3" in names