44
55import importlib
66from contextlib import contextmanager
7+ from pathlib import Path
8+ from textwrap import dedent
79from types import SimpleNamespace
10+ from unittest .mock import AsyncMock
811
912import pytest
1013
1114from basic_memory .sync .sync_service import SyncReport
1215
16+ batch_indexer_module = importlib .import_module ("basic_memory.indexing.batch_indexer" )
1317sync_service_module = importlib .import_module ("basic_memory.sync.sync_service" )
1418
1519
@@ -30,6 +34,14 @@ def fake_span(name: str, **attrs):
3034 return operations , spans , fake_operation , fake_span
3135
3236
37+ def _write_markdown (project_root : Path , relative_path : str , content : str ) -> Path :
38+ """Create one markdown file under the test project."""
39+ file_path = project_root / relative_path
40+ file_path .parent .mkdir (parents = True , exist_ok = True )
41+ file_path .write_text (content , encoding = "utf-8" )
42+ return file_path
43+
44+
3345@pytest .mark .asyncio
3446async def test_sync_emits_phase_spans (sync_service , project_config , monkeypatch ) -> None :
3547 operations , spans , fake_operation , fake_span = _capture_sync_telemetry ()
@@ -97,6 +109,47 @@ async def fake_update(project_id, values):
97109 ]
98110
99111
112+ @pytest .mark .asyncio
113+ async def test_sync_one_markdown_file_emits_index_phase_spans (
114+ sync_service , test_project , monkeypatch
115+ ) -> None :
116+ _ , spans , _ , fake_span = _capture_sync_telemetry ()
117+ monkeypatch .setattr (batch_indexer_module .telemetry , "span" , fake_span )
118+ monkeypatch .setattr (sync_service .search_service , "index_entity_data" , AsyncMock ())
119+
120+ _write_markdown (
121+ Path (test_project .path ),
122+ "notes/telemetry.md" ,
123+ dedent (
124+ f"""\
125+ ---
126+ title: Telemetry Note
127+ type: note
128+ permalink: { test_project .name } /notes/telemetry
129+ ---
130+
131+ # Telemetry Note
132+
133+ Body content.
134+ """
135+ ),
136+ )
137+
138+ result = await sync_service .sync_one_markdown_file ("notes/telemetry.md" )
139+
140+ index_spans = [(name , attrs ) for name , attrs in spans if name .startswith ("index.markdown_file" )]
141+ assert [name for name , _ in index_spans ] == [
142+ "index.markdown_file.prepare" ,
143+ "index.markdown_file.load_permalink_map" ,
144+ "index.markdown_file.normalize" ,
145+ "index.markdown_file.persist" ,
146+ "index.markdown_file.reload_entity" ,
147+ ]
148+ assert index_spans [0 ][1 ] == {"path" : "notes/telemetry.md" }
149+ assert index_spans [3 ][1 ] == {"path" : "notes/telemetry.md" , "is_new" : True }
150+ assert index_spans [4 ][1 ]["entity_id" ] == result .entity .id
151+
152+
100153@pytest .mark .asyncio
101154async def test_sync_file_emits_failure_span (sync_service , monkeypatch ) -> None :
102155 _ , spans , _ , fake_span = _capture_sync_telemetry ()
0 commit comments