Files
LangBot/plugins/KnowledgeEngine/certification-tests/test_limits.py
T

108 lines
4.1 KiB
Python

"""Regression fixtures are local; no external model/parser/provider requests."""
import asyncio
import threading
import pytest
from test_shared_state import load_plugin, bind, StorageFixture, CONNECTORS
@pytest.mark.asyncio
async def test_offload_slot_is_held_through_repeated_cancellation():
pc, _ = load_plugin('LangRAG')
plugin = bind(pc, StorageFixture())
assert hasattr(plugin, 'offload'), 'CPU parsing/chunking needs installation bounded offload'
entered = threading.Event()
release = threading.Event()
count = 0
lock = threading.Lock()
def job():
nonlocal count
with lock:
count += 1
if count == 2:
entered.set()
release.wait(2)
return 'done'
tasks = [asyncio.create_task(plugin.offload.run(job)) for _ in range(5)]
try:
for _ in range(100):
if entered.is_set():
break
await asyncio.sleep(.005)
assert entered.is_set()
tasks[0].cancel()
await asyncio.sleep(.01)
tasks[0].cancel()
await asyncio.sleep(.01)
assert count == 2, 'Cancelled waiters must not release running thread slots'
release.set()
results = await asyncio.gather(*tasks, return_exceptions=True)
assert isinstance(results[0], asyncio.CancelledError)
assert results[1:] == ['done'] * 4
finally:
release.set()
await asyncio.gather(*tasks, return_exceptions=True)
@pytest.mark.asyncio
async def test_parser_rejects_oversized_input_before_decode():
load_plugin('LangRAG')
from components.knowledge_engine.parser import FileParser
with pytest.raises(ValueError, match='limit'):
await FileParser().parse(b'x' * (16 * 1024 * 1024 + 1), 'doc.txt')
@pytest.mark.asyncio
@pytest.mark.parametrize('name', CONNECTORS)
async def test_connector_storage_failure_is_not_missing_and_refuses_mutations(name):
pc, ec = load_plugin(name)
store = StorageFixture()
engine = ec()
engine.plugin = bind(pc, store)
store.fail = True
# Unreadable fence state is "unknown", never "unfenced": the mutation is
# refused with the Host failure instead of being dispatched.
with pytest.raises(RuntimeError, match='offline'):
await engine.delete_document('kb', 'doc')
with pytest.raises(RuntimeError, match='offline'):
await engine.on_knowledge_base_create('kb', {})
assert not store.data
# The unreadable state is not cached either: once Host storage answers, the
# same mutation is retried and proceeds rather than staying refused.
store.fail = False
await engine.on_knowledge_base_create('kb', {})
assert store.data
@pytest.mark.asyncio
async def test_telemetry_cancellation_clear_and_failure_fencing():
pc, _ = load_plugin('LangRAG')
store = StorageFixture()
plugin = bind(pc, store)
await plugin.initialize()
store.release.clear()
task = asyncio.create_task(plugin.telemetry.record_delete(collection_id='kb', document_id='old', status='completed', duration_ms=1))
await store.started.wait()
task.cancel()
clear = asyncio.create_task(plugin.telemetry.clear())
await asyncio.sleep(.01)
with pytest.raises(RuntimeError, match='fenced'):
await clear
store.release.set()
await asyncio.gather(task, return_exceptions=True)
other = bind(pc, store)
await other.initialize()
# A fresh reader may see the detached commit, but a failed clear cannot
# acknowledge deletion or introduce a later event.
assert all(event['document_id'] != 'new' for event in (await other.telemetry.snapshot())['recent']['delete'])
store.fail = True
with pytest.raises(RuntimeError, match='fenced'):
await plugin.telemetry.record_delete(collection_id='kb', document_id='new', status='completed', duration_ms=1)
with pytest.raises(RuntimeError, match='fenced'):
await plugin.telemetry.snapshot()
store.fail = False
with pytest.raises(RuntimeError, match='fenced'):
await plugin.telemetry.clear()
assert all(event['document_id'] != 'new' for event in (await other.telemetry.snapshot())['recent']['delete'])