Skip to content

Commit 4b3db55

Browse files
committed
refactor: move deep_merge_dicts and state_delta list tests to test_functions_parallel
Move tests for deep_merge_dicts and merge_parallel_function_response_events with list state_delta merging from test_functions_simple.py to test_functions_parallel.py per reviewer feedback.
1 parent e3a480a commit 4b3db55

2 files changed

Lines changed: 83 additions & 71 deletions

File tree

tests/unittests/flows/llm_flows/test_functions_parallel.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@
1313
# limitations under the License.
1414

1515
from google.adk.agents.llm_agent import Agent
16+
from google.adk.events.event import Event
1617
from google.adk.events.event_actions import EventActions
18+
from google.adk.flows.llm_flows.functions import deep_merge_dicts
19+
from google.adk.flows.llm_flows.functions import merge_parallel_function_response_events
1720
from google.adk.tools.tool_context import ToolContext
1821
from google.genai import types
1922
import pytest
@@ -105,3 +108,83 @@ async def transfer_to_agent(
105108
},
106109
transfer_to_agent='test_sub_agent',
107110
)
111+
112+
113+
def test_deep_merge_dicts_concatenates_lists():
114+
"""Test that deep_merge_dicts concatenates list values instead of overwriting."""
115+
d1 = {'state_delta': {'items': ['a']}}
116+
d2 = {'state_delta': {'items': ['b']}}
117+
result = deep_merge_dicts(d1, d2)
118+
assert result['state_delta']['items'] == ['a', 'b']
119+
120+
121+
def test_deep_merge_dicts_overwrites_non_list_non_dict():
122+
"""Test that deep_merge_dicts still overwrites scalar values."""
123+
d1 = {'key': 'old'}
124+
d2 = {'key': 'new'}
125+
result = deep_merge_dicts(d1, d2)
126+
assert result['key'] == 'new'
127+
128+
129+
def test_deep_merge_dicts_merges_nested_dicts():
130+
"""Test that deep_merge_dicts recursively merges nested dicts."""
131+
d1 = {'a': {'b': 1, 'c': 2}}
132+
d2 = {'a': {'b': 3, 'd': 4}}
133+
result = deep_merge_dicts(d1, d2)
134+
assert result == {'a': {'b': 3, 'c': 2, 'd': 4}}
135+
136+
137+
def test_deep_merge_dicts_handles_mixed_list_and_non_list():
138+
"""Test that deep_merge_dicts overwrites when types differ (list vs non-list)."""
139+
d1 = {'key': 'not_a_list'}
140+
d2 = {'key': ['a', 'b']}
141+
result = deep_merge_dicts(d1, d2)
142+
assert result['key'] == ['a', 'b']
143+
144+
d1 = {'key': ['a', 'b']}
145+
d2 = {'key': 'not_a_list'}
146+
result = deep_merge_dicts(d1, d2)
147+
assert result['key'] == 'not_a_list'
148+
149+
150+
def test_merge_parallel_function_response_events_merges_state_delta_lists():
151+
"""Test that parallel events with list state_delta values are concatenated, not overwritten."""
152+
invocation_id = 'base_invocation_123'
153+
154+
event1 = Event(
155+
invocation_id=invocation_id,
156+
author='tool',
157+
content=types.Content(
158+
role='user',
159+
parts=[
160+
types.Part(
161+
function_response=types.FunctionResponse(
162+
name='func_1',
163+
response={'result': 'ok'},
164+
)
165+
)
166+
],
167+
),
168+
actions=EventActions(state_delta={'items': ['a']}),
169+
)
170+
171+
event2 = Event(
172+
invocation_id=invocation_id,
173+
author='tool',
174+
content=types.Content(
175+
role='user',
176+
parts=[
177+
types.Part(
178+
function_response=types.FunctionResponse(
179+
name='func_2',
180+
response={'result': 'ok'},
181+
)
182+
)
183+
],
184+
),
185+
actions=EventActions(state_delta={'items': ['b']}),
186+
)
187+
188+
merged_event = merge_parallel_function_response_events([event1, event2])
189+
190+
assert merged_event.actions.state_delta == {'items': ['a', 'b']}

