Skip to content

Commit 7d56ef8

Browse files
DeanChensjcopybara-github
authored andcommitted
test(workflow): run the invariant plugin in test modules that build a raw Runner
`InvariantPlugin` checks event/session invariants on every run, but it only runs when a test goes through the shared test runners. Several modules build a bare `Runner(...)` because they own the session service or pass an `App`, so their runs were never checked. Add `workflow_testing_utils.create_runner(**runner_kwargs, check_invariants=True)`, which builds a `Runner` with the plugin installed first (mirroring `TestInMemoryRunner`), and route the raw sites through it: - `test_workflow_dynamic_nodes.py` (24), `test_workflow_live.py` (6), `test_workflow_rewind.py` (3), `test_workflow_agent_as_node.py` (2), `test_workflow_function_tool_as_node.py` (1), `test_node_runner_failure.py` (9, plus its local `_run_workflow` copy is replaced by the shared `run_workflow`). - `agents/test_llm_agent_interruptions.py` now uses `TestInMemoryRunner` via a small `_make_runner` helper (4 sites). 46 previously unchecked runner sites now run under the plugin; all migrated modules pass with no new invariant violations, so no opt-outs were needed. Test-only change. Co-authored-by: Shangjie Chen <deanchen@google.com> PiperOrigin-RevId: 995957207
1 parent b0ffa24 commit 7d56ef8

8 files changed

Lines changed: 91 additions & 106 deletions

‎tests/unittests/agents/test_llm_agent_interruptions.py‎

Lines changed: 13 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@
1515
from __future__ import annotations
1616

1717
from google.adk.agents import LlmAgent
18-
from google.adk.runners import Runner
19-
from google.adk.sessions.in_memory_session_service import InMemorySessionService
2018
from google.adk.tools.function_tool import FunctionTool
2119
from google.adk.tools.long_running_tool import LongRunningFunctionTool
2220
from google.adk.tools.tool_context import ToolContext
@@ -30,6 +28,15 @@
3028
_SESSION_ID = 'test_session'
3129

3230

31+
async def _make_runner(agent):
32+
"""Build an invariant-checking runner with a pre-created session."""
33+
runner = testing_utils.TestInMemoryRunner(agent=agent, app_name='test')
34+
await runner.session_service.create_session(
35+
app_name='test', user_id=_USER_ID, session_id=_SESSION_ID
36+
)
37+
return runner
38+
39+
3340
async def _setup_runner(mock_model, tools=None, **agent_kwargs):
3441
"""Setup runner with LlmAgent directly."""
3542
llm_agent = LlmAgent(
@@ -38,16 +45,7 @@ async def _setup_runner(mock_model, tools=None, **agent_kwargs):
3845
tools=tools or [],
3946
**agent_kwargs,
4047
)
41-
session_service = InMemorySessionService()
42-
await session_service.create_session(
43-
app_name='test', user_id=_USER_ID, session_id=_SESSION_ID
44-
)
45-
runner = Runner(
46-
app_name='test',
47-
agent=llm_agent,
48-
session_service=session_service,
49-
)
50-
return runner
48+
return await _make_runner(llm_agent)
5149

5250

5351
async def _run_turn(runner, user_message):
@@ -332,14 +330,7 @@ def transfer_to_child(tool_context: ToolContext) -> str:
332330
sub_agents=[child_agent],
333331
)
334332

335-
# Setup runner
336-
session_service = InMemorySessionService()
337-
await session_service.create_session(
338-
app_name='test', user_id=_USER_ID, session_id=_SESSION_ID
339-
)
340-
runner = Runner(
341-
app_name='test', agent=parent_agent, session_service=session_service
342-
)
333+
runner = await _make_runner(parent_agent)
343334

344335
# When Parent runs the first turn
345336
events = await _run_turn(runner, 'Go')
@@ -398,14 +389,7 @@ def transfer_to_child(tool_context: ToolContext) -> str:
398389
sub_agents=[child_agent],
399390
)
400391

401-
# Setup runner
402-
session_service = InMemorySessionService()
403-
await session_service.create_session(
404-
app_name='test', user_id=_USER_ID, session_id=_SESSION_ID
405-
)
406-
runner = Runner(
407-
app_name='test', agent=parent_agent, session_service=session_service
408-
)
392+
runner = await _make_runner(parent_agent)
409393

