3131)
3232
3333
34- @dataclass (slots = True )
35- class RecordingMoveBatchStore :
36- results : list [ProjectIndexMoveBatchResult ]
37- batches : list [ProjectIndexMoveBatch ] = field (default_factory = list )
38-
39- async def apply_project_index_move_batch (
40- self ,
34+ def _stub_move_store (
35+ monkeypatch : pytest .MonkeyPatch ,
36+ * ,
37+ results : list [ProjectIndexMoveBatchResult ],
38+ recorded : list [ProjectIndexMoveBatch ],
39+ ) -> RepositoryProjectIndexMaintenanceStore :
40+ """Build a real store whose move-batch apply returns canned results.
41+
42+ The orchestration under test only cares that each batch produces a result and
43+ is recorded in order, so we monkeypatch the single SQL method rather than drive
44+ a real database — the store is otherwise the same concrete used in production.
45+ """
46+ result_iter = iter (results )
47+
48+ async def fake_apply_move_batch (
49+ _self : RepositoryProjectIndexMaintenanceStore ,
4150 move_batch : ProjectIndexMoveBatch ,
4251 ) -> ProjectIndexMoveBatchResult :
43- self . batches .append (move_batch )
44- return self . results . pop ( 0 )
52+ recorded .append (move_batch )
53+ return next ( result_iter )
4554
55+ monkeypatch .setattr (
56+ RepositoryProjectIndexMaintenanceStore ,
57+ "apply_project_index_move_batch" ,
58+ fake_apply_move_batch ,
59+ )
60+ return RepositoryProjectIndexMaintenanceStore (
61+ session_maker = cast (async_sessionmaker [AsyncSession ], object ()),
62+ project_id = 1 ,
63+ )
4664
47- @dataclass (slots = True )
48- class RecordingDeleteBatchStore :
49- results : list [ProjectIndexDeleteBatchResult ]
50- batches : list [ProjectIndexDeleteBatch ] = field (default_factory = list )
5165
52- async def apply_project_index_delete_batch (
53- self ,
66+ def _stub_delete_store (
67+ monkeypatch : pytest .MonkeyPatch ,
68+ * ,
69+ results : list [ProjectIndexDeleteBatchResult ],
70+ recorded : list [ProjectIndexDeleteBatch ],
71+ ) -> RepositoryProjectIndexMaintenanceStore :
72+ """Build a real store whose delete-batch apply returns canned results."""
73+ result_iter = iter (results )
74+
75+ async def fake_apply_delete_batch (
76+ _self : RepositoryProjectIndexMaintenanceStore ,
5477 delete_batch : ProjectIndexDeleteBatch ,
5578 ) -> ProjectIndexDeleteBatchResult :
56- self .batches .append (delete_batch )
57- return self .results .pop (0 )
79+ recorded .append (delete_batch )
80+ return next (result_iter )
81+
82+ monkeypatch .setattr (
83+ RepositoryProjectIndexMaintenanceStore ,
84+ "apply_project_index_delete_batch" ,
85+ fake_apply_delete_batch ,
86+ )
87+ return RepositoryProjectIndexMaintenanceStore (
88+ session_maker = cast (async_sessionmaker [AsyncSession ], object ()),
89+ project_id = 1 ,
90+ )
5891
5992
6093class FakeProjectIndexScalarResult :
@@ -232,8 +265,12 @@ def test_project_index_maintenance_batch_plans_require_positive_batch_size() ->
232265
233266
234267@pytest .mark .asyncio
235- async def test_project_index_move_runner_applies_batches_and_reports_progress () -> None :
236- store = RecordingMoveBatchStore (
268+ async def test_project_index_move_runner_applies_batches_and_reports_progress (
269+ monkeypatch : pytest .MonkeyPatch ,
270+ ) -> None :
271+ recorded_batches : list [ProjectIndexMoveBatch ] = []
272+ store = _stub_move_store (
273+ monkeypatch ,
237274 results = [
238275 ProjectIndexMoveBatchResult (
239276 updated_files = 1 ,
@@ -246,7 +283,8 @@ async def test_project_index_move_runner_applies_batches_and_reports_progress()
246283 updated_files = 1 ,
247284 moved_entity_ids = frozenset ({11 }),
248285 ),
249- ]
286+ ],
287+ recorded = recorded_batches ,
250288 )
251289
252290 run = await run_project_index_move_batches (
@@ -259,7 +297,7 @@ async def test_project_index_move_runner_applies_batches_and_reports_progress()
259297 move_store = store ,
260298 )
261299
262- assert store . batches == [
300+ assert recorded_batches == [
263301 ProjectIndexMoveBatch (
264302 completed_batches = 1 ,
265303 targets = (
@@ -284,8 +322,12 @@ async def test_project_index_move_runner_applies_batches_and_reports_progress()
284322
285323
286324@pytest .mark .asyncio
287- async def test_project_index_delete_runner_applies_batches_and_reports_progress () -> None :
288- store = RecordingDeleteBatchStore (
325+ async def test_project_index_delete_runner_applies_batches_and_reports_progress (
326+ monkeypatch : pytest .MonkeyPatch ,
327+ ) -> None :
328+ recorded_batches : list [ProjectIndexDeleteBatch ] = []
329+ store = _stub_delete_store (
330+ monkeypatch ,
289331 results = [
290332 ProjectIndexDeleteBatchResult (
291333 deleted_entities = 1 ,
@@ -296,7 +338,8 @@ async def test_project_index_delete_runner_applies_batches_and_reports_progress(
296338 deleted_entities = 0 ,
297339 missing_paths = ("notes/c.md" ,),
298340 ),
299- ]
341+ ],
342+ recorded = recorded_batches ,
300343 )
301344
302345 run = await run_project_index_delete_batches (
@@ -305,7 +348,7 @@ async def test_project_index_delete_runner_applies_batches_and_reports_progress(
305348 delete_store = store ,
306349 )
307350
308- assert store . batches == [
351+ assert recorded_batches == [
309352 ProjectIndexDeleteBatch (
310353 completed_batches = 1 ,
311354 paths = ("notes/a.md" , "notes/b.md" ),
@@ -326,15 +369,25 @@ async def test_project_index_delete_runner_applies_batches_and_reports_progress(
326369
327370
328371@pytest .mark .asyncio
329- async def test_store_project_index_maintenance_runner_delegates_to_batch_stores () -> None :
330- move_store = RecordingMoveBatchStore (results = [ProjectIndexMoveBatchResult (updated_files = 1 )])
331- delete_store = RecordingDeleteBatchStore (
372+ async def test_store_project_index_maintenance_runner_delegates_to_batch_stores (
373+ monkeypatch : pytest .MonkeyPatch ,
374+ ) -> None :
375+ recorded_move_batches : list [ProjectIndexMoveBatch ] = []
376+ recorded_delete_batches : list [ProjectIndexDeleteBatch ] = []
377+ move_store = _stub_move_store (
378+ monkeypatch ,
379+ results = [ProjectIndexMoveBatchResult (updated_files = 1 )],
380+ recorded = recorded_move_batches ,
381+ )
382+ delete_store = _stub_delete_store (
383+ monkeypatch ,
332384 results = [
333385 ProjectIndexDeleteBatchResult (
334386 deleted_entities = 1 ,
335387 relation_cleanup_entity_ids = frozenset ({99 }),
336388 )
337- ]
389+ ],
390+ recorded = recorded_delete_batches ,
338391 )
339392 runner = StoreProjectIndexMaintenanceRunner (
340393 move_store = move_store ,
@@ -351,15 +404,15 @@ async def test_store_project_index_maintenance_runner_delegates_to_batch_stores(
351404 )
352405
353406 assert move_run .total_updated_files == 1
354- assert move_store . batches == [
407+ assert recorded_move_batches == [
355408 ProjectIndexMoveBatch (
356409 completed_batches = 1 ,
357410 targets = (ProjectIndexMoveTarget ("notes/a.md" , "archive/a.md" ),),
358411 )
359412 ]
360413 assert delete_run .total_deleted_entities == 1
361414 assert delete_run .relation_cleanup_entity_ids == frozenset ({99 })
362- assert delete_store . batches == [
415+ assert recorded_delete_batches == [
363416 ProjectIndexDeleteBatch (
364417 completed_batches = 1 ,
365418 paths = ("notes/deleted.md" ,),
0 commit comments