from types import SimpleNamespace from unittest.mock import AsyncMock, MagicMock, patch import pytest 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 == (local_node, remote_node, UpdateDirection.PUSH, {"project": "remote-project"}) assert generic_call.kwargs["exclude_fields"] == strategy._PULL_ONLY_FIELDS