Skip to content

Commit eb6e036

Browse files
committed
fix(lfx): close capability-selected executor streams
1 parent 527a33a commit eb6e036

1 file changed

Lines changed: 46 additions & 0 deletions

File tree

src/lfx/tests/unit/execution/test_capability_routing.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from __future__ import annotations
44

5+
import asyncio
56
from types import SimpleNamespace
67
from typing import TYPE_CHECKING, Any
78

@@ -31,6 +32,21 @@ async def execute(self, unit: Unit) -> AsyncIterator[StepResult | RunComplete]:
3132
yield RunComplete(outputs=[self.output])
3233

3334

35+
class _NeverEndingExecutor(Executor):
36+
kind = "sandbox"
37+
38+
def __init__(self) -> None:
39+
self.closed = False
40+
41+
async def execute(self, unit: Unit) -> AsyncIterator[StepResult | RunComplete]: # noqa: ARG002
42+
try:
43+
while True:
44+
yield StepResult(payload="tick")
45+
await asyncio.sleep(0)
46+
finally:
47+
self.closed = True
48+
49+
3450
@pytest.mark.asyncio
3551
async def test_coordinator_routes_untrusted_runs_to_capability_executor() -> None:
3652
sandbox = _RecordingExecutor("sandbox", "sandbox-output")
@@ -118,3 +134,33 @@ async def test_coordinator_skips_capability_service_when_passthrough() -> None:
118134
assert outputs == ["default-output"]
119135
assert default.units[0].executor_kind is None
120136
assert default.units[0].runtime_options == {}
137+
138+
139+
@pytest.mark.asyncio
140+
async def test_stream_close_finalizes_capability_selected_executor() -> None:
141+
sandbox = _NeverEndingExecutor()
142+
registry = ExecutorRegistry()
143+
registry.register(_RecordingExecutor("in-process", "in-process-output"))
144+
registry.register(sandbox)
145+
146+
class _Classifier:
147+
def trust_of_flow(self, _context: CapabilityContext) -> Trust:
148+
return Trust.UNTRUSTED
149+
150+
def is_untrusted_node(self, _node: dict[str, Any], _context: CapabilityContext | None = None) -> bool:
151+
return True
152+
153+
capability_service = CapabilityService(settings_service=_StubSettings())
154+
capability_service.install(classifier=_Classifier(), untrusted_executor_kind="sandbox")
155+
coordinator = Coordinator(
156+
registry=registry,
157+
executor_kind="in-process",
158+
capability_service=capability_service,
159+
)
160+
161+
stream = coordinator.stream(SimpleNamespace(), inputs=[{}])
162+
assert await anext(stream) == "tick"
163+
await stream.aclose()
164+
await asyncio.sleep(0)
165+
166+
assert sandbox.closed is True

0 commit comments

Comments
 (0)