优化性能
This commit is contained in:
@@ -263,7 +263,7 @@ async def test_create_all_marks_duplicate_project_key_in_same_batch_as_error() -
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_node_raises_on_existing_project_key_with_different_data_id() -> None:
|
||||
async def test_create_node_allows_existing_project_key_with_different_data_id() -> None:
|
||||
collection = DataCollection("remote")
|
||||
|
||||
handler = ProjectDetailApiHandler()
|
||||
@@ -278,15 +278,18 @@ async def test_create_node_raises_on_existing_project_key_with_different_data_id
|
||||
)
|
||||
await collection.add(existing)
|
||||
|
||||
with pytest.raises(RuntimeError, match="project_detail_data load conflict"):
|
||||
handler._create_node(
|
||||
{
|
||||
"id": "remote-detail-99",
|
||||
"project_id": "project-1",
|
||||
"key": "plan_construction",
|
||||
"value": [{"date": "2026-01-01", "capacity": 21.0}],
|
||||
}
|
||||
)
|
||||
node = handler._create_node(
|
||||
{
|
||||
"id": "remote-detail-99",
|
||||
"project_id": "project-1",
|
||||
"key": "plan_construction",
|
||||
"value": [{"date": "2026-01-01", "capacity": 21.0}],
|
||||
}
|
||||
)
|
||||
|
||||
assert node.node_id != existing.node_id
|
||||
assert node.data_id == "remote-detail-99"
|
||||
assert node.context["project_id"] == "project-1"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
||||
@@ -9,7 +9,7 @@ from sync_state_machine.common.binding import BindingManager
|
||||
from sync_state_machine.common.collection import DataCollection
|
||||
from sync_state_machine.datasource.jsonl import JsonlDataSource
|
||||
import sync_state_machine.pipeline.full_sync_pipeline as full_sync_pipeline_module
|
||||
from sync_state_machine.pipeline.full_sync_pipeline import FullSyncPipeline
|
||||
from sync_state_machine.pipeline.full_sync_pipeline import FullSyncPipeline, WriteOutcome
|
||||
|
||||
|
||||
class _FakeDataSource:
|
||||
@@ -81,22 +81,33 @@ async def test_phase_sync_loads_each_node_type_before_strategy(monkeypatch: pyte
|
||||
|
||||
reload_calls: list[tuple[str, str]] = []
|
||||
|
||||
async def fake_commit_creates(node_type: str) -> bool:
|
||||
return node_type == "project"
|
||||
async def fake_commit_creates(node_type: str) -> WriteOutcome:
|
||||
return WriteOutcome(local_written=(node_type == "project"), remote_written=False)
|
||||
|
||||
async def fake_commit_updates(node_type: str) -> bool:
|
||||
async def fake_commit_updates(node_type: str) -> WriteOutcome:
|
||||
del node_type
|
||||
return False
|
||||
return WriteOutcome()
|
||||
|
||||
async def fake_load_node_type(node_type: str, *, reason: str) -> None:
|
||||
reload_calls.append((node_type, reason))
|
||||
|
||||
async def fake_reload_after_write(
|
||||
node_type: str,
|
||||
*,
|
||||
reason: str,
|
||||
reload_local: bool,
|
||||
reload_remote: bool,
|
||||
) -> None:
|
||||
del reload_local, reload_remote
|
||||
reload_calls.append((node_type, reason))
|
||||
|
||||
async def fake_normalize(node_type: str) -> None:
|
||||
del node_type
|
||||
|
||||
monkeypatch.setattr(pipeline, "commit_creates", fake_commit_creates)
|
||||
monkeypatch.setattr(pipeline, "commit_updates", fake_commit_updates)
|
||||
monkeypatch.setattr(pipeline, "_load_node_type", fake_load_node_type)
|
||||
monkeypatch.setattr(pipeline, "_reload_node_type_after_write", fake_reload_after_write)
|
||||
monkeypatch.setattr(pipeline, "normalize_create_success_to_update_entry", fake_normalize)
|
||||
|
||||
await pipeline.phase_sync_by_node_type()
|
||||
@@ -132,12 +143,12 @@ async def test_phase_sync_skips_reload_for_jsonl_datasources(
|
||||
|
||||
reload_calls: list[tuple[str, str]] = []
|
||||
|
||||
async def fake_commit_creates(node_type: str) -> bool:
|
||||
return node_type == "project"
|
||||
async def fake_commit_creates(node_type: str) -> WriteOutcome:
|
||||
return WriteOutcome(local_written=(node_type == "project"), remote_written=False)
|
||||
|
||||
async def fake_commit_updates(node_type: str) -> bool:
|
||||
async def fake_commit_updates(node_type: str) -> WriteOutcome:
|
||||
del node_type
|
||||
return False
|
||||
return WriteOutcome()
|
||||
|
||||
async def fake_load_node_type(node_type: str, *, reason: str) -> None:
|
||||
reload_calls.append((node_type, reason))
|
||||
@@ -157,6 +168,46 @@ async def test_phase_sync_skips_reload_for_jsonl_datasources(
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_reload_after_local_only_create_skips_remote_datasource() -> None:
|
||||
class _RecordingDataSource(_FakeDataSource):
|
||||
def __init__(self, label: str):
|
||||
self.label = label
|
||||
self.load_calls: list[tuple[str | None, tuple[str, ...] | None]] = []
|
||||
|
||||
async def load_all(self, order=None, data_type=None) -> None:
|
||||
order_tuple = tuple(order) if order is not None else None
|
||||
self.load_calls.append((data_type, order_tuple))
|
||||
|
||||
local_ds = _RecordingDataSource("local")
|
||||
remote_ds = _RecordingDataSource("remote")
|
||||
project_strategy = _StubStrategy("project")
|
||||
|
||||
pipeline = FullSyncPipeline(
|
||||
local_datasource=local_ds,
|
||||
remote_datasource=remote_ds,
|
||||
strategies=[project_strategy],
|
||||
persistence=_FakePersistence(),
|
||||
local_collection=DataCollection("local"),
|
||||
remote_collection=DataCollection("remote"),
|
||||
binding_manager=BindingManager(_FakePersistence(), auto_persist=False),
|
||||
node_types=["project"],
|
||||
load_order=["project"],
|
||||
sync_order=["project"],
|
||||
enable_persistence=False,
|
||||
)
|
||||
|
||||
await pipeline._reload_node_type_after_write(
|
||||
"project",
|
||||
reason="create wrote data",
|
||||
reload_local=True,
|
||||
reload_remote=False,
|
||||
)
|
||||
|
||||
assert local_ds.load_calls == [(None, ("project",))]
|
||||
assert remote_ds.load_calls == []
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_evaluate_consistency_merges_compare_and_post_check_ignore_fields() -> None:
|
||||
project_strategy = _StubStrategy("project")
|
||||
|
||||
@@ -96,7 +96,7 @@ async def test_project_detail_create_failure_preserves_push_id_and_biz_id() -> N
|
||||
assert result.metadata["key"] == "production"
|
||||
|
||||
|
||||
def test_project_detail_load_conflict_raises_on_same_project_key_different_data_id() -> None:
|
||||
def test_project_detail_load_allows_same_project_key_with_different_data_id() -> None:
|
||||
collection = DataCollection("remote")
|
||||
|
||||
project = _ProjectNode(
|
||||
@@ -119,16 +119,20 @@ def test_project_detail_load_conflict_raises_on_same_project_key_different_data_
|
||||
)
|
||||
collection._nodes[existing_detail.node_id] = existing_detail
|
||||
collection._data_id_to_node_id[existing_detail.data_id] = existing_detail.node_id
|
||||
collection._node_id_to_data_id[existing_detail.node_id] = existing_detail.data_id
|
||||
|
||||
handler = ProjectDetailApiHandler()
|
||||
handler.set_collection(collection)
|
||||
|
||||
with pytest.raises(RuntimeError, match="project_detail_data load conflict"):
|
||||
handler._create_node(
|
||||
{
|
||||
"id": "detail-new",
|
||||
"project_id": "project-1",
|
||||
"key": "actual_construction",
|
||||
"value": [{"date": "2026-01-02", "capacity": 2.0}],
|
||||
}
|
||||
)
|
||||
node = handler._create_node(
|
||||
{
|
||||
"id": "detail-new",
|
||||
"project_id": "project-1",
|
||||
"key": "actual_construction",
|
||||
"value": [{"date": "2026-01-02", "capacity": 2.0}],
|
||||
}
|
||||
)
|
||||
|
||||
assert node.node_id != existing_detail.node_id
|
||||
assert node.data_id == "detail-new"
|
||||
assert node.context["project_id"] == "project-1"
|
||||
|
||||
Reference in New Issue
Block a user