整理update逻辑
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
from sync_state_machine.datasource.task_result import TaskStatus
|
||||
from sync_state_machine.domain.contract.api_handler import ContractApiHandler
|
||||
from sync_state_machine.domain.contract.sync_node import ContractSyncNode
|
||||
|
||||
|
||||
class _MockApiClient:
|
||||
def __init__(self) -> None:
|
||||
self.requests: list[dict[str, Any]] = []
|
||||
|
||||
async def request(self, method: str, endpoint: str, **kwargs: Any) -> dict[str, Any]:
|
||||
self.requests.append({"method": method, "endpoint": endpoint, **kwargs})
|
||||
return {"code": 200, "message": "OK", "data": {"biz_id": "contract-created-1"}}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_contract_create_passes_name_and_qt_code_to_api() -> None:
|
||||
handler = ContractApiHandler()
|
||||
handler.api_client = _MockApiClient()
|
||||
handler.set_poll_mode("sync")
|
||||
|
||||
node = ContractSyncNode(
|
||||
node_id="contract-node-1",
|
||||
data={
|
||||
"id": "contract-local-1",
|
||||
"project_id": "project-1",
|
||||
"name": "电缆采购合同",
|
||||
"short_name": "电缆采购合同",
|
||||
"code": "QT",
|
||||
"contract_type": "product",
|
||||
"currency": "CNY",
|
||||
"manager_name": "张三",
|
||||
"manager_phone": "13800000000",
|
||||
"sign_company": "测试供应商",
|
||||
"company_id": "company-1",
|
||||
"sign_date": "2026-03-01",
|
||||
"credit_code": "91350000123456789X",
|
||||
"total_price": 1200.5,
|
||||
"sub_name": None,
|
||||
},
|
||||
context={"project_id": "project-1"},
|
||||
)
|
||||
|
||||
results = await handler.create_all([node])
|
||||
|
||||
assert len(results) == 1
|
||||
assert results[0].status == TaskStatus.SUCCESS
|
||||
assert results[0].data_id == "contract-created-1"
|
||||
|
||||
request = handler.api_client.requests[0]
|
||||
assert request["endpoint"] == "/contract/create"
|
||||
assert request["data"]["data"]["name"] == "电缆采购合同"
|
||||
assert request["data"]["data"]["code"] == "QT"
|
||||
assert request["data"]["data"]["project_id"] == "project-1"
|
||||
@@ -0,0 +1,57 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from sync_state_machine.common.collection import DataCollection
|
||||
from sync_state_machine.domain.project.api_handler import ProjectApiHandler
|
||||
|
||||
|
||||
class _FakeProjectResponse:
|
||||
def __init__(self, project_id: str):
|
||||
self.id = project_id
|
||||
|
||||
def model_dump(self) -> dict[str, str]:
|
||||
return {"id": self.id, "name": f"project-{self.id}"}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_project_handler_purge_project_data_requires_data_id_filter() -> None:
|
||||
handler = ProjectApiHandler()
|
||||
handler.set_handler_config({"purge_project_data": True})
|
||||
|
||||
with pytest.raises(ValueError, match="requires non-empty data_id_filter"):
|
||||
await handler.load()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_project_handler_purge_project_data_calls_remote_endpoint(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
handler = ProjectApiHandler()
|
||||
handler.set_handler_config(
|
||||
{
|
||||
"purge_project_data": True,
|
||||
"data_id_filter": ["project-1"],
|
||||
}
|
||||
)
|
||||
handler.api_client = object()
|
||||
handler.set_collection(DataCollection("remote"))
|
||||
|
||||
purged: list[str] = []
|
||||
|
||||
async def fake_purge(client, project_id: str):
|
||||
purged.append(project_id)
|
||||
return {"project_id": project_id}
|
||||
|
||||
async def fake_get_project(client, project_id: str):
|
||||
return _FakeProjectResponse(project_id)
|
||||
|
||||
async def fake_get_all_info(cls, client, project_id: str):
|
||||
return {}
|
||||
|
||||
monkeypatch.setattr("sync_state_machine.domain.project.api_handler.api_purge_project_data", fake_purge)
|
||||
monkeypatch.setattr("sync_state_machine.domain.project.api_handler.api_get_project", fake_get_project)
|
||||
monkeypatch.setattr(ProjectApiHandler, "get_all_info", classmethod(fake_get_all_info))
|
||||
|
||||
nodes = await handler.load()
|
||||
|
||||
assert purged == ["project-1"]
|
||||
assert [node.data_id for node in nodes] == ["project-1"]
|
||||
@@ -4,6 +4,8 @@ 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
|
||||
from sync_state_machine.domain.project_detail.sync_strategy import ProjectDetailSyncStrategy
|
||||
from schemas.project_extensions.project_detail import ProjectDetailKey
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_run_update_with_direction_overrides():
|
||||
@@ -107,3 +109,45 @@ def test_default_strategy_exposes_normalize_compare_payload():
|
||||
}
|
||||
|
||||
assert strategy.normalize_compare_payload(local_payload) == strategy.normalize_compare_payload(remote_payload)
|
||||
|
||||
|
||||
def test_project_detail_compare_payload_ignores_response_only_year_and_is_audit_noise():
|
||||
strategy = ProjectDetailSyncStrategy(
|
||||
"project_detail_data",
|
||||
MagicMock(),
|
||||
MagicMock(),
|
||||
MagicMock(),
|
||||
)
|
||||
|
||||
local_payload = {
|
||||
"project_id": "project-1",
|
||||
"key": "actual_construction",
|
||||
"value": [{"date": "2023-08-23", "capacity": 4.0, "is_audit": False, "year": None}],
|
||||
}
|
||||
remote_payload = {
|
||||
"project_id": "project-1",
|
||||
"key": "actual_construction",
|
||||
"value": [{"date": "2023-08-23", "capacity": 4.0, "is_audit": True, "year": 2023}],
|
||||
}
|
||||
|
||||
assert strategy.normalize_compare_payload(local_payload) == strategy.normalize_compare_payload(remote_payload)
|
||||
|
||||
|
||||
def test_project_detail_compare_payload_normalizes_enum_key_values():
|
||||
strategy = ProjectDetailSyncStrategy(
|
||||
"project_detail_data",
|
||||
MagicMock(),
|
||||
MagicMock(),
|
||||
MagicMock(),
|
||||
)
|
||||
|
||||
remote_payload = {
|
||||
"project_id": "project-1",
|
||||
"key": ProjectDetailKey.PLAN_CONSTRUCTION,
|
||||
"value": [{"date": "2023-06-28", "capacity": 4.0, "year": 2023, "is_audit": True}],
|
||||
}
|
||||
|
||||
normalized = strategy.normalize_compare_payload(remote_payload)
|
||||
|
||||
assert normalized["key"] == "plan_construction"
|
||||
assert normalized["value"] == [{"date": "2023-06-28", "capacity": 4.0}]
|
||||
|
||||
Reference in New Issue
Block a user