410394
# When Parent runs the first turn
411395
events = await _run_turn(runner, 'Go')
@@ -459,14 +443,7 @@ async def test_single_turn_child_agent_interrupt_and_resume(self):
459443
sub_agents=[child_agent],
460444
)
461445

462-
# Setup runner
463-
session_service = InMemorySessionService()
464-
await session_service.create_session(
465-
app_name='test', user_id=_USER_ID, session_id=_SESSION_ID
466-
)
467-
runner = Runner(
468-
app_name='test', agent=parent_agent, session_service=session_service
469-
)
446+
runner = await _make_runner(parent_agent)
470447

471448
# When Parent runs the first turn
472449
events = await _run_turn(runner, 'Go')

‎tests/unittests/workflow/test_node_runner_failure.py‎

Lines changed: 11 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
from google.adk.agents.context import Context
2525
from google.adk.agents.invocation_context import InvocationContext
2626
from google.adk.events.event import Event
27-
from google.adk.runners import Runner
2827
from google.adk.sessions.in_memory_session_service import InMemorySessionService
2928
from google.adk.sessions.session import Session
3029
from google.adk.workflow import BaseNode
@@ -45,30 +44,15 @@
4544
import pytest
4645
from typing_extensions import override
4746

48-
from .._invariants import InvariantPlugin
4947
from .workflow_testing_utils import _FlakyNode
48+
from .workflow_testing_utils import create_runner
5049
from .workflow_testing_utils import CustomNonRetryableError
5150
from .workflow_testing_utils import CustomRetryableError
51+
from .workflow_testing_utils import run_workflow as _run_workflow
5252
from .workflow_testing_utils import simplify_events_with_node
5353
from .workflow_testing_utils import TestingNode
5454

5555

56-
async def _run_workflow(wf, message='start', *, check_invariants: bool = True):
57-
"""Run a Workflow through Runner, return collected events."""
58-
ss = InMemorySessionService()
59-
runner = Runner(app_name=wf.name, node=wf, session_service=ss)
60-
if check_invariants:
61-
runner.plugin_manager.plugins.insert(0, InvariantPlugin())
62-
session = await ss.create_session(app_name=wf.name, user_id='u')
63-
msg = types.Content(parts=[types.Part(text=message)], role='user')
64-
events = []
65-
async for event in runner.run_async(
66-
user_id='u', session_id=session.id, new_message=msg
67-
):
68-
events.append(event)
69-
return events, ss, session
70-
71-
7256
@pytest.mark.asyncio
7357
async def test_node_retries_on_matched_exception_string(
7458
request: pytest.FixtureRequest,
@@ -170,7 +154,7 @@ async def test_node_fails_immediately_on_unmatched_exception_string(
170154
)
171155

172156
ss = InMemorySessionService()
173-
runner = Runner(app_name=agent.name, node=agent, session_service=ss)
157+
runner = create_runner(app_name=agent.name, node=agent, session_service=ss)
174158
session = await ss.create_session(app_name=agent.name, user_id='u')
175159
msg = types.Content(parts=[types.Part(text='start')], role='user')
176160
events = []
@@ -364,7 +348,7 @@ async def test_node_stops_retrying_after_max_attempts(
364348
)
365349

366350
ss = InMemorySessionService()
367-
runner = Runner(app_name=agent.name, node=agent, session_service=ss)
351+
runner = create_runner(app_name=agent.name, node=agent, session_service=ss)
368352
session = await ss.create_session(app_name=agent.name, user_id='u')
369353
msg = types.Content(parts=[types.Part(text='start')], role='user')
370354
events = []
@@ -435,7 +419,7 @@ async def test_node_fails_immediately_without_retry_config(
435419
)
436420

437421
ss = InMemorySessionService()
438-
runner = Runner(app_name=agent.name, node=agent, session_service=ss)
422+
runner = create_runner(app_name=agent.name, node=agent, session_service=ss)
439423
session = await ss.create_session(app_name=agent.name, user_id='u')
440424
msg = types.Content(parts=[types.Part(text='start')], role='user')
441425
events = []
@@ -563,7 +547,7 @@ async def test_node_waits_for_initial_delay_before_retry(
563547
)
564548

565549
ss = InMemorySessionService()
566-
runner = Runner(app_name=agent.name, node=agent, session_service=ss)
550+
runner = create_runner(app_name=agent.name, node=agent, session_service=ss)
567551
session = await ss.create_session(app_name=agent.name, user_id='u')
568552
msg = types.Content(parts=[types.Part(text='start')], role='user')
569553

@@ -639,7 +623,7 @@ async def test_retry_applies_backoff_strategy(request: pytest.FixtureRequest):
639623
)
640624

