Skip to content

Commit 198b30e

Browse files
committed
test(interactions): Make integration assertions compatible with google-genai 2.x.
Signed-off-by: Sébastien Han <seb@redhat.com>
1 parent 211106a commit 198b30e

1 file changed

Lines changed: 70 additions & 44 deletions

File tree

tests/integration/interactions/test_interactions.py

Lines changed: 70 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,31 @@ def _suppress_experimental_warning():
2727
def _get_text_output(interaction):
2828
"""Extract the first text output, skipping any thought content."""
2929
for output in interaction.outputs:
30-
if output.type == "text":
30+
if _get_field(output, "type") == "text":
3131
return output
3232
return None
3333

3434

35+
def _get_field(value, key, default=None):
36+
"""Get a field from either an SDK object or a dict payload."""
37+
if isinstance(value, dict):
38+
return value.get(key, default)
39+
return getattr(value, key, default)
40+
41+
42+
def _get_event_type(event):
43+
"""Get a canonical event type string across google-genai versions."""
44+
return _get_field(event, "event_type", type(event).__name__)
45+
46+
47+
def _get_content_delta_text(event):
48+
"""Extract text from a content.delta event for both SDK object styles."""
49+
delta = _get_field(event, "delta")
50+
if delta is None:
51+
return None
52+
return _get_field(delta, "text")
53+
54+
3555
def test_interactions_non_streaming_basic(genai_client, text_model_id):
3656
"""Basic non-streaming interaction returns a valid Google Interactions response."""
3757
interaction = genai_client.interactions.create(
@@ -43,8 +63,10 @@ def test_interactions_non_streaming_basic(genai_client, text_model_id):
4363
assert interaction.status == "completed", f"Status should be 'completed', got: {interaction.status}"
4464
assert len(interaction.outputs) > 0, "Expected at least one output"
4565
text_output = _get_text_output(interaction)
46-
assert text_output is not None, f"Expected a text output, got types: {[o.type for o in interaction.outputs]}"
47-
assert len(text_output.text) > 0
66+
assert text_output is not None, (
67+
f"Expected a text output, got types: {[_get_field(o, 'type') for o in interaction.outputs]}"
68+
)
69+
assert len(_get_field(text_output, "text", "")) > 0
4870
assert interaction.usage.total_input_tokens > 0
4971
assert interaction.usage.total_output_tokens > 0
5072
assert (
@@ -64,7 +86,7 @@ def test_interactions_non_streaming_system_instruction(genai_client, text_model_
6486
assert len(interaction.outputs) > 0
6587
text_output = _get_text_output(interaction)
6688
assert text_output is not None
67-
assert len(text_output.text) > 0
89+
assert len(_get_field(text_output, "text", "")) > 0
6890

6991

7092
def test_interactions_non_streaming_multi_turn(genai_client, text_model_id):
@@ -82,7 +104,7 @@ def test_interactions_non_streaming_multi_turn(genai_client, text_model_id):
82104
assert len(interaction.outputs) > 0
83105
text_output = _get_text_output(interaction)
84106
assert text_output is not None
85-
assert "alice" in text_output.text.lower()
107+
assert "alice" in _get_field(text_output, "text", "").lower()
86108

87109

88110
def test_interactions_non_streaming_generation_config(genai_client, text_model_id):
@@ -100,7 +122,7 @@ def test_interactions_non_streaming_generation_config(genai_client, text_model_i
100122
assert len(interaction.outputs) > 0
101123
text_output = _get_text_output(interaction)
102124
assert text_output is not None
103-
assert len(text_output.text) > 0
125+
assert len(_get_field(text_output, "text", "")) > 0
104126

105127

106128
def test_interactions_non_streaming_response_shape(genai_client, text_model_id):
@@ -131,25 +153,28 @@ def test_interactions_streaming_basic(genai_client, text_model_id):
131153
interaction_id = None
132154

133155
for event in stream:
134-
event_name = type(event).__name__
135-
event_types.append(event_name)
156+
event_type = _get_event_type(event)
157+
event_types.append(event_type)
136158

137-
if event_name == "InteractionStartEvent" and hasattr(event, "interaction") and event.interaction:
138-
interaction_id = event.interaction.id
159+
if event_type == "interaction.start":
160+
interaction = _get_field(event, "interaction")
161+
interaction_id = _get_field(interaction, "id")
139162

140-
if event_name == "ContentDelta" and hasattr(event, "delta") and event.delta and hasattr(event.delta, "text"):
141-
text_parts.append(event.delta.text)
163+
if event_type == "content.delta":
164+
text = _get_content_delta_text(event)
165+
if text:
166+
text_parts.append(text)
142167

143168
full_text = "".join(text_parts)
144169
assert len(full_text) > 0, "Streaming should produce text"
145170
assert interaction_id is not None, "Should have received an interaction ID"
146171

147172
# Verify event sequence contains expected types
148-
assert "InteractionStartEvent" in event_types
149-
assert "ContentStart" in event_types
150-
assert "ContentDelta" in event_types
151-
assert "ContentStop" in event_types
152-
assert "InteractionCompleteEvent" in event_types
173+
assert "interaction.start" in event_types
174+
assert "content.start" in event_types
175+
assert "content.delta" in event_types
176+
assert "content.stop" in event_types
177+
assert "interaction.complete" in event_types
153178

154179

155180
def test_interactions_streaming_text_concatenation(genai_client, text_model_id):
@@ -162,9 +187,10 @@ def test_interactions_streaming_text_concatenation(genai_client, text_model_id):
162187

163188
text_parts = []
164189
for event in stream:
165-
if type(event).__name__ == "ContentDelta" and hasattr(event, "delta") and event.delta:
166-
if hasattr(event.delta, "text"):
167-
text_parts.append(event.delta.text)
190+
if _get_event_type(event) == "content.delta":
191+
text = _get_content_delta_text(event)
192+
if text:
193+
text_parts.append(text)
168194

169195
full_text = "".join(text_parts)
170196
assert len(full_text) > 0
@@ -179,23 +205,21 @@ def test_interactions_streaming_event_order(genai_client, text_model_id):
179205
)
180206

181207
events = list(stream)
182-
event_names = [type(e).__name__ for e in events]
183-
assert len(events) >= 4, f"Expected at least 4 events, got {len(events)}: {event_names}"
208+
event_types = [_get_event_type(e) for e in events]
209+
assert len(events) >= 4, f"Expected at least 4 events, got {len(events)}: {event_types}"
184210

185211
# Verify all required event types are present
186-
required = ["InteractionStartEvent", "ContentStart", "ContentDelta", "ContentStop", "InteractionCompleteEvent"]
212+
required = ["interaction.start", "content.start", "content.delta", "content.stop", "interaction.complete"]
187213
for req in required:
188-
assert req in event_names, f"Missing required event type {req}, got: {event_names}"
214+
assert req in event_types, f"Missing required event type {req}, got: {event_types}"
189215

190216
# Verify relative ordering: start before content, content before complete
191217
def _first(name):
192-
return event_names.index(name)
218+
return event_types.index(name)
193219

194-
assert _first("InteractionStartEvent") < _first("ContentStart"), "InteractionStartEvent should precede ContentStart"
195-
assert _first("ContentStart") < _first("ContentDelta"), "ContentStart should precede ContentDelta"
196-
assert _first("ContentStop") < _first("InteractionCompleteEvent"), (
197-
"ContentStop should precede InteractionCompleteEvent"
198-
)
220+
assert _first("interaction.start") < _first("content.start"), "interaction.start should precede content.start"
221+
assert _first("content.start") < _first("content.delta"), "content.start should precede content.delta"
222+
assert _first("content.stop") < _first("interaction.complete"), "content.stop should precede interaction.complete"
199223

200224

201225
def test_interactions_tool_calling_function_call_output(genai_client, text_model_id):
@@ -226,15 +250,15 @@ def test_interactions_tool_calling_function_call_output(genai_client, text_model
226250
assert len(interaction.outputs) > 0
227251

228252
# Model should produce a function_call output
229-
function_calls = [o for o in interaction.outputs if o.type == "function_call"]
253+
function_calls = [o for o in interaction.outputs if _get_field(o, "type") == "function_call"]
230254
if not function_calls:
231255
pytest.skip("Model answered directly without calling the tool")
232256

233257
fc = function_calls[0]
234-
assert fc.name == "get_weather"
235-
assert fc.id is not None
258+
assert _get_field(fc, "name") == "get_weather"
259+
assert _get_field(fc, "id") is not None
236260
# SDK uses 'arguments' attribute for function call args
237-
fc_args = getattr(fc, "arguments", None) or getattr(fc, "args", None) or {}
261+
fc_args = _get_field(fc, "arguments") or _get_field(fc, "args") or {}
238262
assert isinstance(fc_args, dict)
239263

240264

@@ -269,12 +293,14 @@ def test_interactions_tool_calling_round_trip(genai_client, text_model_id):
269293
],
270294
)
271295

272-
function_calls = [o for o in interaction.outputs if o.type == "function_call"]
296+
function_calls = [o for o in interaction.outputs if _get_field(o, "type") == "function_call"]
273297
if not function_calls:
274298
pytest.skip("Model answered directly without calling the tool")
275299

276300
fc = function_calls[0]
277-
fc_args = getattr(fc, "arguments", None) or getattr(fc, "args", None) or {}
301+
fc_args = _get_field(fc, "arguments") or _get_field(fc, "args") or {}
302+
fc_id = _get_field(fc, "id")
303+
fc_name = _get_field(fc, "name")
278304

279305
# Step 2: Send function_response and get a final text answer
280306
interaction2 = genai_client.interactions.create(
@@ -286,8 +312,8 @@ def test_interactions_tool_calling_round_trip(genai_client, text_model_id):
286312
"content": [
287313
{
288314
"type": "function_call",
289-
"id": fc.id,
290-
"name": fc.name,
315+
"id": fc_id,
316+
"name": fc_name,
291317
"arguments": fc_args,
292318
}
293319
],
@@ -297,8 +323,8 @@ def test_interactions_tool_calling_round_trip(genai_client, text_model_id):
297323
"content": [
298324
{
299325
"type": "function_result",
300-
"call_id": fc.id,
301-
"name": fc.name,
326+
"call_id": fc_id,
327+
"name": fc_name,
302328
"result": {"temperature_celsius": 22, "condition": "Cloudy"},
303329
}
304330
],
@@ -324,7 +350,7 @@ def test_interactions_tool_calling_round_trip(genai_client, text_model_id):
324350
)
325351

326352
assert interaction2.status == "completed"
327-
text_outputs = [o for o in interaction2.outputs if o.type == "text"]
353+
text_outputs = [o for o in interaction2.outputs if _get_field(o, "type") == "text"]
328354
assert len(text_outputs) > 0, "Expected a text response after providing function result"
329355

330356

@@ -366,10 +392,10 @@ def test_interactions_tool_calling_multiple_tools(genai_client, text_model_id):
366392
assert interaction.status in ("completed", "requires_action")
367393
assert len(interaction.outputs) > 0
368394

369-
function_calls = [o for o in interaction.outputs if o.type == "function_call"]
395+
function_calls = [o for o in interaction.outputs if _get_field(o, "type") == "function_call"]
370396
if function_calls:
371397
# If the model called a tool, it should have picked get_time
372-
assert function_calls[0].name == "get_time"
398+
assert _get_field(function_calls[0], "name") == "get_time"
373399

374400

375401
def test_interactions_no_tools_no_function_call(genai_client, text_model_id):
@@ -380,7 +406,7 @@ def test_interactions_no_tools_no_function_call(genai_client, text_model_id):
380406
)
381407

382408
assert interaction.status == "completed"
383-
function_calls = [o for o in interaction.outputs if o.type == "function_call"]
409+
function_calls = [o for o in interaction.outputs if _get_field(o, "type") == "function_call"]
384410
assert len(function_calls) == 0, "Should not produce function_call without tools"
385411

386412

0 commit comments

Comments
 (0)