Files
app/backend/tests/sdk/test_paths.py
T
stroblmeandClaude Fable 5 7e4f03369b Three fewer things to remember
**The portal link puts itself back up.** It already retried a connection that
raised, but a session that ended *cleanly* — a portal restarting, a proxy
closing an idle socket — returned normally and went straight back round the
loop with no wait at all, so an engine could spin against a portal that was
merely saying goodbye politely. Every ending now reconnects on a delay, and
the delay turns on whether the attempt got as far as attaching: one that stood
up and dropped is a network event and retries at once, one that never stood up
waits longer each time. Jittered, so a portal coming back is not met by every
installation it serves in the same instant. Ping timeouts are named rather
than defaulted, since they are what bounds how long a suspended laptop's dead
socket looks alive, and the keepalive task is awaited so the reason a link
went reaches the log instead of the garbage collector.

**`fluksio enroll <code>`** is the whole command now; hub.fluksio.com is the
default and `--portal` names another. The one command run before anything
works should not need two flags.

**`fluksio run` syncs first.** The reason a run exists is usually the edit
before it, so remembering to sync was remembering to do something the computer
could do — including the worker refresh, which is what makes an edit to your
own package take effect at all. `--no-sync` opts out for a tight loop.

That last one needed discovery fixed: it only ever looked at top-level `*.py`,
so a repository whose code is in a package — the ordinary shape — found
nothing from its own root. It now descends into the packages it holds.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012ue1tkFWB1bcGy3aWhCKpU
2026-08-24 18:17:16 +02:00

129 lines
4.2 KiB
Python

"""Which installation a command is for, and where its token lives.
A repository with its own venv gets its own engine, so "which one" is a fact
about the working directory rather than about the machine.
"""
import json
from pathlib import Path
import pytest
from fluksio.sdk import client
@pytest.fixture
def elsewhere(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> Path:
"""A working directory with no installation above it."""
monkeypatch.chdir(tmp_path)
monkeypatch.setenv("XDG_CONFIG_HOME", str(tmp_path / "xdg"))
monkeypatch.setattr(client, "GLOBAL_DATA_DIR", tmp_path / "home" / ".fluksio")
return tmp_path
def test_a_project_local_installation_is_found_from_below(elsewhere: Path):
(elsewhere / ".fluksio").mkdir()
deep = elsewhere / "src" / "pkg" / "sub"
deep.mkdir(parents=True)
assert client.find_data_dir(deep) == elsewhere / ".fluksio"
assert client.config_path(client.data_dir(deep)).parent.name == ".fluksio"
def test_the_nearest_one_wins(elsewhere: Path):
"""An installation inside another belongs to the directory it is in."""
(elsewhere / ".fluksio").mkdir()
inner = elsewhere / "inner"
(inner / ".fluksio").mkdir(parents=True)
assert client.find_data_dir(inner) == inner / ".fluksio"
def test_with_none_above_it_the_shared_one_answers(elsewhere: Path):
assert client.find_data_dir() is None
assert client.data_dir() == elsewhere / "home" / ".fluksio"
def test_a_token_is_written_only_for_its_owner(elsewhere: Path):
path = client.write_config("http://127.0.0.1:8000", "abc", elsewhere / ".fluksio")
assert json.loads(path.read_text()) == {
"url": "http://127.0.0.1:8000",
"token": "abc",
}
# It is a credential sitting in somebody's project directory.
assert path.stat().st_mode & 0o077 == 0
# And one nothing can commit by accident.
assert (path.parent / ".gitignore").read_text().endswith("*\n")
def test_the_credential_beside_the_data_is_the_one_used(elsewhere: Path):
client.write_config("http://127.0.0.1:8131", "local", elsewhere / ".fluksio")
assert client._stored()["token"] == "local"
def test_a_login_from_before_installations_were_local_still_works(elsewhere: Path):
"""`fluksio login` wrote to XDG once; that must not stop answering."""
legacy = client._legacy_config_path()
legacy.parent.mkdir(parents=True)
legacy.write_text(json.dumps({"url": "http://elsewhere:8000", "token": "old"}))
assert client._stored()["token"] == "old"
def test_a_local_credential_wins_over_the_legacy_one(elsewhere: Path):
legacy = client._legacy_config_path()
legacy.parent.mkdir(parents=True)
legacy.write_text(json.dumps({"url": "http://elsewhere:8000", "token": "old"}))
client.write_config("http://127.0.0.1:8131", "local", elsewhere / ".fluksio")
assert client._stored()["token"] == "local"
def test_ignoring_itself_leaves_an_existing_gitignore_alone(elsewhere: Path):
directory = elsewhere / ".fluksio"
directory.mkdir()
(directory / ".gitignore").write_text("mine\n")
client.ignore_self(directory)
assert (directory / ".gitignore").read_text() == "mine\n"
def test_a_repository_whose_code_is_in_a_package_is_discovered(
elsewhere: Path, monkeypatch: pytest.MonkeyPatch
):
"""`fluksio sync` in a repo root has to find `myresearch/`, not just *.py.
This is the ordinary layout, and it is what `run` leans on to sync without
being told where to look.
"""
from fluksio.sdk import FLOWS
from fluksio.sdk.cli import discover
package = elsewhere / "mystudy"
package.mkdir()
(package / "__init__.py").write_text("")
(package / "pipeline.py").write_text(
"from fluksio import Flow, Port, node\n"
"\n"
"@node(provides=[Port('score', 'float')])\n"
"def scoring():\n"
" return {'score': 1.0}\n"
"\n"
"study = Flow('study', nodes=[scoring], outputs=['score'])\n"
)
# The things a repository root also holds, none of which is importable.
(elsewhere / ".venv").mkdir()
(elsewhere / ".fluksio").mkdir()
(elsewhere / "data").mkdir()
FLOWS.clear()
try:
found = discover(["."])
finally:
FLOWS.clear()
assert [flow.name for flow in found] == ["study"]