from __future__ import annotations from pathlib import Path import pytest from sync_state_machine.common.types import BindingStatus, SyncAction, SyncStatus from sync_state_machine.engine import StateMachineConfig, StateMachineRuntime from sync_state_machine.engine.events import e20_create_prepare, e40_sync_execute from sync_state_machine.engine.state_apply import apply_state_to_node from tests.mocks.mock_datasource import MockSyncNode CFG_PATH = Path(__file__).resolve().parents[2] / "sync_state_machine" / "config" / "node_state_machine.yaml" def _new_node(node_id: str, *, data_id: str = "seed-id") -> MockSyncNode: return MockSyncNode( node_id=node_id, data_id=data_id, data={"id": node_id, "name": "mock"}, action=SyncAction.NONE, status=SyncStatus.PENDING, binding_status=BindingStatus.UNCHECKED, ) def _set_core_state(runtime: StateMachineRuntime, node: MockSyncNode, state_id: str, *, data_id: str) -> None: apply_state_to_node( runtime, node, state_id=state_id, reason="test setup", fields={"binding_status", "action", "status"}, ) apply_state_to_node( runtime, node, state_id=state_id, reason="test setup", fields={"data_id"}, data_id=data_id, ) def test_create_success_requires_non_empty_result_data_id() -> None: runtime = StateMachineRuntime(StateMachineConfig.load(CFG_PATH)) node = _new_node("create-missing-result-id", data_id="") _set_core_state(runtime, node, "S06", data_id="") with pytest.raises(RuntimeError, match="requires non-empty result_data_id"): e40_sync_execute( runtime, node=node, handler_result="SUCCESS", action="CREATE", poll_timeout=False, result_data_id=None, ) def test_e20_requires_s13_data_id_present() -> None: runtime = StateMachineRuntime(StateMachineConfig.load(CFG_PATH)) node = _new_node("s13-no-data-id", data_id="") _set_core_state(runtime, node, "S13", data_id="") with pytest.raises(RuntimeError, match="cannot resolve current state"): e20_create_prepare(runtime, node=node, spawn_success=True)