Clients take a flow's id or key: one resolver in the SDK, id first, explicit id:/key:, a warning for reads and a refusal for changes when a name means two flows, deleted flows found by their last key; sync creates by POST, retries a create race through the drift checks and reports the id; MCP gets create_flow and resolves every flow argument with the caller's token; displays show flow_name; an engine from before ids is named as such
This commit is contained in:
@@ -7,6 +7,7 @@ from pathlib import Path
|
||||
import pytest
|
||||
|
||||
from fluksio.cli import load_or_create_secret_key
|
||||
from fluksio.sdk.resolve import Resolved
|
||||
|
||||
|
||||
def test_importing_the_cli_does_not_build_the_settings() -> None:
|
||||
@@ -242,6 +243,9 @@ def test_a_local_run_always_waits(monkeypatch) -> None:
|
||||
return self
|
||||
|
||||
class FakeClient:
|
||||
def resolve_flow(self, flow: str, **how: bool) -> Resolved:
|
||||
return Resolved(flow, flow)
|
||||
|
||||
def get_flow(self, name: str) -> dict[str, object]:
|
||||
return {"definition": {"inputs": []}}
|
||||
|
||||
@@ -264,7 +268,8 @@ def test_a_local_run_always_waits(monkeypatch) -> None:
|
||||
assert cli.cmd_run(args, []) == 0
|
||||
# "cli" rather than the SDK's default: the history says which asked.
|
||||
assert submitted == {
|
||||
"flow": "train",
|
||||
# Resolved once, then named by id so the submit does not ask again.
|
||||
"flow": "id:train",
|
||||
"no_cache": True,
|
||||
"waited": True,
|
||||
"cause": "cli",
|
||||
@@ -289,6 +294,9 @@ def test_ctrl_c_while_waiting_cancels_the_run(monkeypatch) -> None:
|
||||
raise KeyboardInterrupt
|
||||
|
||||
class FakeClient:
|
||||
def resolve_flow(self, flow: str, **how: bool) -> Resolved:
|
||||
return Resolved(flow, flow)
|
||||
|
||||
def get_flow(self, name: str) -> dict[str, object]:
|
||||
return {"definition": {"inputs": []}}
|
||||
|
||||
@@ -429,6 +437,9 @@ def test_a_failed_run_prints_what_each_node_said(monkeypatch, capsys) -> None:
|
||||
return self
|
||||
|
||||
class FakeClient:
|
||||
def resolve_flow(self, flow: str, **how: bool) -> Resolved:
|
||||
return Resolved(flow, flow)
|
||||
|
||||
def get_flow(self, name: str) -> dict[str, object]:
|
||||
return {"definition": {"inputs": []}}
|
||||
|
||||
@@ -699,6 +710,9 @@ def test_run_imports_the_module_that_declared_the_flow(tmp_path, monkeypatch):
|
||||
class Engine:
|
||||
origin: dict = {}
|
||||
|
||||
def resolve_flow(self, flow, **how):
|
||||
return Resolved(flow, flow)
|
||||
|
||||
def get_flow(self, name):
|
||||
return {"definition": {"origin": self.origin}}
|
||||
|
||||
@@ -1196,3 +1210,50 @@ def test_the_dashboard_subscribes_where_the_browser_does() -> None:
|
||||
assert socket_url("http://127.0.0.1:8000") == "ws://127.0.0.1:8000/api/v1/flows/ws"
|
||||
# TLS on the one side is TLS on the other.
|
||||
assert socket_url("https://engine.example.com").startswith("wss://")
|
||||
|
||||
|
||||
def test_a_flow_argument_goes_through_the_resolver(monkeypatch, capsys) -> None:
|
||||
"""A run of a name two flows answer to is refused; a listing warns."""
|
||||
from contextlib import contextmanager
|
||||
|
||||
import httpx
|
||||
|
||||
from fluksio.cli import _parser
|
||||
from fluksio.sdk import cli
|
||||
from fluksio.sdk.client import Client
|
||||
|
||||
listed = [
|
||||
{"id": "heating", "name": "warmth"},
|
||||
{"id": "f_heat0000", "name": "heating"},
|
||||
]
|
||||
asked: list[str] = []
|
||||
|
||||
def handler(request: httpx.Request) -> httpx.Response:
|
||||
if request.url.path == "/api/v1/flows/":
|
||||
return httpx.Response(200, json={"data": listed, "count": 2})
|
||||
if request.url.path == "/api/v1/runs/overview":
|
||||
return httpx.Response(200, json=[])
|
||||
asked.append(f"{request.url.path}?{request.url.query.decode()}")
|
||||
return httpx.Response(200, json=[])
|
||||
|
||||
@contextmanager
|
||||
def engine():
|
||||
http = httpx.Client(transport=httpx.MockTransport(handler), base_url="http://e")
|
||||
yield Client(http=http, token="t")
|
||||
|
||||
monkeypatch.setattr(cli, "_engine_client", engine)
|
||||
parser = _parser()
|
||||
|
||||
run = parser.parse_args(["run", "heating", "--local", "--no-sync"])
|
||||
assert cli.cmd_run(run, []) == 1
|
||||
assert "Pass id:heating or key:heating" in capsys.readouterr().err
|
||||
assert asked == []
|
||||
|
||||
assert (
|
||||
cli.cmd_runs(parser.parse_args(["runs", "--flow", "heating", "--local"])) == 0
|
||||
)
|
||||
assert (
|
||||
"fluksio: warning: 'heating' is the id of 'warmth' and the key of "
|
||||
"'f_heat0000'. Using the id. Pass key:heating for the other.\n"
|
||||
) in capsys.readouterr().err
|
||||
assert asked == ["/api/v1/runs?limit=20&flow=heating"]
|
||||
|
||||
Reference in New Issue
Block a user