185 lines
6.7 KiB
Python
185 lines
6.7 KiB
Python
from types import SimpleNamespace
|
|
from unittest.mock import AsyncMock, MagicMock, patch
|
|
|
|
import pytest
|
|
|
|
from sync_state_machine.common.binding import BindingManager
|
|
from sync_state_machine.common.collection import DataCollection
|
|
from sync_state_machine.common.types import SyncAction
|
|
from sync_state_machine.domain.project.sync_node import ProjectSyncNode
|
|
from sync_state_machine.domain.project.sync_strategy import ProjectSyncStrategy
|
|
from sync_state_machine.sync_system.config import UpdateDirection
|
|
|
|
|
|
def _fake_node(*, node_id: str, data_id: str, data: dict, context=None):
|
|
return SimpleNamespace(
|
|
node_id=node_id,
|
|
data_id=data_id,
|
|
data=data,
|
|
context=context or {},
|
|
action=None,
|
|
get_data=lambda: data,
|
|
)
|
|
|
|
|
|
def test_project_get_node_update_payload_enriches_group_plan_dates_from_all_info():
|
|
strategy = ProjectSyncStrategy("project", MagicMock(), MagicMock(), MagicMock())
|
|
node = _fake_node(
|
|
node_id="node-1",
|
|
data_id="project-1",
|
|
data={"id": "project-1", "project_name": "demo"},
|
|
context={
|
|
"all_info": {
|
|
"wind_extension": {
|
|
"ic_plan_first_production_date": "2026-01-01",
|
|
"ic_plan_full_production_date": "2026-06-01",
|
|
}
|
|
}
|
|
},
|
|
)
|
|
|
|
payload = strategy.get_node_update_payload(node)
|
|
|
|
assert payload["ic_plan_first_production_date"] == "2026-01-01"
|
|
assert payload["ic_plan_full_production_date"] == "2026-06-01"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_project_update_pair_runs_special_pull_then_generic_update():
|
|
strategy = ProjectSyncStrategy("project", MagicMock(), MagicMock(), MagicMock())
|
|
strategy.config.domain_option = {"pull_group_plan_production_date": True}
|
|
|
|
local_node = _fake_node(node_id="local", data_id="local-1", data={"id": "local-1"})
|
|
remote_node = _fake_node(node_id="remote", data_id="remote-1", data={"id": "remote-1"})
|
|
pull_node = SimpleNamespace(node_id="pull-node")
|
|
push_node = SimpleNamespace(node_id="push-node")
|
|
|
|
with patch.object(
|
|
strategy,
|
|
"prepare_update_for_direction",
|
|
new=AsyncMock(side_effect=[pull_node, push_node]),
|
|
) as mock_prepare:
|
|
updated_nodes = await strategy.update_pair(local_node, remote_node, {"project": "remote-project"})
|
|
|
|
assert updated_nodes == [pull_node, push_node]
|
|
|
|
pull_call = mock_prepare.await_args_list[0]
|
|
assert pull_call.args == (local_node, remote_node, UpdateDirection.PULL, {"project": "remote-project"})
|
|
assert pull_call.kwargs["include_fields"] == strategy._PULL_ONLY_FIELDS
|
|
|
|
generic_call = mock_prepare.await_args_list[1]
|
|
assert generic_call.args[1:] == (remote_node, UpdateDirection.PUSH, {"project": "remote-project"})
|
|
assert generic_call.args[0] is not local_node
|
|
assert generic_call.kwargs["exclude_fields"] == strategy._PULL_ONLY_FIELDS
|
|
|
|
|
|
def _project_payload(
|
|
*,
|
|
project_id: str,
|
|
company_id: str,
|
|
company_name: str,
|
|
name: str,
|
|
plan_first: str | None,
|
|
plan_full: str | None,
|
|
):
|
|
return {
|
|
"id": project_id,
|
|
"project_type": "photovoltaic",
|
|
"region_name": ["中国", "云南省"],
|
|
"region_path": ["100000", "530000"],
|
|
"province": "530000",
|
|
"is_domestic": True,
|
|
"company_id": company_id,
|
|
"company_name": company_name,
|
|
"syxs": None,
|
|
"sub_type": None,
|
|
"scgc_type": "self",
|
|
"address": "测试地址",
|
|
"code": "",
|
|
"name": name,
|
|
"short_name": "",
|
|
"manager_name": "测试负责人",
|
|
"manager_phone": "13800000000",
|
|
"authorization_date": "2024-01-01",
|
|
"authorized_capacity": 7.0,
|
|
"investment_decision_capacity": 7.0,
|
|
"investment_decision_date": "2024-01-02",
|
|
"plan_construction_capacity": 7.0,
|
|
"plan_construction_date": "2024-01-03",
|
|
"actual_construction_capacity": 0.0,
|
|
"actual_construction_date": None,
|
|
"accumulated_construction_capacity": 0.0,
|
|
"constructing_capacity": 0.0,
|
|
"ensure_production_capacity": 2.0,
|
|
"challenge_production_capacity": 2.0,
|
|
"climb_production_capacity": 2.0,
|
|
"plan_production_date": None,
|
|
"plan_full_production_date": None,
|
|
"actual_production_date": None,
|
|
"actual_full_production_date": None,
|
|
"production_capacity": 0.0,
|
|
"production_date": None,
|
|
"total_production_capacity": 0.0,
|
|
"dynamic_investment": 0.0,
|
|
"complete_investment": 0.0,
|
|
"progress_type": None,
|
|
"key_constraints": "NONE",
|
|
"key_constraints_remark": "",
|
|
"apply_file_ids": [],
|
|
"dbtc_score_list": [],
|
|
"ic_plan_first_production_date": plan_first,
|
|
"ic_plan_full_production_date": plan_full,
|
|
}
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_project_update_pair_can_prepare_pull_and_push_on_same_pair():
|
|
local_collection = DataCollection("local")
|
|
remote_collection = DataCollection("remote")
|
|
binding_manager = BindingManager(None)
|
|
|
|
local_node = ProjectSyncNode(
|
|
node_id="local-project-node",
|
|
data_id="local-project-id",
|
|
data=_project_payload(
|
|
project_id="local-project-id",
|
|
company_id="local-company-id",
|
|
company_name="云南公司",
|
|
name="本地项目",
|
|
plan_first=None,
|
|
plan_full=None,
|
|
),
|
|
)
|
|
remote_node = ProjectSyncNode(
|
|
node_id="remote-project-node",
|
|
data_id="remote-project-id",
|
|
data=_project_payload(
|
|
project_id="remote-project-id",
|
|
company_id="remote-company-id",
|
|
company_name="清洁能源",
|
|
name="远端项目",
|
|
plan_first="2026-01-01",
|
|
plan_full="2026-06-01",
|
|
),
|
|
)
|
|
|
|
await local_collection.add(local_node)
|
|
await remote_collection.add(remote_node)
|
|
await binding_manager.bind("project", local_node.node_id, remote_node.node_id)
|
|
|
|
strategy = ProjectSyncStrategy("project", local_collection, remote_collection, binding_manager)
|
|
strategy.config.update_direction = UpdateDirection.PUSH
|
|
strategy.config.domain_option = {"pull_group_plan_production_date": True}
|
|
strategy.config.depend_fields = {}
|
|
|
|
await strategy.bind()
|
|
|
|
updated_nodes = await strategy.update_pair(local_node, remote_node, data_id_map={})
|
|
|
|
assert [node.node_id for node in updated_nodes] == [local_node.node_id, remote_node.node_id]
|
|
assert local_node.action == SyncAction.UPDATE
|
|
assert remote_node.action == SyncAction.UPDATE
|
|
assert local_node.get_data()["ic_plan_first_production_date"] == "2026-01-01"
|
|
assert local_node.get_data()["ic_plan_full_production_date"] == "2026-06-01"
|
|
assert remote_node.get_data()["name"] == "本地项目"
|
|
assert remote_node.get_data()["company_name"] == "云南公司" |