import importlib.util import json import subprocess import sys import types import unittest from pathlib import Path from typing import cast from unittest import mock MODULE_PATH = Path(__file__).resolve().parents[1] / "scripts" / "obsidian-reindex-server.py" def load_module(): spec = importlib.util.spec_from_file_location("obsidian_reindex_server", MODULE_PATH) assert spec is not None and spec.loader is not None module = importlib.util.module_from_spec(spec) sys.modules[spec.name] = module spec.loader.exec_module(module) return cast(types.ModuleType, module) class SemanticSearchRerankTests(unittest.TestCase): def setUp(self): self.server = load_module() self.results = [ {"id": "a", "text": "alpha doc", "path": "a.md", "score": 0.1}, {"id": "b", "text": "beta doc", "path": "b.md", "score": 0.2}, {"id": "c", "text": "gamma doc", "path": "c.md", "score": 0.3}, ] def _mock_search_run(self, expected_top_k=None): def fake_run(cmd, capture_output, text, timeout, env): if expected_top_k is not None: self.assertEqual(cmd[cmd.index("--top-k") + 1], str(expected_top_k)) return subprocess.CompletedProcess( cmd, 0, stdout=json.dumps({"index": "obsidian_bge_npu", "results": self.results}), stderr="", ) return fake_run def test_disabled_rerank_preserves_vector_order(self): setattr(self.server, "RAG_RERANK_ENABLED", False) with mock.patch.object(self.server.subprocess, "run", self._mock_search_run(expected_top_k=2)): payload = self.server.run_semantic_search("npu smoke", top_k=2) self.assertTrue(payload["ok"]) self.assertEqual(payload["search_k"], 2) self.assertEqual([item["id"] for item in payload["results"]], ["a", "b"]) self.assertEqual(payload["rerank"]["reason"], "disabled") self.assertFalse(payload["rerank"]["attempted"]) def test_enabled_rerank_reorders_matching_results(self): setattr(self.server, "RAG_RERANK_ENABLED", True) setattr(self.server, "RAG_RERANK_INITIAL_K", 3) setattr(self.server, "RAG_RERANK_TOP_K", 2) class FakeResponse: def __enter__(self): return self def __exit__(self, *args): return False def read(self): return json.dumps( { "ok": True, "model": "synthetic-reranker", "device": "NPU", "npu_busy_delta_us": 123, "results": [ {"id": "c", "score": 9.0}, {"id": "a", "score": 7.0}, ], } ).encode() with mock.patch.object(self.server.subprocess, "run", self._mock_search_run(expected_top_k=3)), mock.patch.object( self.server.request, "urlopen", return_value=FakeResponse() ): payload = self.server.run_semantic_search("npu smoke", top_k=2) self.assertEqual([item["id"] for item in payload["results"]], ["c", "a"]) self.assertTrue(payload["rerank"]["attempted"]) self.assertTrue(payload["rerank"]["ok"]) self.assertEqual(payload["rerank"]["npu_busy_delta_us"], 123) self.assertEqual(payload["results"][0]["rerank_rank"], 1) def test_enabled_rerank_error_falls_back_to_vector_order(self): setattr(self.server, "RAG_RERANK_ENABLED", True) setattr(self.server, "RAG_RERANK_INITIAL_K", 3) setattr(self.server, "RAG_RERANK_TOP_K", 2) with mock.patch.object(self.server.subprocess, "run", self._mock_search_run(expected_top_k=3)), mock.patch.object( self.server.request, "urlopen", side_effect=OSError("reranker unavailable") ): payload = self.server.run_semantic_search("npu smoke", top_k=2) self.assertEqual([item["id"] for item in payload["results"]], ["a", "b"]) self.assertTrue(payload["rerank"]["attempted"]) self.assertFalse(payload["rerank"]["ok"]) self.assertIn("reranker unavailable", payload["rerank"]["error"]) def test_enabled_rerank_requires_positive_npu_proof(self): setattr(self.server, "RAG_RERANK_ENABLED", True) setattr(self.server, "RAG_RERANK_INITIAL_K", 3) setattr(self.server, "RAG_RERANK_TOP_K", 2) setattr(self.server, "RAG_RERANK_REQUIRE_NPU_PROOF", True) class FakeResponse: def __enter__(self): return self def __exit__(self, *args): return False def read(self): return json.dumps( { "ok": True, "device": "NPU", "npu_busy_delta_us": 0, "results": [{"id": "c", "score": 9.0}], } ).encode() with mock.patch.object(self.server.subprocess, "run", self._mock_search_run(expected_top_k=3)), mock.patch.object( self.server.request, "urlopen", return_value=FakeResponse() ): payload = self.server.run_semantic_search("npu smoke", top_k=2) self.assertEqual([item["id"] for item in payload["results"]], ["a", "b"]) self.assertTrue(payload["rerank"]["attempted"]) self.assertFalse(payload["rerank"]["ok"]) self.assertIn("positive npu_busy_delta_us", payload["rerank"]["error"]) if __name__ == "__main__": unittest.main()