tests/unittests/flows/llm_flows/test_functions_simple.py

Lines changed: 0 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
from google.adk.flows.llm_flows.functions import find_matching_function_call
2424
from google.adk.flows.llm_flows.functions import handle_function_calls_async
2525
from google.adk.flows.llm_flows.functions import handle_function_calls_live
26-
from google.adk.flows.llm_flows.functions import deep_merge_dicts
2726
from google.adk.flows.llm_flows.functions import merge_parallel_function_response_events
2827
from google.adk.tools.computer_use.computer_use_tool import ComputerUseTool
2928
from google.adk.tools.function_tool import FunctionTool
@@ -1237,73 +1236,3 @@ async def mock_run(*args, **kwargs):
12371236
# Verify the image was converted to a blob
12381237
assert len(response_part.parts) == 1
12391238
assert response_part.parts[0].inline_data is not None
1240-
1241-
1242-
def test_deep_merge_dicts_concatenates_lists():
1243-
"""Test that deep_merge_dicts concatenates list values instead of overwriting."""
1244-
d1 = {"state_delta": {"items": ["a"]}}
1245-
d2 = {"state_delta": {"items": ["b"]}}
1246-
result = deep_merge_dicts(d1, d2)
1247-
assert result["state_delta"]["items"] == ["a", "b"]
1248-
1249-
1250-
def test_deep_merge_dicts_overwrites_non_list_non_dict():
1251-
"""Test that deep_merge_dicts still overwrites scalar values."""
1252-
d1 = {"key": "old"}
1253-
d2 = {"key": "new"}
1254-
result = deep_merge_dicts(d1, d2)
1255-
assert result["key"] == "new"
1256-
1257-
1258-
def test_deep_merge_dicts_merges_nested_dicts():
1259-
"""Test that deep_merge_dicts recursively merges nested dicts."""
1260-
d1 = {"a": {"b": 1, "c": 2}}
1261-
d2 = {"a": {"b": 3, "d": 4}}
1262-
result = deep_merge_dicts(d1, d2)
1263-
assert result == {"a": {"b": 3, "c": 2, "d": 4}}
1264-
1265-
1266-
def test_deep_merge_dicts_handles_mixed_list_and_non_list():
1267-
"""Test that deep_merge_dicts overwrites when types differ (list vs non-list)."""
1268-
d1 = {"key": "not_a_list"}
1269-
d2 = {"key": ["a", "b"]}
1270-
result = deep_merge_dicts(d1, d2)
1271-
assert result["key"] == ["a", "b"]
1272-
1273-
d1 = {"key": ["a", "b"]}
1274-
d2 = {"key": "not_a_list"}
1275-
result = deep_merge_dicts(d1, d2)
1276-
assert result["key"] == "not_a_list"
1277-
1278-
1279-
def test_merge_parallel_function_response_events_merges_state_delta_lists():
1280-
"""Test that parallel events with list state_delta values are concatenated, not overwritten."""
1281-
invocation_id = "base_invocation_123"
1282-
1283-
event1 = Event(
1284-
invocation_id=invocation_id,
1285-
author="tool",
1286-
content=types.Content(
1287-
role="user",
1288-
parts=[types.Part(function_response=types.FunctionResponse(
1289-
name="func_1", response={"result": "ok"},
1290-
))],
1291-
),
1292-
actions=EventActions(state_delta={"items": ["a"]}),
1293-
)
1294-
1295-
event2 = Event(
1296-
invocation_id=invocation_id,
1297-
author="tool",
1298-
content=types.Content(
1299-
role="user",
1300-
parts=[types.Part(function_response=types.FunctionResponse(
1301-
name="func_2", response={"result": "ok"},
1302-
))],
1303-
),
1304-
actions=EventActions(state_delta={"items": ["b"]}),
1305-
)
1306-
1307-
merged_event = merge_parallel_function_response_events([event1, event2])
1308-
1309-
assert merged_event.actions.state_delta == {"items": ["a", "b"]}

0 commit comments

Comments
 (0)