from scripts import dev def test_backend_runtime_probe_checks_mysql8_auth_dependency(monkeypatch): commands = [] monkeypatch.setattr(dev, "_backend_python", lambda: "/tmp/backend-python") def fake_run(command, **kwargs): commands.append(command) class Result: returncode = 0 stderr = "" return Result() monkeypatch.setattr(dev.subprocess, "run", fake_run) assert dev._ensure_backend_runtime() == "/tmp/backend-python" assert commands[0] == [ "/tmp/backend-python", "-c", "import fastapi, pymysql, uvicorn, cryptography", ] def test_backend_environment_has_local_defaults(monkeypatch): for name in ("DEV_MODE", "MYSQL_DSN", "AGENT_TOKEN"): monkeypatch.delenv(name, raising=False) env = dev.build_backend_env({}) assert env["DEV_MODE"] == "true" assert env["MYSQL_DSN"] == "mysql+pymysql://root:root@127.0.0.1:3306/rpa_center?charset=utf8mb4" assert env["AGENT_TOKEN"] == "dev-agent-token" def test_start_uses_checked_backend_python(monkeypatch): spawned = [] monkeypatch.setattr(dev, "ensure_mysql", lambda: None) monkeypatch.setattr(dev, "wait_for_port", lambda host, port: None) monkeypatch.setattr(dev, "_ensure_backend_runtime", lambda: "/tmp/backend-python") monkeypatch.setattr(dev, "_read_pids", lambda: {}) monkeypatch.setattr(dev, "_pid_alive", lambda pid: False) monkeypatch.setattr(dev, "_port_open", lambda host, port: False) monkeypatch.setattr(dev, "_write_pids", lambda pids: None) monkeypatch.setattr(dev, "build_backend_env", lambda: {}) def fake_spawn(name, command, cwd, env): spawned.append((name, command)) return len(spawned) monkeypatch.setattr(dev, "_spawn", fake_spawn) dev.start() assert spawned[0] == ( "backend", [ "/tmp/backend-python", "-m", "uvicorn", "state_center.app.main:app", "--host", "0.0.0.0", "--port", "8000", ], ) def test_start_reuses_frontend_when_port_is_already_open(monkeypatch): spawned = [] monkeypatch.setattr(dev, "ensure_mysql", lambda: None) monkeypatch.setattr(dev, "wait_for_port", lambda host, port: None) monkeypatch.setattr(dev, "_ensure_backend_runtime", lambda: "/tmp/backend-python") monkeypatch.setattr(dev, "_read_pids", lambda: {}) monkeypatch.setattr(dev, "_write_pids", lambda pids: None) monkeypatch.setattr(dev, "build_backend_env", lambda: {}) monkeypatch.setattr(dev, "_port_open", lambda host, port: port == 5173) def fake_spawn(name, command, cwd, env): spawned.append(name) return len(spawned) monkeypatch.setattr(dev, "_spawn", fake_spawn) dev.start() assert spawned == ["backend"] def test_pid_alive_rejects_invalid_pid(): assert dev._pid_alive(-1) is False assert dev._pid_alive(0) is False def test_stop_pid_terminates_process_group_on_posix(monkeypatch): calls = [] monkeypatch.setattr(dev.os, "name", "posix") monkeypatch.setattr(dev.os, "getpgid", lambda pid: 4321) monkeypatch.setattr(dev.os, "killpg", lambda pgid, sig: calls.append(("killpg", pgid, sig))) monkeypatch.setattr(dev.os, "kill", lambda pid, sig: calls.append(("kill", pid, sig))) dev._stop_pid(1234) assert calls == [("killpg", 4321, dev.signal.SIGTERM)]