mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-09-30 21:36:47 +08:00
fix(box): align integration tests with runner-owned bindings
This commit is contained in:
@@ -670,7 +670,7 @@ async def test_box_service_allows_host_mount_under_configured_root(tmp_path):
|
||||
'cmd': 'pwd',
|
||||
'host_path': str(host_dir),
|
||||
'host_path_mode': BoxHostMountMode.READ_WRITE.value,
|
||||
'session_id': '11',
|
||||
'session_id': 'person_test_user',
|
||||
},
|
||||
make_query(11),
|
||||
)
|
||||
@@ -962,7 +962,7 @@ async def test_profile_unlocked_field_can_be_overridden():
|
||||
await service.initialize()
|
||||
|
||||
result = await service.execute_spec_payload(
|
||||
{'cmd': 'echo hi', 'timeout_sec': 60, 'network': 'on', 'session_id': '31'},
|
||||
{'cmd': 'echo hi', 'timeout_sec': 60, 'network': 'on', 'session_id': 'person_test_user'},
|
||||
make_query(31),
|
||||
)
|
||||
|
||||
@@ -984,7 +984,7 @@ async def test_profile_locked_field_cannot_be_overridden():
|
||||
await service.initialize()
|
||||
|
||||
result = await service.execute_spec_payload(
|
||||
{'cmd': 'echo hi', 'network': 'on', 'host_path_mode': 'rw', 'session_id': '32'},
|
||||
{'cmd': 'echo hi', 'network': 'on', 'host_path_mode': 'rw', 'session_id': 'person_test_user'},
|
||||
make_query(32),
|
||||
)
|
||||
|
||||
@@ -1193,7 +1193,7 @@ async def test_profile_offline_readonly_locks_read_only_rootfs():
|
||||
await service.initialize()
|
||||
|
||||
await service.execute_spec_payload(
|
||||
{'cmd': 'echo hi', 'read_only_rootfs': False, 'session_id': '41'}, make_query(41)
|
||||
{'cmd': 'echo hi', 'read_only_rootfs': False, 'session_id': 'person_test_user'}, make_query(41)
|
||||
)
|
||||
|
||||
spec = backend.start_specs[0]
|
||||
@@ -2372,3 +2372,17 @@ class TestAttachmentHostPath:
|
||||
service.default_workspace = None
|
||||
# Must not raise.
|
||||
await service._purge_attachment_dirs()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_execution_cannot_override_runner_bound_session():
|
||||
logger = Mock()
|
||||
backend = FakeBackend(logger)
|
||||
runtime = BoxRuntime(logger=logger, backends=[backend], session_ttl_sec=300)
|
||||
service = BoxService(make_app(logger), client=_InProcessBoxRuntimeClient(logger, runtime))
|
||||
await service.initialize()
|
||||
|
||||
with pytest.raises(BoxValidationError, match='session_id must match the bound Box'):
|
||||
await service.execute_spec_payload({'cmd': 'true', 'session_id': 'other-box'}, make_query())
|
||||
|
||||
assert backend.start_calls == []
|
||||
|
||||
@@ -8,6 +8,7 @@ from unittest.mock import AsyncMock, Mock
|
||||
import pytest
|
||||
|
||||
from langbot.pkg.api.http.context import ExecutionContext
|
||||
from langbot.pkg.box.runner import RunBoxBinding
|
||||
|
||||
|
||||
_CONTEXT = ExecutionContext(
|
||||
@@ -30,6 +31,12 @@ def _make_query(*, variables=None, **kwargs):
|
||||
)
|
||||
|
||||
|
||||
def _make_bound_query(**kwargs):
|
||||
query = _make_query(**kwargs)
|
||||
query._box_binding = RunBoxBinding('run-a', 'skill-box', {}, 'run-a')
|
||||
return query
|
||||
|
||||
|
||||
def _make_skill_manager(skills: dict[str, dict], **kwargs):
|
||||
return SimpleNamespace(
|
||||
skills=skills,
|
||||
@@ -546,14 +553,14 @@ class TestNativeToolLoaderSkillPaths:
|
||||
await loader.invoke_tool(
|
||||
'read',
|
||||
{'path': '/workspace/.skills/demo/SKILL.md'},
|
||||
_make_query(query_id='q1', variables={PIPELINE_BOUND_SKILLS_KEY: ['demo']}),
|
||||
_make_bound_query(query_id='q1', variables={PIPELINE_BOUND_SKILLS_KEY: ['demo']}),
|
||||
)
|
||||
return
|
||||
|
||||
result = await loader.invoke_tool(
|
||||
'read',
|
||||
{'path': '/workspace/.skills/demo/SKILL.md'},
|
||||
_make_query(query_id='q1', variables={PIPELINE_BOUND_SKILLS_KEY: ['demo']}),
|
||||
_make_bound_query(query_id='q1', variables={PIPELINE_BOUND_SKILLS_KEY: ['demo']}),
|
||||
)
|
||||
|
||||
assert result['ok'] is True
|
||||
@@ -577,7 +584,7 @@ class TestNativeToolLoaderSkillPaths:
|
||||
)
|
||||
ap.skill_mgr = _make_skill_manager({'demo': _make_skill_data(name='demo', package_root=tmpdir)})
|
||||
loader = NativeToolLoader(ap)
|
||||
query = _make_query(
|
||||
query = _make_bound_query(
|
||||
query_id='q-external-read',
|
||||
variables={PIPELINE_BOUND_SKILLS_KEY: ['demo']},
|
||||
)
|
||||
@@ -609,7 +616,7 @@ class TestNativeToolLoaderSkillPaths:
|
||||
)
|
||||
ap.skill_mgr = _make_skill_manager({'demo': _make_skill_data(name='demo', package_root=tmpdir)})
|
||||
loader = NativeToolLoader(ap)
|
||||
query = _make_query(
|
||||
query = _make_bound_query(
|
||||
query_id='q-external-no-protocol',
|
||||
variables={PIPELINE_BOUND_SKILLS_KEY: ['demo']},
|
||||
)
|
||||
@@ -639,7 +646,7 @@ class TestNativeToolLoaderSkillPaths:
|
||||
ap.skill_mgr = SimpleNamespace(refresh_skill_from_disk=Mock())
|
||||
loader = NativeToolLoader(ap)
|
||||
|
||||
query = _make_query(query_id='q1', launcher_type='person', launcher_id='123')
|
||||
query = _make_bound_query(query_id='q1', launcher_type='person', launcher_id='123')
|
||||
register_activated_skill(query, _make_skill_data(name='demo', package_root=tmpdir))
|
||||
|
||||
result = await loader.invoke_tool(
|
||||
@@ -671,7 +678,7 @@ class TestNativeToolLoaderSkillPaths:
|
||||
)
|
||||
ap.skill_mgr = SimpleNamespace(refresh_skill_from_disk=Mock())
|
||||
loader = NativeToolLoader(ap)
|
||||
query = _make_query(query_id='q-external', launcher_type='person', launcher_id='123')
|
||||
query = _make_bound_query(query_id='q-external', launcher_type='person', launcher_id='123')
|
||||
register_activated_skill(
|
||||
query,
|
||||
_make_skill_data(
|
||||
@@ -709,7 +716,7 @@ class TestNativeToolLoaderSkillPaths:
|
||||
ap.skill_mgr = _make_skill_manager({'demo': _make_skill_data(name='demo', package_root=tmpdir)})
|
||||
loader = NativeToolLoader(ap)
|
||||
|
||||
query = _make_query(query_id='q1', variables={PIPELINE_BOUND_SKILLS_KEY: ['demo']})
|
||||
query = _make_bound_query(query_id='q1', variables={PIPELINE_BOUND_SKILLS_KEY: ['demo']})
|
||||
|
||||
with pytest.raises(ValueError, match='Skill "demo" is not available at this path'):
|
||||
await loader.invoke_tool(
|
||||
@@ -717,3 +724,16 @@ class TestNativeToolLoaderSkillPaths:
|
||||
{'path': '/workspace/.skills/demo/notes.txt', 'content': 'hi'},
|
||||
query,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_native_skill_tools_require_runner_box_binding():
|
||||
from langbot.pkg.provider.tools.loaders.native import NativeToolLoader
|
||||
from langbot_plugin.box.errors import BoxValidationError
|
||||
|
||||
ap = _make_ap()
|
||||
ap.box_service = SimpleNamespace(available=True, execute_tool=AsyncMock())
|
||||
loader = NativeToolLoader(ap)
|
||||
with pytest.raises(BoxValidationError, match='Runner must bind a Box'):
|
||||
await loader.invoke_tool('exec', {'command': 'true'}, _make_query())
|
||||
ap.box_service.execute_tool.assert_not_awaited()
|
||||
|
||||
Reference in New Issue
Block a user