Files
Timmy-time-dashboard/tests/unit/test_content_indexer.py
Claude (Opus 4.6) f0841bd34e
Some checks failed
Tests / lint (push) Has been cancelled
Tests / test (push) Has been cancelled
[claude] Automated Episode Compiler — Highlights to Published Video (#880) (#1318)
2026-03-24 02:05:14 +00:00

171 lines
6.1 KiB
Python

"""Unit tests for content.archive.indexer."""
from __future__ import annotations
from unittest.mock import patch
import pytest
from content.archive.indexer import (
EpisodeDocument,
IndexResult,
_meilisearch_available,
index_episode,
search_episodes,
)
# ── _meilisearch_available ────────────────────────────────────────────────────
class TestMeilisearchAvailable:
def test_returns_bool(self):
assert isinstance(_meilisearch_available(), bool)
def test_false_when_spec_missing(self):
with patch("importlib.util.find_spec", return_value=None):
assert _meilisearch_available() is False
# ── EpisodeDocument ───────────────────────────────────────────────────────────
class TestEpisodeDocument:
def test_to_dict_contains_id(self):
doc = EpisodeDocument(id="ep-001", title="Test")
d = doc.to_dict()
assert d["id"] == "ep-001"
def test_to_dict_contains_title(self):
doc = EpisodeDocument(id="ep-001", title="My Episode")
assert doc.to_dict()["title"] == "My Episode"
def test_to_dict_defaults(self):
doc = EpisodeDocument(id="ep-001", title="T")
d = doc.to_dict()
assert d["tags"] == []
assert d["highlight_ids"] == []
assert d["duration"] == 0.0
assert d["clip_count"] == 0
def test_to_dict_preserves_tags(self):
doc = EpisodeDocument(id="ep-001", title="T", tags=["gaming", "highlights"])
assert doc.to_dict()["tags"] == ["gaming", "highlights"]
def test_to_dict_all_fields(self):
doc = EpisodeDocument(
id="ep-002",
title="Full",
description="Desc",
tags=["t"],
published_at="2026-03-23T00:00:00Z",
youtube_url="https://yt.com/x",
blossom_url="https://blossom.io/x",
duration=180.0,
clip_count=5,
highlight_ids=["h1", "h2"],
)
d = doc.to_dict()
assert d["description"] == "Desc"
assert d["youtube_url"] == "https://yt.com/x"
assert d["duration"] == 180.0
assert d["highlight_ids"] == ["h1", "h2"]
# ── index_episode ─────────────────────────────────────────────────────────────
class TestIndexEpisode:
@pytest.mark.asyncio
async def test_empty_id_returns_failure(self):
result = await index_episode("", "Title")
assert result.success is False
assert "episode_id" in result.error
@pytest.mark.asyncio
async def test_whitespace_id_returns_failure(self):
result = await index_episode(" ", "Title")
assert result.success is False
@pytest.mark.asyncio
async def test_returns_failure_when_meilisearch_missing(self):
with patch("content.archive.indexer._meilisearch_available", return_value=False):
result = await index_episode("ep-001", "Title")
assert result.success is False
assert "meilisearch" in result.error.lower()
@pytest.mark.asyncio
async def test_successful_indexing(self):
fake_result = IndexResult(success=True, document_id="ep-001")
with (
patch("content.archive.indexer._meilisearch_available", return_value=True),
patch("asyncio.to_thread", return_value=fake_result),
):
result = await index_episode(
"ep-001",
"Test Episode",
description="A test",
tags=["gaming"],
published_at="2026-03-23T00:00:00Z",
youtube_url="https://yt.com/abc",
duration=120.0,
clip_count=3,
highlight_ids=["h1", "h2", "h3"],
)
assert result.success is True
assert result.document_id == "ep-001"
@pytest.mark.asyncio
async def test_exception_from_thread_returns_failure(self):
with (
patch("content.archive.indexer._meilisearch_available", return_value=True),
patch("asyncio.to_thread", side_effect=RuntimeError("connection refused")),
):
result = await index_episode("ep-001", "Title")
assert result.success is False
assert "connection refused" in result.error
# ── search_episodes ───────────────────────────────────────────────────────────
class TestSearchEpisodes:
@pytest.mark.asyncio
async def test_returns_empty_when_library_missing(self):
with patch("content.archive.indexer._meilisearch_available", return_value=False):
results = await search_episodes("highlights")
assert results == []
@pytest.mark.asyncio
async def test_returns_hits_on_success(self):
fake_hits = [{"id": "ep-001", "title": "Gaming Highlights"}]
with (
patch("content.archive.indexer._meilisearch_available", return_value=True),
patch("asyncio.to_thread", return_value=fake_hits),
):
results = await search_episodes("gaming")
assert len(results) == 1
assert results[0]["id"] == "ep-001"
@pytest.mark.asyncio
async def test_returns_empty_on_exception(self):
with (
patch("content.archive.indexer._meilisearch_available", return_value=True),
patch("asyncio.to_thread", side_effect=RuntimeError("timeout")),
):
results = await search_episodes("query")
assert results == []
@pytest.mark.asyncio
async def test_empty_list_when_no_results(self):
with (
patch("content.archive.indexer._meilisearch_available", return_value=True),
patch("asyncio.to_thread", return_value=[]),
):
results = await search_episodes("nothing matches")
assert results == []