Files
LangBot/tests/unit_tests/api/service/test_pipeline_migration_cloud.py
T

122 lines
4.0 KiB
Python

"""Shared admission and real embedded artifact schema regressions."""
import copy
import json
from pathlib import Path
from types import SimpleNamespace as NS
import pytest
import sqlalchemy as sa
from tests.unit_tests.api.service.test_pipeline_migration import (
env as migration_env,
execute,
WS,
SOURCE,
RID,
planner,
)
from langbot.pkg.agent.runner.interaction_store import InteractionStore, InteractionScopeError
from langbot.pkg.entity.persistence.agent_interaction import AgentInteraction
@pytest.fixture
async def env(tmp_path, monkeypatch):
async for value in migration_env.__wrapped__(tmp_path, monkeypatch):
yield value
async def request(env, **kwargs):
return await InteractionStore(env.pm.get_db_engine()).create_request(
interaction_id='form',
run_id='run',
binding_id='binding',
runner_id=RID,
processor_type='pipeline',
processor_id='one',
workspace_id=WS,
request={},
delivery_target={},
expected_config=copy.deepcopy(SOURCE),
authority_check=lambda: True,
**kwargs,
)
@pytest.mark.asyncio
async def test_stale_writer_after_commit_rejected(env):
original = env.svc._activate
async def activate(*args):
with pytest.raises(InteractionScopeError):
await request(env)
return await original(*args)
env.svc._activate = activate
task = await execute(env)
assert task.task_context.metadata['results'][0]['state'] == 'migrated'
with pytest.raises(InteractionScopeError):
await request(env)
async with env.engine.connect() as conn:
assert not (await conn.execute(sa.select(AgentInteraction))).all()
@pytest.mark.asyncio
async def test_writer_requires_pipeline_authority(env):
with pytest.raises(InteractionScopeError):
await InteractionStore(env.engine).create_request(
interaction_id='form',
run_id='run',
binding_id='binding',
runner_id=RID,
processor_type='pipeline',
processor_id='one',
workspace_id=WS,
request={},
delivery_target={},
)
@pytest.mark.asyncio
@pytest.mark.parametrize(
'folder,field,good,bad',
[
('LangflowAgent', 'tweaks', {'node': {'value': 1}}, ['not-an-object']),
('WeKnoraAgent', 'knowledge-base-ids', ['kb-a'], [1]),
],
)
async def test_embedded_artifact_schema_types(env, folder, field, good, bad):
root = Path(__file__).parent / 'fixtures'
artifact = 'langflow-agent' if folder == 'LangflowAgent' else 'weknora-agent'
spec = {'config': json.loads((root / (artifact + '-artifact-schema.json')).read_text())}
kind = 'json' if folder == 'LangflowAgent' else 'array[string]'
schema = next(s for s in spec['config'] if s['type'] == kind)
descriptor = env.ap.runner_registry.list_runners.return_value[0]
descriptor.config_schema = [schema]
plan = planner(SOURCE)
plan['config']['ai']['runner_config'][RID] = {schema['name']: good}
await env.svc._verify_runtime(NS(workspace_uuid=WS), plan)
plan['config']['ai']['runner_config'][RID][schema['name']] = bad
with pytest.raises(env.m.MigrationError, match='runner_schema_incompatible'):
await env.svc._verify_runtime(NS(workspace_uuid=WS), plan)
def test_conversation_authority_is_captured_before_runner_returns():
from langbot.pkg.agent.runner.interaction_manager import InteractionManager
old, new = NS(), NS()
config = planner(SOURCE)['config']
query = NS(pipeline_config=config, pipeline_uuid='one', session=NS(using_conversation=new))
binding = NS(
processor_type='pipeline', processor_id='one', runner_id=RID, runner_config=config['ai']['runner_config'][RID]
)
authority = InteractionManager._pipeline_admission(
binding,
NS(id=RID),
{
'_query': query,
'_pipeline_expected_config': copy.deepcopy(config),
'_pipeline_conversation': old,
},
)
assert authority['authority_check']() is False