Files
stroblme 243d39b591 Give connectors a store that survives restarts, and a way to clear it
`ConnectorNode.store` keeps short strings per connector package in the
engine's database (`connector_state`, migration f8c3e5a91d27), so the nodes of
one package share them and `fluksio serve` needs nothing new: get, set and
delete, at most 64 kB a value and 256 keys a package. A superuser lists the
keys (never the values) and clears them through `/connectors/{node_type}/state`,
or under Stored state in a connector node's panel. Documented in the connector
contract.
2026-10-06 17:19:48 +02:00

75 lines
2.4 KiB
Python

"""Resetting what a connector keeps: a superuser's, named by node type."""
import pytest
from fastapi.testclient import TestClient
from fluksio.core.config import settings
from fluksio.flow.connector import CONTRACT_VERSION, ConnectorNode
from fluksio.flow.controller import NODE_TYPES, NodeType
URL = f"{settings.API_V1_STR}/connectors"
class Bridge(ConnectorNode):
contract = CONTRACT_VERSION
@pytest.fixture
def bridge(monkeypatch):
monkeypatch.setitem(NODE_TYPES, "test_bridge", NodeType("Bridge", "", Bridge))
store = Bridge(name="b").store
store.set("cert:10.0.0.2", "PEM")
store.set("cert:10.0.0.3", "PEM")
yield store
store.clear()
def test_a_superuser_lists_and_clears_the_keys(
client: TestClient, superuser_token_headers: dict[str, str], bridge
) -> None:
listed = client.get(f"{URL}/test_bridge/state", headers=superuser_token_headers)
assert listed.status_code == 200
body = listed.json()
assert body["connector"] == "tests"
assert [row["key"] for row in body["data"]] == ["cert:10.0.0.2", "cert:10.0.0.3"]
assert "value" not in body["data"][0]
one = client.delete(
f"{URL}/test_bridge/state/cert:10.0.0.2", headers=superuser_token_headers
)
assert one.status_code == 200
assert bridge.get("cert:10.0.0.2") is None
rest = client.delete(f"{URL}/test_bridge/state", headers=superuser_token_headers)
assert rest.status_code == 200
assert bridge.entries() == []
def test_anyone_else_is_refused(
client: TestClient, normal_user_token_headers: dict[str, str], bridge
) -> None:
for method in ("GET", "DELETE"):
response = client.request(
method, f"{URL}/test_bridge/state", headers=normal_user_token_headers
)
assert response.status_code == 403
assert bridge.get("cert:10.0.0.2") == "PEM"
@pytest.mark.parametrize("path", ["python/state", "nothing/state", "..%2F../state"])
def test_only_a_connector_has_state(
client: TestClient, superuser_token_headers: dict[str, str], path: str
) -> None:
response = client.get(f"{URL}/{path}", headers=superuser_token_headers)
assert response.status_code == 404
@pytest.mark.usefixtures("bridge")
def test_a_key_that_is_not_there_is_a_404(
client: TestClient, superuser_token_headers: dict[str, str]
) -> None:
response = client.delete(
f"{URL}/test_bridge/state/cert:nowhere", headers=superuser_token_headers
)
assert response.status_code == 404