Skip to content

Commit f0fbb8e

Browse files
test: search-index concurrency for rebuild, queries, and lock order (#139)
* test: concurrency suite for search-index rebuild, pointer swap, and query * test: exercise background rebuild and lock order in concurrency suite * test: fix ruff and mypy on search-index concurrency tests * fix: stoppable background worker and stronger concurrency test oracles * fix: keep background worker ownership until stop is confirmed * address per comment * fix docstring * Pin locked-index live-scan fallback in concurrency test
1 parent bcde11d commit f0fbb8e

4 files changed

Lines changed: 533 additions & 66 deletions

File tree

tests/conftest.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,32 @@
22

33
from __future__ import annotations
44

5+
import json
56
import os
67
import shutil
78
from collections.abc import Mapping
89
from pathlib import Path
10+
from unittest.mock import patch
911

1012
import pytest
1113
from hypothesis import settings
1214

1315
from app import create_app
1416

17+
18+
def write_session(path: Path, lines: list[dict[str, object]]) -> None:
19+
"""Write JSONL session *lines* to *path*, creating parent directories."""
20+
path.parent.mkdir(parents=True, exist_ok=True)
21+
with path.open("w", encoding="utf-8") as handle:
22+
for line in lines:
23+
handle.write(json.dumps(line, ensure_ascii=False) + "\n")
24+
25+
26+
def index_patches(cache_root: Path):
27+
"""Return the patch context managers that point the index at *cache_root*."""
28+
return (patch("utils.search_index.cache_dir", return_value=cache_root),)
29+
30+
1531
# Hypothesis profiles drive fuzz example counts/deadlines (deadline disabled to
1632
# avoid timing flakiness on slow/CI runners). CI runs fewer examples for speed.
1733
settings.register_profile("dev", max_examples=200, deadline=None)
@@ -67,7 +83,7 @@ def client(tmp_path, export_state_file):
6783

6884
@pytest.fixture
6985
def client_single(tmp_path, export_state_file):
70-
"""Flask test client with one seeded session ? for search/limit tests."""
86+
"""Flask test client with one seeded session for search/limit tests."""
7187
return _make_test_client(tmp_path, {"session_abc123.jsonl": "session_minimal.jsonl"})
7288

7389

tests/test_search_index.py

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
from __future__ import annotations
44

5-
import json
65
import sqlite3
76
from contextlib import closing, contextmanager
87
from datetime import UTC, datetime, timedelta
@@ -12,6 +11,7 @@
1211
import pytest
1312

1413
from api.search import _resolve_search_results, _search_via_index
14+
from tests.conftest import index_patches as _index_patches, write_session as _write_session
1515
from utils.exclusion_rules import load_rules
1616
from utils.search_index import (
1717
build_search_index,
@@ -26,17 +26,6 @@
2626
)
2727

2828

29-
def _write_session(path: Path, lines: list[dict[str, object]]) -> None:
30-
path.parent.mkdir(parents=True, exist_ok=True)
31-
with path.open("w", encoding="utf-8") as handle:
32-
for line in lines:
33-
handle.write(json.dumps(line, ensure_ascii=False) + "\n")
34-
35-
36-
def _index_patches(cache_root: Path):
37-
return (patch("utils.search_index.cache_dir", return_value=cache_root),)
38-
39-
4029
@pytest.fixture
4130
def indexed_tree(tmp_path, monkeypatch):
4231
"""Temp projects dir + isolated search index cache."""
@@ -381,11 +370,15 @@ def test_background_worker_starts_once(self, indexed_tree, monkeypatch):
381370
patches[0],
382371
patch("utils.search_index.threading.Thread") as mock_thread,
383372
):
373+
# The mock worker is not a real thread; report it as stopped so the
374+
# teardown reset does not treat it as a live worker that won't join.
375+
mock_thread.return_value.is_alive.return_value = False
384376
start_search_index_background(indexed_tree["projects"], [])
385377
start_search_index_background(indexed_tree["projects"], [])
386378
assert mock_thread.call_count == 1
387379
assert mock_thread.call_args.kwargs.get("daemon") is True
388380
assert mock_thread.return_value.start.call_count == 1
381+
reset_background_for_tests()
389382

390383

391384
class TestIndexSearchCompleteness:

0 commit comments

Comments
 (0)