Revert "fix(runtime): make plugin and box connectors resilient"

This reverts commit 0b461e5830.
This commit is contained in:
Junyan Qin
2026-07-21 18:43:01 +08:00
parent 0b461e5830
commit 1765c43262
15 changed files with 236 additions and 699 deletions
+1 -19
View File
@@ -1,7 +1,7 @@
from __future__ import annotations
from types import SimpleNamespace
from unittest.mock import AsyncMock, Mock
from unittest.mock import Mock
import pytest
@@ -104,21 +104,3 @@ def test_box_runtime_connector_dispose_terminates_subprocess(monkeypatch: pytest
ctrl_task.cancel.assert_called_once()
assert connector._handler_task is None
assert connector._ctrl_task is None
@pytest.mark.asyncio
async def test_box_runtime_connector_cleans_partial_transport_on_connect_failure(
monkeypatch: pytest.MonkeyPatch,
):
monkeypatch.setattr('langbot.pkg.utils.platform.get_platform', lambda: 'linux')
monkeypatch.setattr('langbot.pkg.utils.platform.standalone_box', False)
connector = BoxRuntimeConnector(make_app(Mock()))
connector._start_local_stdio = AsyncMock(side_effect=RuntimeError('bind failed'))
connector._stop_transport = AsyncMock()
connector._close_managed_subprocess = AsyncMock()
with pytest.raises(RuntimeError, match='bind failed'):
await connector.initialize()
assert connector._stop_transport.await_count == 2
connector._close_managed_subprocess.assert_awaited_once()
+1 -19
View File
@@ -325,28 +325,10 @@ async def test_box_service_dispose_schedules_shutdown_on_event_loop(monkeypatch:
service.dispose()
await asyncio.sleep(0)
connector.dispose.assert_not_called()
connector.dispose.assert_called_once()
service.shutdown.assert_awaited_once()
@pytest.mark.asyncio
async def test_box_service_shutdown_reaps_connector_when_runtime_rpc_is_offline(
monkeypatch: pytest.MonkeyPatch,
):
connector = Mock()
connector.client = Mock()
connector.client.shutdown = AsyncMock(side_effect=RuntimeError('offline'))
connector.aclose = AsyncMock()
monkeypatch.setattr('langbot.pkg.box.service.BoxRuntimeConnector', Mock(return_value=connector))
service = BoxService(make_app(Mock()))
await service.shutdown()
connector.client.shutdown.assert_awaited_once()
connector.aclose.assert_awaited_once()
@pytest.mark.asyncio
async def test_box_runtime_reuses_request_session():
logger = Mock()
+20 -34
View File
@@ -2,7 +2,6 @@ from __future__ import annotations
import signal
from types import SimpleNamespace
from unittest.mock import Mock
import pytest
@@ -19,60 +18,47 @@ async def test_main_signal_handler_handles_sigint_before_app_created(monkeypatch
async def fake_make_app(loop):
captured_handler[signal.SIGINT](signal.SIGINT, None)
def fake_exit(code):
raise SystemExit(code)
monkeypatch.setattr(signal, 'signal', fake_signal)
monkeypatch.setattr(boot, 'make_app', fake_make_app)
monkeypatch.setattr(boot.os, '_exit', fake_exit)
await boot.main(SimpleNamespace())
with pytest.raises(SystemExit) as exc_info:
await boot.main(SimpleNamespace())
assert exc_info.value.code == 0
@pytest.mark.asyncio
async def test_main_signal_handler_disposes_created_app(monkeypatch):
captured_handler = {}
app_inst = SimpleNamespace(shutdown_called=False)
app_inst = SimpleNamespace(disposed=False)
def fake_signal(sig, handler):
captured_handler[sig] = handler
async def shutdown():
app_inst.shutdown_called = True
def dispose():
app_inst.disposed = True
async def run():
captured_handler[signal.SIGINT](signal.SIGINT, None)
async def fake_make_app(loop):
app_inst.shutdown = shutdown
app_inst.dispose = dispose
app_inst.run = run
return app_inst
def fake_exit(code):
raise SystemExit(code)
monkeypatch.setattr(signal, 'signal', fake_signal)
monkeypatch.setattr(boot, 'make_app', fake_make_app)
monkeypatch.setattr(boot.os, '_exit', fake_exit)
await boot.main(SimpleNamespace())
with pytest.raises(SystemExit) as exc_info:
await boot.main(SimpleNamespace())
assert app_inst.shutdown_called is True
@pytest.mark.asyncio
async def test_main_reports_app_run_failure_and_still_shuts_down(monkeypatch):
app_inst = SimpleNamespace(shutdown_called=False)
async def shutdown():
app_inst.shutdown_called = True
async def run():
raise RuntimeError('run failed')
async def fake_make_app(loop):
app_inst.shutdown = shutdown
app_inst.run = run
return app_inst
print_exc = Mock()
monkeypatch.setattr(signal, 'signal', lambda *_args: None)
monkeypatch.setattr(boot, 'make_app', fake_make_app)
monkeypatch.setattr(boot.traceback, 'print_exc', print_exc)
await boot.main(SimpleNamespace())
print_exc.assert_called_once()
assert app_inst.shutdown_called is True
assert exc_info.value.code == 0
assert app_inst.disposed is True
@@ -62,25 +62,6 @@ class TestListPlugins:
assert result == []
@pytest.mark.asyncio
async def test_returns_empty_while_runtime_is_disconnected(self):
connector = create_mock_connector()
result = await connector.list_plugins()
assert result == []
@pytest.mark.asyncio
async def test_returns_empty_after_managed_transport_disconnects(self):
connector = create_mock_connector()
connector.handler = AsyncMock()
connector._transport_task = Mock()
result = await connector.list_plugins()
assert result == []
connector.handler.list_plugins.assert_not_called()
@pytest.mark.asyncio
async def test_calls_handler_list_plugins(self):
"""Test that handler.list_plugins is called."""
@@ -313,12 +294,6 @@ class TestListKnowledgeEngines:
connector.handler.list_knowledge_engines.assert_called_once()
assert result == [{'plugin_id': 'author/engine', 'name': 'Engine'}]
@pytest.mark.asyncio
async def test_returns_empty_while_runtime_is_disconnected(self):
connector = create_mock_connector()
assert await connector.list_knowledge_engines() == []
class TestListParsers:
"""Tests for list_parsers method."""
@@ -356,12 +331,6 @@ class TestListParsers:
connector.handler.list_parsers.assert_called_once()
assert result == [{'plugin_id': 'author/parser', 'supported_mime_types': ['text/plain']}]
@pytest.mark.asyncio
async def test_returns_empty_while_runtime_is_disconnected(self):
connector = create_mock_connector()
assert await connector.list_parsers() == []
class TestCallParser:
"""Tests for call_parser method."""
@@ -417,7 +417,7 @@ class TestBuildBoxSessionPayload:
payload = s._build_box_session_payload('session-123')
assert payload['image'] == 'node:20'
assert payload['cpus'] == 2.0
assert payload['memory_mb'] == 1024
assert payload["memory_mb"] == 1024
assert payload['pids_limit'] == 256
def test_none_fields_excluded(self, mcp_module):
@@ -680,51 +680,6 @@ class TestGetRuntimeInfoDict:
# ... but are isolated by distinct process_ids within that session.
assert transient._box_stdio_runtime.process_id != live._box_stdio_runtime.process_id
def test_different_resource_profiles_use_different_box_sessions(self, mcp_module):
ap = _make_ap()
ap.box_service.available = True
default = _make_session(
mcp_module,
{
'name': 'default',
'uuid': 'default-uuid',
'mode': 'stdio',
'command': 'uvx',
'args': ['mcp-server-time'],
},
ap=ap,
)
constrained = _make_session(
mcp_module,
{
'name': 'constrained',
'uuid': 'constrained-uuid',
'mode': 'stdio',
'command': 'uvx',
'args': ['mcp-server-time'],
'box': {'memory_mb': 2048},
},
ap=ap,
)
assert default._build_box_session_id() == 'mcp-shared'
assert constrained._build_box_session_id().startswith('mcp-shared-')
assert constrained._build_box_session_id() != default._build_box_session_id()
writable = _make_session(
mcp_module,
{
'name': 'writable',
'uuid': 'writable-uuid',
'mode': 'stdio',
'command': 'uvx',
'args': ['mcp-server-time'],
'box': {'host_path_mode': 'rw'},
},
ap=ap,
)
assert writable._build_box_session_id() != default._build_box_session_id()
def test_stdio_session_refuses_when_box_unavailable(self, mcp_module):
"""Policy: when Box is configured but unavailable (disabled in config
OR connection failed), stdio MCP servers are NOT treated as box-stdio.