# retoor import itertools import socket import pytest from devplacepy.database import get_table, init_db from devplacepy.services.containers import store from devplacepy.services.containers.workspace import provision OWNER = "provision-owner" STATUSES = ( store.ST_CREATED, store.ST_STARTING, store.ST_RUNNING, store.ST_STOPPED, store.ST_PAUSED, store.ST_CRASHED, store.ST_RESTARTING, store.ST_REMOVING, store.ST_REMOVED, "", ) DESIRED = (store.DESIRED_RUNNING, store.DESIRED_STOPPED, store.DESIRED_PAUSED, "") @pytest.fixture(autouse=True) def _provision_db(): init_db() yield get_table("instances").delete(workspace_owner_uid=OWNER) def _instance(**overrides) -> dict: row = { "uid": "ws-phase", "status": store.ST_RUNNING, "desired_state": store.DESIRED_RUNNING, "suspended_at": "", "editor_port": 8443, "ports_json": "[]", "container_ip": "", "workspace_owner_uid": OWNER, } row.update(overrides) return row @pytest.fixture def listener(): sock = socket.socket() sock.bind(("127.0.0.1", 0)) sock.listen(4) try: yield sock finally: sock.close() @pytest.mark.parametrize( "status, desired, ready, expected", [ (store.ST_RUNNING, store.DESIRED_RUNNING, True, provision.PHASE_READY), (store.ST_RUNNING, store.DESIRED_RUNNING, False, provision.PHASE_STARTING), (store.ST_CREATED, store.DESIRED_RUNNING, False, provision.PHASE_STARTING), (store.ST_STOPPED, store.DESIRED_RUNNING, False, provision.PHASE_STARTING), (store.ST_CRASHED, store.DESIRED_RUNNING, False, provision.PHASE_STARTING), (store.ST_RUNNING, store.DESIRED_STOPPED, True, provision.PHASE_STOPPING), (store.ST_PAUSED, store.DESIRED_STOPPED, False, provision.PHASE_STOPPING), (store.ST_RESTARTING, store.DESIRED_STOPPED, False, provision.PHASE_STOPPING), (store.ST_CRASHED, store.DESIRED_STOPPED, False, provision.PHASE_CRASHED), (store.ST_STOPPED, store.DESIRED_STOPPED, False, provision.PHASE_STOPPED), (store.ST_CREATED, store.DESIRED_STOPPED, False, provision.PHASE_STOPPED), ("", "", False, provision.PHASE_STOPPED), ], ) def test_phase_follows_desired_state_status_and_the_editor_probe( status, desired, ready, expected ): row = _instance(status=status, desired_state=desired) assert provision.phase(row, ready) == expected def test_a_suspended_workspace_is_suspended_whatever_else_it_says(): for status, desired, ready in itertools.product(STATUSES, DESIRED, (True, False)): row = _instance( status=status, desired_state=desired, suspended_at="2026-01-01T00:00:00" ) assert provision.phase(row, ready) == provision.PHASE_SUSPENDED def test_ready_needs_a_running_container_that_wants_to_run(): for status, desired in itertools.product(STATUSES, DESIRED): row = _instance(status=status, desired_state=desired) is_ready = provision.phase(row, True) == provision.PHASE_READY assert is_ready == ( status == store.ST_RUNNING and desired == store.DESIRED_RUNNING ) def test_every_phase_over_the_whole_input_domain_has_a_label(): for status, desired, ready, suspended in itertools.product( STATUSES, DESIRED, (True, False), ("", "2026-01-01T00:00:00") ): row = _instance(status=status, desired_state=desired, suspended_at=suspended) assert provision.phase(row, ready) in provision.PHASE_LABELS def test_transitional_phases_are_exactly_starting_and_stopping(): assert set(provision.TRANSITIONAL_PHASES) == { provision.PHASE_STARTING, provision.PHASE_STOPPING, } def test_editor_ready_when_the_editor_port_accepts_connections(listener): port = listener.getsockname()[1] row = _instance(container_ip="127.0.0.1", editor_port=port) assert provision.editor_ready(row) is True def test_editor_ready_is_false_when_nothing_listens(): probe = socket.socket() probe.bind(("127.0.0.1", 0)) port = probe.getsockname()[1] probe.close() row = _instance(container_ip="127.0.0.1", editor_port=port) assert provision.editor_ready(row) is False def test_editor_ready_is_false_without_a_reachable_target(listener): row = _instance(container_ip="", ports_json="[]") assert provision.editor_ready(row) is False def test_editor_ready_is_false_unless_the_container_runs(listener): port = listener.getsockname()[1] for status in STATUSES: if status == store.ST_RUNNING: continue row = _instance(container_ip="127.0.0.1", editor_port=port, status=status) assert provision.editor_ready(row) is False def test_editor_ready_is_false_while_suspended(listener): port = listener.getsockname()[1] row = _instance( container_ip="127.0.0.1", editor_port=port, suspended_at="2026-01-01T00:00:00" ) assert provision.editor_ready(row) is False def test_view_carries_the_phase_its_label_readiness_and_the_owner(listener): port = listener.getsockname()[1] instance = store.create_instance( { "project_uid": "provision-project", "name": "ws-view", "status": store.ST_RUNNING, "desired_state": store.DESIRED_RUNNING, "is_workspace": 1, "workspace_owner_uid": OWNER, "container_ip": "127.0.0.1", "editor_port": port, "ports_json": "[]", } ) view = provision.view(instance) assert view["phase"] == provision.PHASE_READY assert view["phase_label"] == "Ready" assert view["editor_ready"] is True assert view["owner_uid"] == OWNER store.update_instance(instance["uid"], {"desired_state": store.DESIRED_STOPPED}) view = provision.view(store.get_instance(instance["uid"])) assert view["phase"] == provision.PHASE_STOPPING assert view["editor_ready"] is True