diff --git a/backend/fluksio/api/routes/flows.py b/backend/fluksio/api/routes/flows.py index bc352af..756233b 100644 --- a/backend/fluksio/api/routes/flows.py +++ b/backend/fluksio/api/routes/flows.py @@ -353,7 +353,10 @@ async def delete_shared_node( for flow in sorted({usage.split(".", 1)[0] for usage in running}): await controller.reload_flow(flow) return Message(message=f"Deleted shared node '{lib_name}'") - used_by = controller.store.usages(lib_name) + # The published flows too: a draft that unshared a node still runs it. + used_by = sorted( + {*controller.store.usages(lib_name), *controller.store.usages(lib_name, False)} + ) if used_by: raise HTTPException( status_code=409, diff --git a/backend/tests/api/routes/test_flows.py b/backend/tests/api/routes/test_flows.py index d28ada2..b2cb0d7 100644 --- a/backend/tests/api/routes/test_flows.py +++ b/backend/tests/api/routes/test_flows.py @@ -583,6 +583,36 @@ def test_a_shared_node_in_use_is_retired_only_with_detach( client.delete(f"{PREFIX}/shared", headers=superuser_token_headers) +def test_a_shared_node_only_the_published_flow_uses_is_kept( + client: TestClient, superuser_token_headers: dict[str, str] +) -> None: + """An unshare in the draft leaves the running flow on the source.""" + client.put( + f"{PREFIX}/unshared", headers=superuser_token_headers, json=a_flow("unshared") + ) + shared = client.post( + f"{PREFIX}/unshared/nodes/sensor/share", + headers=superuser_token_headers, + json={"lib_name": "published_reading"}, + ).json() + client.post( + f"{PREFIX}/unshared/publish", + headers=superuser_token_headers, + json={"version": shared["definition"]["version"]}, + ) + client.post( + f"{PREFIX}/unshared/nodes/sensor/unshare", headers=superuser_token_headers + ) + + url = f"{PREFIX}/library/published_reading" + response = client.delete(url, headers=superuser_token_headers) + assert response.status_code == 409 + assert "unshared.sensor" in response.json()["detail"] + + client.delete(f"{url}?detach=true", headers=superuser_token_headers) + client.delete(f"{PREFIX}/unshared", headers=superuser_token_headers) + + def test_a_shared_source_write_is_audited( client: TestClient, superuser_token_headers: dict[str, str],