"""Nodes shared across flows: one source, many instances.""" from pathlib import Path import pytest from app.flow.messages import MessageSpec from app.flow.schemas import FlowDef, NodeDef from app.flow.store import FlowStore, LibExists, LibNotFound SOURCE = "def process():\n return {'temp': 1}\n" @pytest.fixture def store(tmp_path: Path) -> FlowStore: return FlowStore(tmp_path / "flows") def a_flow(name: str = "heating") -> FlowDef: return FlowDef( name=name, nodes=[NodeDef(id="sensor", provides=[MessageSpec(name="temp")])], ) def test_sharing_moves_the_source_and_points_the_node_at_it(store: FlowStore): store.write_flow(a_flow()) store.write_node_source("heating", "sensor", SOURCE) store.share_node("heating", "sensor", "read_temp") assert store.list_lib() == ["read_temp"] assert store.read_lib_source("read_temp") == SOURCE node = store.read_flow("heating", draft=True).nodes[0] assert node.source_ref == "read_temp" # The private copy is gone; the library one is what it runs. assert not (store.root / "heating" / "nodes" / "sensor.py").exists() def test_the_library_is_not_mistaken_for_a_flow(store: FlowStore): store.write_flow(a_flow()) store.write_node_source("heating", "sensor", SOURCE) store.share_node("heating", "sensor", "read_temp") assert store.list_flows() == ["heating"] assert [flow.name for flow in store.read_all()] == ["heating"] def test_a_second_flow_can_use_the_same_source(store: FlowStore): store.write_flow(a_flow()) store.write_node_source("heating", "sensor", SOURCE) store.share_node("heating", "sensor", "read_temp") store.write_flow( FlowDef( name="cooling", nodes=[ NodeDef( id="sensor", source_ref="read_temp", provides=[MessageSpec(name="temp")], ) ], ) ) assert store.usages("read_temp") == ["cooling.sensor", "heating.sensor"] def test_a_shared_name_is_not_taken_twice(store: FlowStore): store.write_flow(a_flow()) store.write_node_source("heating", "sensor", SOURCE) store.share_node("heating", "sensor", "read_temp") store.write_flow(FlowDef(name="cooling", nodes=[NodeDef(id="sensor")])) with pytest.raises(LibExists): store.share_node("cooling", "sensor", "read_temp") def test_unsharing_takes_a_private_copy_back(store: FlowStore): store.write_flow(a_flow()) store.write_node_source("heating", "sensor", SOURCE) store.share_node("heating", "sensor", "read_temp") store.unshare_node("heating", "sensor") node = store.read_flow("heating", draft=True).nodes[0] assert node.source_ref is None assert store.read_node_source("heating", "sensor", draft=True) == SOURCE # The library keeps its copy for whoever else is using it. assert store.list_lib() == ["read_temp"] def test_a_missing_shared_source_is_reported(store: FlowStore): with pytest.raises(LibNotFound): store.read_lib_source("nothing_here")