"""Routing cascade: explicit > capability > sticky > default-local.""" from __future__ import annotations import pytest from uuid import UUID from claire.config import ClaireConfig, HostEntry from claire.routing import route from claire.web import service @pytest.fixture def cfg() -> ClaireConfig: return ClaireConfig( machine_id="m", this_host="plum", known_hosts=[ HostEntry(name="plum", aliases=["local"]), HostEntry(name="apricot", capabilities=["cores:64", "gpu"]), HostEntry(name="black", capabilities=["media", "transmission"]), ], ) def _add_session(conn, uuid: str, host: str) -> None: conn.execute( "INSERT INTO sessions (uuid, host, updated_hlc) VALUES (?, ?, ?)", (uuid, host, "1"), ) def _task_with_worker(conn, gen, *, project: str, host: str, session_uuid: str): """Create a project+task and an active assignment to a session on `host`. Returns the task id (str). Uses service so FK constraints are satisfied.""" service.create_project(conn, gen, name=project) task = service.add_task(conn, gen, project=project, title="t") _add_session(conn, session_uuid, host) service.create_assignment(conn, gen, task_id=task.id, session_uuid=UUID(session_uuid)) return str(task.id) # 1. explicit ----------------------------------------------------------------- def test_explicit_host_wins(conn, cfg) -> None: d = route(conn, cfg, receiving_host="plum", explicit_host="apricot") assert (d.host, d.reason) == ("apricot", "explicit") def test_explicit_alias_resolves(conn, cfg) -> None: # "local" → plum even when received on plum d = route(conn, cfg, receiving_host="plum", explicit_host="local") assert (d.host, d.reason) == ("plum", "explicit") def test_explicit_unknown_host_falls_back_local_not_silent(conn, cfg) -> None: d = route(conn, cfg, receiving_host="plum", explicit_host="mars") assert d.host == "plum" assert d.reason == "unknown-host" # 2. capability --------------------------------------------------------------- def test_capability_single(conn, cfg) -> None: d = route(conn, cfg, receiving_host="plum", capability_needs=["media"]) assert (d.host, d.reason) == ("black", "capability") def test_capability_key_prefix(conn, cfg) -> None: # asking "cores" matches "cores:64" d = route(conn, cfg, receiving_host="plum", capability_needs=["cores"]) assert d.host == "apricot" def test_capability_intersection_of_needs(conn, cfg) -> None: # gpu AND cores → only apricot has both; media-only black excluded d = route(conn, cfg, receiving_host="plum", capability_needs=["gpu", "cores"]) assert d.host == "apricot" def test_capability_no_match_falls_through_to_default(conn, cfg) -> None: d = route(conn, cfg, receiving_host="plum", capability_needs=["fpga"]) assert (d.host, d.reason) == ("plum", "default-local") def test_capability_tiebreak_least_loaded(conn) -> None: cfg = ClaireConfig( machine_id="m", this_host="plum", known_hosts=[ HostEntry(name="a", capabilities=["media"]), HostEntry(name="b", capabilities=["media"]), ], ) d = route(None, cfg, receiving_host="plum", capability_needs=["media"], host_load={"a": 5, "b": 1}) assert d.host == "b" assert set(d.candidates) == {"a", "b"} # 3. sticky ------------------------------------------------------------------- def test_sticky_by_session(conn, cfg) -> None: _add_session(conn, "11111111-1111-1111-1111-111111111111", "apricot") d = route(conn, cfg, receiving_host="plum", session_uuid="11111111-1111-1111-1111-111111111111") assert (d.host, d.reason) == ("apricot", "sticky") def test_sticky_by_task_via_active_assignment(conn, gen, cfg) -> None: task_id = _task_with_worker( conn, gen, project="p", host="black", session_uuid="22222222-2222-2222-2222-222222222222", ) d = route(conn, cfg, receiving_host="plum", task_id=task_id) assert (d.host, d.reason) == ("black", "sticky") def test_session_reference_beats_task(conn, gen, cfg) -> None: _add_session(conn, "33333333-3333-3333-3333-333333333333", "apricot") task_id = _task_with_worker( conn, gen, project="p", host="black", session_uuid="44444444-4444-4444-4444-444444444444", ) d = route(conn, cfg, receiving_host="plum", session_uuid="33333333-3333-3333-3333-333333333333", task_id=task_id) assert d.host == "apricot" # session wins # 4. default ------------------------------------------------------------------ def test_default_local_when_no_signal(conn, cfg) -> None: d = route(conn, cfg, receiving_host="apricot") assert (d.host, d.reason) == ("apricot", "default-local") def test_precedence_explicit_over_everything(conn, cfg) -> None: # a sticky session on black, capability=media (black), but explicit apricot wins _add_session(conn, "55555555-5555-5555-5555-555555555555", "black") d = route(conn, cfg, receiving_host="plum", explicit_host="apricot", capability_needs=["media"], session_uuid="55555555-5555-5555-5555-555555555555") assert (d.host, d.reason) == ("apricot", "explicit")