641625
ss = InMemorySessionService()
642-
runner = Runner(app_name=agent.name, node=agent, session_service=ss)
626+
runner = create_runner(app_name=agent.name, node=agent, session_service=ss)
643627
session = await ss.create_session(app_name=agent.name, user_id='u')
644628
msg = types.Content(parts=[types.Part(text='start')], role='user')
645629

@@ -718,7 +702,7 @@ async def test_retry_applies_random_jitter(request: pytest.FixtureRequest):
718702
)
719703

720704
ss = InMemorySessionService()
721-
runner = Runner(app_name=agent.name, node=agent, session_service=ss)
705+
runner = create_runner(app_name=agent.name, node=agent, session_service=ss)
722706
session = await ss.create_session(app_name=agent.name, user_id='u')
723707
msg = types.Content(parts=[types.Part(text='start')], role='user')
724708

@@ -926,7 +910,7 @@ async def test_node_fails_immediately_on_unmatched_exception_class(
926910
)
927911

928912
ss = InMemorySessionService()
929-
runner = Runner(app_name=agent.name, node=agent, session_service=ss)
913+
runner = create_runner(app_name=agent.name, node=agent, session_service=ss)
930914
session = await ss.create_session(app_name=agent.name, user_id='u')
931915
msg = types.Content(parts=[types.Part(text='start')], role='user')
932916
events = []
@@ -995,7 +979,7 @@ async def test_error_event_emitted_on_failure(
995979
)
996980

997981
ss = InMemorySessionService()
998-
runner = Runner(app_name=agent.name, node=agent, session_service=ss)
982+
runner = create_runner(app_name=agent.name, node=agent, session_service=ss)
999983
session = await ss.create_session(app_name=agent.name, user_id='u')
1000984
msg = types.Content(parts=[types.Part(text='start')], role='user')
1001985
events = []
@@ -1047,7 +1031,7 @@ async def test_error_event_emitted_on_each_retry(
10471031
)
10481032

10491033
ss = InMemorySessionService()
1050-
runner = Runner(app_name=agent.name, node=agent, session_service=ss)
1034+
runner = create_runner(app_name=agent.name, node=agent, session_service=ss)
10511035
session = await ss.create_session(app_name=agent.name, user_id='u')
10521036
msg = types.Content(parts=[types.Part(text='start')], role='user')
10531037
events = []

‎tests/unittests/workflow/test_workflow_agent_as_node.py‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,14 @@
2020
from google.adk.agents.context import Context
2121
from google.adk.agents.invocation_context import InvocationContext as BaseInvocationContext
2222
from google.adk.events.event import Event
23-
from google.adk.runners import Runner
2423
from google.adk.sessions.in_memory_session_service import InMemorySessionService
2524
from google.adk.sessions.session import Session
2625
from google.adk.workflow import START
2726
from google.adk.workflow._workflow import Workflow
2827
from google.genai import types
2928
import pytest
3029

30+
from .workflow_testing_utils import create_runner
3131
from .workflow_testing_utils import InputCapturingNode
3232
from .workflow_testing_utils import simplify_events_with_node
3333

@@ -97,7 +97,7 @@ async def test_run_async_with_agent_nodes(request: pytest.FixtureRequest):
9797
],
9898
)
9999
ss = InMemorySessionService()
100-
runner = Runner(app_name='test', node=wf, session_service=ss)
100+
runner = create_runner(app_name='test', node=wf, session_service=ss)
101101
session = await ss.create_session(app_name='test', user_id='u')
102102

103103
msg = types.Content(parts=[types.Part(text='start')], role='user')
@@ -128,7 +128,7 @@ async def test_run_async_with_agent_node_piping_data(
128128
],
129129
)
130130
ss = InMemorySessionService()
131-
runner = Runner(app_name='test', node=wf, session_service=ss)
131+
runner = create_runner(app_name='test', node=wf, session_service=ss)
132132
session = await ss.create_session(app_name='test', user_id='u')
133133

134134
msg = types.Content(parts=[types.Part(text='start')], role='user')

0 commit comments

Comments
 (0)