Skip to content

Commit e625f51

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 4306662 commit e625f51

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
@@ -24,7 +24,6 @@
2424
from google.adk.events.event import Event
2525
from google.adk.events.event_actions import EventActions
2626
from google.adk.events.ui_widget import UiWidget
27-
from google.adk.flows.llm_flows.functions import deep_merge_dicts
2827
from google.adk.flows.llm_flows.functions import find_matching_function_call
2928
from google.adk.flows.llm_flows.functions import handle_function_calls_async
3029
from google.adk.flows.llm_flows.functions import handle_function_calls_live
@@ -1865,73 +1864,3 @@ async def slow_fn_2() -> dict[str, str]:
18651864

18661865
await asyncio.sleep(0)
18671866
assert len(invocation_context.active_non_blocking_tool_tasks) == 0
1868-
1869-
1870-
def test_deep_merge_dicts_concatenates_lists():
1871-
"""Test that deep_merge_dicts concatenates list values instead of overwriting."""
1872-
d1 = {"state_delta": {"items": ["a"]}}
1873-
d2 = {"state_delta": {"items": ["b"]}}
1874-
result = deep_merge_dicts(d1, d2)
1875-
assert result["state_delta"]["items"] == ["a", "b"]
1876-
1877-
1878-
def test_deep_merge_dicts_overwrites_non_list_non_dict():
1879-
"""Test that deep_merge_dicts still overwrites scalar values."""
1880-
d1 = {"key": "old"}
1881-
d2 = {"key": "new"}
1882-
result = deep_merge_dicts(d1, d2)
1883-
assert result["key"] == "new"
1884-
1885-
1886-
def test_deep_merge_dicts_merges_nested_dicts():
1887-
"""Test that deep_merge_dicts recursively merges nested dicts."""
1888-
d1 = {"a": {"b": 1, "c": 2}}
1889-
d2 = {"a": {"b": 3, "d": 4}}
1890-
result = deep_merge_dicts(d1, d2)
1891-
assert result == {"a": {"b": 3, "c": 2, "d": 4}}
1892-
1893-
1894-
def test_deep_merge_dicts_handles_mixed_list_and_non_list():
1895-
"""Test that deep_merge_dicts overwrites when types differ (list vs non-list)."""
1896-
d1 = {"key": "not_a_list"}
1897-
d2 = {"key": ["a", "b"]}
1898-
result = deep_merge_dicts(d1, d2)
1899-
assert result["key"] == ["a", "b"]
1900-
1901-
d1 = {"key": ["a", "b"]}
1902-
d2 = {"key": "not_a_list"}
1903-
result = deep_merge_dicts(d1, d2)
1904-
assert result["key"] == "not_a_list"
1905-
1906-
1907-
def test_merge_parallel_function_response_events_merges_state_delta_lists():
1908-
"""Test that parallel events with list state_delta values are concatenated, not overwritten."""
1909-
invocation_id = "base_invocation_123"
1910-
1911-
event1 = Event(
1912-
invocation_id=invocation_id,
1913-
author="tool",
1914-
content=types.Content(
1915-
role="user",
1916-
parts=[types.Part(function_response=types.FunctionResponse(
1917-
name="func_1", response={"result": "ok"},
1918-
))],
1919-
),
1920-
actions=EventActions(state_delta={"items": ["a"]}),
1921-
)
1922-
1923-
event2 = Event(
1924-
invocation_id=invocation_id,
1925-
author="tool",
1926-
content=types.Content(
1927-
role="user",
1928-
parts=[types.Part(function_response=types.FunctionResponse(
1929-
name="func_2", response={"result": "ok"},
1930-
))],
1931-
),
1932-
actions=EventActions(state_delta={"items": ["b"]}),
1933-
)
1934-
1935-
merged_event = merge_parallel_function_response_events([event1, event2])
1936-
1937-
assert merged_event.actions.state_delta == {"items": ["a", "b"]}

0 commit comments

Comments
 (0)