整体同步代码
This commit is contained in:
@@ -8,6 +8,7 @@ import pytest
|
||||
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
|
||||
|
||||
|
||||
@@ -30,7 +31,12 @@ class _StubStrategy:
|
||||
def __init__(self, node_type: str):
|
||||
self.node_type = node_type
|
||||
self.skip_sync = False
|
||||
self.config = SimpleNamespace()
|
||||
self.config = SimpleNamespace(
|
||||
depend_fields={},
|
||||
update_direction=None,
|
||||
compare_ignore_fields=[],
|
||||
post_check_ignore_fields=[],
|
||||
)
|
||||
self.sm_runtime = None
|
||||
|
||||
async def bind(self):
|
||||
@@ -143,4 +149,48 @@ async def test_phase_sync_skips_reload_for_jsonl_datasources(
|
||||
|
||||
assert reload_calls == [
|
||||
("project", "pre-strategy refresh"),
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_evaluate_consistency_merges_compare_and_post_check_ignore_fields() -> None:
|
||||
project_strategy = _StubStrategy("project")
|
||||
project_strategy.config.compare_ignore_fields = ["updated_at", "code"]
|
||||
project_strategy.config.post_check_ignore_fields = ["code", "audit_status"]
|
||||
|
||||
pipeline = FullSyncPipeline(
|
||||
local_datasource=_FakeDataSource(),
|
||||
remote_datasource=_FakeDataSource(),
|
||||
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,
|
||||
)
|
||||
|
||||
captured: dict[str, object] = {}
|
||||
|
||||
async def fake_evaluate_consistency_for_node_type(**kwargs):
|
||||
captured.update(kwargs)
|
||||
return {
|
||||
"ok": True,
|
||||
"checked_pairs": 0,
|
||||
"mismatch_count": 0,
|
||||
"fields": [],
|
||||
"schema_name": "project",
|
||||
"ignore_fields": kwargs["ignore_fields"],
|
||||
}
|
||||
|
||||
original = full_sync_pipeline_module.evaluate_consistency_for_node_type
|
||||
full_sync_pipeline_module.evaluate_consistency_for_node_type = fake_evaluate_consistency_for_node_type
|
||||
try:
|
||||
result = await pipeline._evaluate_consistency_for_node_type("project")
|
||||
finally:
|
||||
full_sync_pipeline_module.evaluate_consistency_for_node_type = original
|
||||
|
||||
assert captured["ignore_fields"] == ["updated_at", "code", "audit_status"]
|
||||
assert result["ignore_fields"] == ["updated_at", "code", "audit_status"]
|
||||
@@ -0,0 +1,37 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from sync_state_machine.config.builder import _apply_strategy_overrides
|
||||
from sync_state_machine.config.strategy_config import StrategyConfig, StrategyRuntimeConfig
|
||||
|
||||
|
||||
def test_strategy_runtime_config_skip_sync_defaults_false() -> None:
|
||||
runtime_config = StrategyRuntimeConfig(node_type="project")
|
||||
|
||||
assert runtime_config.skip_sync is False
|
||||
|
||||
|
||||
def test_apply_strategy_overrides_allows_skip_sync_override() -> None:
|
||||
resolved = _apply_strategy_overrides(
|
||||
node_types=["project"],
|
||||
strategy_overrides={
|
||||
"project": {
|
||||
"skip_sync": True,
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
assert len(resolved) == 1
|
||||
assert resolved[0].node_type == "project"
|
||||
assert resolved[0].skip_sync is True
|
||||
|
||||
|
||||
def test_strategy_config_supports_both_post_check_ignore_fields() -> None:
|
||||
config = StrategyConfig.model_validate(
|
||||
{
|
||||
"post_check_ignore_fields": ["code"],
|
||||
"post_check_ignore_list_item_fields": {"plan_node": ["is_audit"]},
|
||||
}
|
||||
)
|
||||
|
||||
assert config.post_check_ignore_fields == ["code"]
|
||||
assert config.post_check_ignore_list_item_fields == {"plan_node": ["is_audit"]}
|
||||
@@ -1,5 +1,6 @@
|
||||
import pytest
|
||||
from unittest.mock import AsyncMock, patch, MagicMock
|
||||
from sync_state_machine.domain.company.sync_strategy import CompanySyncStrategy
|
||||
from sync_state_machine.sync_system.config import UpdateDirection
|
||||
from sync_state_machine.sync_system.strategy_ops.update_ops import run_update
|
||||
from sync_state_machine.domain.construction.sync_strategy import ConstructionTaskSyncStrategy
|
||||
@@ -86,3 +87,23 @@ def test_construction_task_compare_payload_ignores_plan_node_is_audit():
|
||||
}
|
||||
|
||||
assert strategy.normalize_compare_payload(local_payload) == strategy.normalize_compare_payload(remote_payload)
|
||||
|
||||
|
||||
def test_default_strategy_exposes_normalize_compare_payload():
|
||||
strategy = CompanySyncStrategy(
|
||||
"company",
|
||||
MagicMock(),
|
||||
MagicMock(),
|
||||
MagicMock(),
|
||||
)
|
||||
|
||||
local_payload = {
|
||||
"id": "remote-company-id",
|
||||
"code": "COMP-001",
|
||||
}
|
||||
remote_payload = {
|
||||
"id": "local-company-id",
|
||||
"code": "COMP-001",
|
||||
}
|
||||
|
||||
assert strategy.normalize_compare_payload(local_payload) == strategy.normalize_compare_payload(remote_payload)
|
||||
|
||||
Reference in New Issue
Block a user