"""Tests for service.index_service."""
from __future__ import annotations
from unittest.mock import Mock
import service.index_service as index_service_module
from index.scheduler import SchedulerMetrics
class ImmediateThread:
def __init__(self, target, args=(), name=None, daemon=None):
self._target = target
self._args = args
self.name = name
self.daemon = daemon
self.started = False
def start(self):
self.started = True
self._target(*self._args)
class FakeScheduler:
instances = []
def __init__(self, worker, outbox_store, get_account_ids, worker_id, interval_seconds):
self.worker = worker
self.outbox_store = outbox_store
self.get_account_ids = get_account_ids
self.worker_id = worker_id
self.interval_seconds = interval_seconds
self.started = False
self.stop_calls = []
self.metrics = SchedulerMetrics(
worker_id=worker_id,
total_processed=3,
total_succeeded=2,
total_failed=1,
total_dlq=1,
)
type(self).instances.append(self)
def start(self):
self.started = True
def stop(self, wait=True):
self.stop_calls.append(wait)
def test_start_creates_worker_threads_and_schedulers(monkeypatch):
FakeScheduler.instances = []
worker_ctor = Mock(return_value=Mock())
monkeypatch.setattr(index_service_module, "OutboxWorker", worker_ctor)
monkeypatch.setattr(index_service_module, "OutboxScheduler", FakeScheduler)
monkeypatch.setattr(index_service_module.threading, "Thread", ImmediateThread)
monkeypatch.setattr(index_service_module.uuid, "uuid4", Mock(side_effect=[Mock(hex="aaaabbbbccccdddd"), Mock(hex="1111222233334444")]))
service = index_service_module.IndexService(
outbox_store=Mock(),
embedder=Mock(),
vector_index=Mock(),
get_account_ids=lambda: ["acct-1"],
interval_seconds=12,
worker_count=2,
)
service.start()
assert service.is_running is True
assert len(service.schedulers) == 2
assert all(s.started for s in service.schedulers)
assert len(service._threads) == 2
worker_ctor.assert_called_once()
def test_start_is_idempotent(monkeypatch):
FakeScheduler.instances = []
monkeypatch.setattr(index_service_module, "OutboxWorker", Mock(return_value=Mock()))
monkeypatch.setattr(index_service_module, "OutboxScheduler", FakeScheduler)
monkeypatch.setattr(index_service_module.threading, "Thread", ImmediateThread)
warning = Mock()
monkeypatch.setattr(index_service_module.logger, "warning", warning)
service = index_service_module.IndexService(
outbox_store=Mock(),
embedder=Mock(),
vector_index=Mock(),
get_account_ids=lambda: [],
worker_count=1,
)
service.start()
service.start()
warning.assert_called_once()
def test_stop_clears_runtime_state(monkeypatch):
FakeScheduler.instances = []
monkeypatch.setattr(index_service_module, "OutboxWorker", Mock(return_value=Mock()))
monkeypatch.setattr(index_service_module, "OutboxScheduler", FakeScheduler)
monkeypatch.setattr(index_service_module.threading, "Thread", ImmediateThread)
service = index_service_module.IndexService(
outbox_store=Mock(),
embedder=Mock(),
vector_index=Mock(),
get_account_ids=lambda: [],
worker_count=2,
)
service.start()
service.stop(wait=False)
assert service.is_running is False
assert service.schedulers == []
assert service._threads == []
for scheduler in FakeScheduler.instances:
assert scheduler.stop_calls == [False]
def test_get_metrics_and_aggregated_stats(monkeypatch):
FakeScheduler.instances = []
monkeypatch.setattr(index_service_module, "OutboxWorker", Mock(return_value=Mock()))
monkeypatch.setattr(index_service_module, "OutboxScheduler", FakeScheduler)
monkeypatch.setattr(index_service_module.threading, "Thread", ImmediateThread)
service = index_service_module.IndexService(
outbox_store=Mock(),
embedder=Mock(),
vector_index=Mock(),
get_account_ids=lambda: [],
worker_count=2,
)
service.start()
metrics = service.get_metrics()
stats = service.get_aggregated_stats()
assert len(metrics) == 2
assert stats == {
"worker_count": 2,
"total_processed": 6,
"total_succeeded": 4,
"total_failed": 2,
"total_dlq": 2,
"is_running": True,
}
def test_singleton_helpers_and_signal_handlers(monkeypatch):
handlers = {}
exits = []
monkeypatch.setattr(index_service_module.signal, "signal", lambda sig, handler: handlers.setdefault(sig, handler))
monkeypatch.setattr(index_service_module.sys, "exit", lambda code: exits.append(code))
service = Mock()
created = index_service_module.init_index_service(
outbox_store=Mock(),
embedder=Mock(),
vector_index=Mock(),
get_account_ids=lambda: ["acct-1"],
worker_count=1,
)
assert index_service_module.get_index_service() is created
index_service_module.setup_signal_handlers(service)
handlers[index_service_module.signal.SIGINT](2, None)
service.stop.assert_called_once_with(wait=True)
assert exits == [0]