Skip to content

Commit 138a868

Browse files
test(openai): Replace mocks with httpx types for streaming Responses
1 parent 2dad6dc commit 138a868

File tree

1 file changed

+107
-65
lines changed

1 file changed

+107
-65
lines changed

tests/integrations/openai/test_openai.py

Lines changed: 107 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
SKIP_RESPONSES_TESTS = True
4242

4343
from sentry_sdk import start_transaction
44-
from sentry_sdk.consts import SPANDATA
44+
from sentry_sdk.consts import SPANDATA, OP
4545
from sentry_sdk.integrations.openai import (
4646
OpenAIIntegration,
4747
_calculate_token_usage,
@@ -2553,7 +2553,14 @@ async def test_ai_client_span_responses_async_api(
25532553
)
25542554
@pytest.mark.skipif(SKIP_RESPONSES_TESTS, reason="Responses API not available")
25552555
async def test_ai_client_span_streaming_responses_async_api(
2556-
sentry_init, capture_events, instructions, input, request, async_iterator
2556+
sentry_init,
2557+
capture_events,
2558+
instructions,
2559+
input,
2560+
request,
2561+
get_model_response,
2562+
async_iterator,
2563+
server_side_event_chunks,
25572564
):
25582565
sentry_init(
25592566
integrations=[OpenAIIntegration(include_prompts=True)],
@@ -2563,25 +2570,30 @@ async def test_ai_client_span_streaming_responses_async_api(
25632570
events = capture_events()
25642571

25652572
client = AsyncOpenAI(api_key="z")
2566-
returned_stream = AsyncStream(cast_to=None, response=None, client=client)
2567-
returned_stream._iterator = async_iterator(EXAMPLE_RESPONSES_STREAM)
2568-
client.responses._post = mock.AsyncMock(return_value=returned_stream)
2573+
returned_stream = get_model_response(
2574+
async_iterator(server_side_event_chunks(EXAMPLE_RESPONSES_STREAM))
2575+
)
25692576

2570-
with start_transaction(name="openai tx"):
2571-
result = await client.responses.create(
2572-
model="gpt-4o",
2573-
instructions=instructions,
2574-
input=input,
2575-
stream=True,
2576-
max_output_tokens=100,
2577-
temperature=0.7,
2578-
top_p=0.9,
2579-
)
2580-
async for _ in result:
2581-
pass
2577+
with mock.patch.object(
2578+
client.chat._client._client,
2579+
"send",
2580+
return_value=returned_stream,
2581+
):
2582+
with start_transaction(name="openai tx"):
2583+
result = await client.responses.create(
2584+
model="gpt-4o",
2585+
instructions=instructions,
2586+
input=input,
2587+
stream=True,
2588+
max_output_tokens=100,
2589+
temperature=0.7,
2590+
top_p=0.9,
2591+
)
2592+
async for _ in result:
2593+
pass
25822594

25832595
(transaction,) = events
2584-
spans = transaction["spans"]
2596+
spans = [span for span in transaction["spans"] if span["op"] == OP.GEN_AI_RESPONSES]
25852597

25862598
assert len(spans) == 1
25872599
assert spans[0]["op"] == "gen_ai.responses"
@@ -2881,7 +2893,12 @@ async def test_error_in_responses_async_api(sentry_init, capture_events):
28812893
)
28822894
@pytest.mark.skipif(SKIP_RESPONSES_TESTS, reason="Responses API not available")
28832895
def test_streaming_responses_api(
2884-
sentry_init, capture_events, send_default_pii, include_prompts
2896+
sentry_init,
2897+
capture_events,
2898+
send_default_pii,
2899+
include_prompts,
2900+
get_model_response,
2901+
server_side_event_chunks,
28852902
):
28862903
sentry_init(
28872904
integrations=[
@@ -2895,24 +2912,31 @@ def test_streaming_responses_api(
28952912
events = capture_events()
28962913

28972914
client = OpenAI(api_key="z")
2898-
returned_stream = Stream(cast_to=None, response=None, client=client)
2899-
returned_stream._iterator = EXAMPLE_RESPONSES_STREAM
2900-
client.responses._post = mock.Mock(return_value=returned_stream)
2901-
2902-
with start_transaction(name="openai tx"):
2903-
response_stream = client.responses.create(
2904-
model="some-model",
2905-
input="hello",
2906-
stream=True,
2907-
max_output_tokens=100,
2908-
temperature=0.7,
2909-
top_p=0.9,
2915+
returned_stream = get_model_response(
2916+
server_side_event_chunks(
2917+
EXAMPLE_RESPONSES_STREAM,
29102918
)
2919+
)
29112920

2912-
response_string = ""
2913-
for item in response_stream:
2914-
if hasattr(item, "delta"):
2915-
response_string += item.delta
2921+
with mock.patch.object(
2922+
client.chat._client._client,
2923+
"send",
2924+
return_value=returned_stream,
2925+
):
2926+
with start_transaction(name="openai tx"):
2927+
response_stream = client.responses.create(
2928+
model="some-model",
2929+
input="hello",
2930+
stream=True,
2931+
max_output_tokens=100,
2932+
temperature=0.7,
2933+
top_p=0.9,
2934+
)
2935+
2936+
response_string = ""
2937+
for item in response_stream:
2938+
if hasattr(item, "delta"):
2939+
response_string += item.delta
29162940

29172941
assert response_string == "hello world"
29182942

@@ -2945,7 +2969,13 @@ def test_streaming_responses_api(
29452969
)
29462970
@pytest.mark.skipif(SKIP_RESPONSES_TESTS, reason="Responses API not available")
29472971
async def test_streaming_responses_api_async(
2948-
sentry_init, capture_events, send_default_pii, include_prompts, async_iterator
2972+
sentry_init,
2973+
capture_events,
2974+
send_default_pii,
2975+
include_prompts,
2976+
get_model_response,
2977+
async_iterator,
2978+
server_side_event_chunks,
29492979
):
29502980
sentry_init(
29512981
integrations=[
@@ -2959,24 +2989,29 @@ async def test_streaming_responses_api_async(
29592989
events = capture_events()
29602990

29612991
client = AsyncOpenAI(api_key="z")
2962-
returned_stream = AsyncStream(cast_to=None, response=None, client=client)
2963-
returned_stream._iterator = async_iterator(EXAMPLE_RESPONSES_STREAM)
2964-
client.responses._post = AsyncMock(return_value=returned_stream)
2992+
returned_stream = get_model_response(
2993+
async_iterator(server_side_event_chunks(EXAMPLE_RESPONSES_STREAM))
2994+
)
29652995

2966-
with start_transaction(name="openai tx"):
2967-
response_stream = await client.responses.create(
2968-
model="some-model",
2969-
input="hello",
2970-
stream=True,
2971-
max_output_tokens=100,
2972-
temperature=0.7,
2973-
top_p=0.9,
2974-
)
2996+
with mock.patch.object(
2997+
client.chat._client._client,
2998+
"send",
2999+
return_value=returned_stream,
3000+
):
3001+
with start_transaction(name="openai tx"):
3002+
response_stream = await client.responses.create(
3003+
model="some-model",
3004+
input="hello",
3005+
stream=True,
3006+
max_output_tokens=100,
3007+
temperature=0.7,
3008+
top_p=0.9,
3009+
)
29753010

2976-
response_string = ""
2977-
async for item in response_stream:
2978-
if hasattr(item, "delta"):
2979-
response_string += item.delta
3011+
response_string = ""
3012+
async for item in response_stream:
3013+
if hasattr(item, "delta"):
3014+
response_string += item.delta
29803015

29813016
assert response_string == "hello world"
29823017

@@ -3258,7 +3293,9 @@ async def test_streaming_chat_completion_ttft_async(
32583293

32593294
# noinspection PyTypeChecker
32603295
@pytest.mark.skipif(SKIP_RESPONSES_TESTS, reason="Responses API not available")
3261-
def test_streaming_responses_api_ttft(sentry_init, capture_events):
3296+
def test_streaming_responses_api_ttft(
3297+
sentry_init, capture_events, get_model_response, server_side_event_chunks
3298+
):
32623299
"""
32633300
Test that streaming responses API captures time-to-first-token (TTFT).
32643301
"""
@@ -3269,19 +3306,24 @@ def test_streaming_responses_api_ttft(sentry_init, capture_events):
32693306
events = capture_events()
32703307

32713308
client = OpenAI(api_key="z")
3272-
returned_stream = Stream(cast_to=None, response=None, client=client)
3273-
returned_stream._iterator = EXAMPLE_RESPONSES_STREAM
3274-
client.responses._post = mock.Mock(return_value=returned_stream)
3309+
returned_stream = get_model_response(
3310+
server_side_event_chunks(EXAMPLE_RESPONSES_STREAM)
3311+
)
32753312

3276-
with start_transaction(name="openai tx"):
3277-
response_stream = client.responses.create(
3278-
model="some-model",
3279-
input="hello",
3280-
stream=True,
3281-
)
3282-
# Consume the stream
3283-
for _ in response_stream:
3284-
pass
3313+
with mock.patch.object(
3314+
client.chat._client._client,
3315+
"send",
3316+
return_value=returned_stream,
3317+
):
3318+
with start_transaction(name="openai tx"):
3319+
response_stream = client.responses.create(
3320+
model="some-model",
3321+
input="hello",
3322+
stream=True,
3323+
)
3324+
# Consume the stream
3325+
for _ in response_stream:
3326+
pass
32853327

32863328
(tx,) = events
32873329
span = tx["spans"][0]

0 commit comments

Comments
 (0)