generated from coulomb/repo-seed
feat(diagnostics): end-to-end tunnel check, stale state detection, MCP extensions
- diagnostics.py: TunnelCheckResult with SSH process liveness, port probe, and optional API health check; check_tunnel / check_all_tunnels - cli.py: bridge status shows LIVE column and [STALE] marker when state says connected but PID is dead; bridge check wired to diagnostics - state.py: read_raw_pid helper; _pid_alive exported for reuse - capabilities.py: capabilities registry stubs - mcp_server/server.py: expose check_tunnel and tunnel capabilities over MCP - SCOPE.md: rapid orientation document - workplans/OPS-WP-0001-diagnostics.md: workplan backing this feature - tests: 207 passing (test_cli, test_mcp, test_diagnostics) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -188,6 +188,84 @@ class TestLogsCommand:
|
||||
assert "bridge_started" in result.output
|
||||
|
||||
|
||||
class TestCheckCommand:
|
||||
def test_check_help(self):
|
||||
result = runner.invoke(app, ["check", "--help"])
|
||||
assert result.exit_code == 0
|
||||
|
||||
@pytest.mark.capability("bridge_check")
|
||||
@pytest.mark.access_mode("cli")
|
||||
def test_check_all_pass(self, env):
|
||||
from bridge.diagnostics import TunnelCheckResult
|
||||
ok_result = TunnelCheckResult(
|
||||
tunnel="test-tunnel",
|
||||
ssh_process="ok",
|
||||
pid=12345,
|
||||
remote_port="listening",
|
||||
local_api=None,
|
||||
latency_ms=None,
|
||||
stale_state=False,
|
||||
)
|
||||
with patch("bridge.cli.check_all_tunnels", return_value=[ok_result]):
|
||||
result = runner.invoke(app, ["check"], env=env)
|
||||
assert result.exit_code == 0
|
||||
|
||||
def test_check_any_fail(self, env):
|
||||
from bridge.diagnostics import TunnelCheckResult
|
||||
fail_result = TunnelCheckResult(
|
||||
tunnel="test-tunnel",
|
||||
ssh_process="dead",
|
||||
pid=None,
|
||||
remote_port="closed",
|
||||
local_api=None,
|
||||
latency_ms=None,
|
||||
stale_state=True,
|
||||
)
|
||||
with patch("bridge.cli.check_all_tunnels", return_value=[fail_result]):
|
||||
result = runner.invoke(app, ["check"], env=env)
|
||||
assert result.exit_code == 1
|
||||
|
||||
def test_check_json_flag(self, env):
|
||||
from bridge.diagnostics import TunnelCheckResult
|
||||
ok_result = TunnelCheckResult(
|
||||
tunnel="test-tunnel",
|
||||
ssh_process="ok",
|
||||
pid=12345,
|
||||
remote_port="listening",
|
||||
local_api=None,
|
||||
latency_ms=None,
|
||||
stale_state=False,
|
||||
)
|
||||
with patch("bridge.cli.check_all_tunnels", return_value=[ok_result]):
|
||||
result = runner.invoke(app, ["check", "--json"], env=env)
|
||||
assert result.exit_code == 0
|
||||
data = json.loads(result.output)
|
||||
assert isinstance(data, list)
|
||||
assert len(data) == 1
|
||||
assert data[0]["ok"] is True
|
||||
assert data[0]["tunnel"] == "test-tunnel"
|
||||
assert data[0]["ssh_process"] == "ok"
|
||||
|
||||
def test_check_specific_tunnel(self, env):
|
||||
from bridge.diagnostics import TunnelCheckResult
|
||||
ok_result = TunnelCheckResult(
|
||||
tunnel="test-tunnel",
|
||||
ssh_process="ok",
|
||||
pid=12345,
|
||||
remote_port="listening",
|
||||
local_api=None,
|
||||
latency_ms=None,
|
||||
stale_state=False,
|
||||
)
|
||||
with patch("bridge.cli.check_tunnel", return_value=ok_result):
|
||||
result = runner.invoke(app, ["check", "test-tunnel"], env=env)
|
||||
assert result.exit_code == 0
|
||||
|
||||
def test_check_unknown_tunnel_exit_1(self, env):
|
||||
result = runner.invoke(app, ["check", "nonexistent"], env=env)
|
||||
assert result.exit_code == 1
|
||||
|
||||
|
||||
class TestRestartCommand:
|
||||
def test_restart_unknown_tunnel_exit_1(self, env):
|
||||
result = runner.invoke(app, ["restart", "nonexistent"], env=env)
|
||||
|
||||
Reference in New Issue
Block a user