from __future__ import annotations from pathlib import Path import pytest from pydantic import BaseModel from sync_state_machine.common.registry import DomainRegistry from sync_state_machine.common.sync_node import SyncNode from sync_state_machine.config import ( BaseDataSourceConfig, LoggingConfig, PersistConfig, PipelineRunConfig, register_datasource_type, ) from sync_state_machine.datasource import BaseDataSource from sync_state_machine.datasource.handler import BaseNodeHandler from sync_state_machine.pipeline.factory import create_pipeline_from_config from sync_state_machine.sync_system.strategy import DefaultSyncStrategy class EndpointInitConfig(BaseDataSourceConfig): __test__ = False type: str = "endpoint_init_memory" class EndpointInitSchema(BaseModel): __test__ = False id: str name: str | None = None class EndpointInitNode(SyncNode[EndpointInitSchema]): __test__ = False node_type = "factory_endpoint_demo" schema = EndpointInitSchema class EndpointInitStrategy(DefaultSyncStrategy[EndpointInitSchema]): __test__ = False schema = EndpointInitSchema class EndpointInitHandler(BaseNodeHandler[EndpointInitSchema]): __test__ = False def __init__(self, datasource: BaseDataSource): super().__init__("factory_endpoint_demo", EndpointInitNode, EndpointInitSchema) self.datasource = datasource def extract_id(self, data: dict[str, str]) -> str: return str(data.get("id", "")) async def load(self): return [] async def create_all(self, nodes): return [] async def update_all(self, nodes): return [] def _ensure_registered() -> None: node_type = "factory_endpoint_demo" if DomainRegistry.is_registered(node_type): reg = DomainRegistry.get_registration(node_type) reg.schema = EndpointInitSchema reg.node_class = EndpointInitNode reg.strategy_class = EndpointInitStrategy reg.handler_classes["endpoint_init_memory"] = EndpointInitHandler return DomainRegistry.register( node_type=node_type, schema=EndpointInitSchema, node_class=EndpointInitNode, strategy_class=EndpointInitStrategy, ) DomainRegistry.register_handler(node_type, "endpoint_init_memory", EndpointInitHandler) def _register_endpoint_init_datasource_type() -> None: register_datasource_type( "endpoint_init_memory", config_model=EndpointInitConfig, factory=lambda config, endpoint_name: BaseDataSource(), replace=True, ) @pytest.mark.asyncio async def test_factory_initializes_same_datasource_type_with_distinct_handler_configs( tmp_path: Path, monkeypatch: pytest.MonkeyPatch, ) -> None: _ensure_registered() _register_endpoint_init_datasource_type() config = PipelineRunConfig( node_types=["factory_endpoint_demo"], local_datasource=EndpointInitConfig( type="endpoint_init_memory", handler_configs={"factory_endpoint_demo": {"side": "local", "batch_size": 10}}, ), remote_datasource=EndpointInitConfig( type="endpoint_init_memory", handler_configs={"factory_endpoint_demo": {"side": "remote", "batch_size": 20}}, ), strategies=[], persist=PersistConfig(db_path=str(tmp_path / "factory-init.db")), logging=LoggingConfig(initialize=False), ) pipeline = await create_pipeline_from_config(config) try: local_handler = pipeline.local_datasource.get_handler("factory_endpoint_demo") remote_handler = pipeline.remote_datasource.get_handler("factory_endpoint_demo") assert isinstance(local_handler, EndpointInitHandler) assert isinstance(remote_handler, EndpointInitHandler) assert local_handler.handler_config == {"side": "local", "batch_size": 10} assert remote_handler.handler_config == {"side": "remote", "batch_size": 20} finally: await pipeline.close()