Skip to content

Commit 4abb01f

Browse files
authored
tests: Move streaming decorator tests (#6695)
### Description Moving streaming `@trace` decorator tests from `test_span_streaming` to `test_decorator` and adapting existing tests to also test the streamed variant if applicable. #### Issues - Part of #5395 #### Reminders - Please add tests to validate your changes, and lint your code using `uv run ruff`. - Add GH Issue ID _&_ Linear ID (if applicable) - PR title should use [conventional commit](https://develop.sentry.dev/engineering-practices/commit-messages/#type) style (`feat:`, `fix:`, `ref:`, `meta:`) - For external contributors: [CONTRIBUTING.md](https://github.com/getsentry/sentry-python/blob/master/CONTRIBUTING.md), [Sentry SDK development docs](https://develop.sentry.dev/sdk/), [Discord community](https://discord.gg/Ww9hbqr)
1 parent 291739f commit 4abb01f

2 files changed

Lines changed: 257 additions & 161 deletions

File tree

tests/tracing/test_decorator.py

Lines changed: 257 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
import sentry_sdk
77
from sentry_sdk.consts import SPANTEMPLATE
8-
from sentry_sdk.tracing import trace
98
from sentry_sdk.tracing_utils import create_span_decorator
109
from sentry_sdk.utils import logger
1110
from tests.conftest import patch_start_tracing_child
@@ -86,6 +85,246 @@ async def test_trace_decorator_async_no_trx():
8685
assert result2 == "return_of_async_function"
8786

8887

88+
def test_trace_decorator_span_streaming(sentry_init, capture_items):
89+
sentry_init(
90+
traces_sample_rate=1.0,
91+
_experiments={"trace_lifecycle": "stream"},
92+
)
93+
94+
items = capture_items("span")
95+
96+
@sentry_sdk.traces.trace
97+
def traced_function():
98+
return "ok"
99+
100+
result = traced_function()
101+
assert result == "ok"
102+
103+
sentry_sdk.get_client().flush()
104+
spans = [item.payload for item in items]
105+
106+
assert len(spans) == 1
107+
(span,) = spans
108+
109+
assert (
110+
span["name"]
111+
== "test_decorator.test_trace_decorator_span_streaming.<locals>.traced_function"
112+
)
113+
assert span["status"] == "ok"
114+
115+
116+
def test_trace_decorator_arguments_span_streaming(sentry_init, capture_items):
117+
sentry_init(
118+
traces_sample_rate=1.0,
119+
_experiments={"trace_lifecycle": "stream"},
120+
)
121+
122+
items = capture_items("span")
123+
124+
@sentry_sdk.traces.trace(name="traced", attributes={"traced.attribute": 123})
125+
def traced_function():
126+
return "ok"
127+
128+
result = traced_function()
129+
assert result == "ok"
130+
131+
sentry_sdk.get_client().flush()
132+
spans = [item.payload for item in items]
133+
134+
assert len(spans) == 1
135+
(span,) = spans
136+
137+
assert span["name"] == "traced"
138+
assert span["attributes"]["traced.attribute"] == 123
139+
assert span["status"] == "ok"
140+
141+
142+
def test_trace_decorator_inactive_span_streaming(sentry_init, capture_items):
143+
sentry_init(
144+
traces_sample_rate=1.0,
145+
_experiments={"trace_lifecycle": "stream"},
146+
)
147+
148+
items = capture_items("span")
149+
150+
@sentry_sdk.traces.trace(name="outer", active=False)
151+
def traced_function():
152+
with sentry_sdk.traces.start_span(name="inner"):
153+
return "ok"
154+
155+
result = traced_function()
156+
assert result == "ok"
157+
158+
sentry_sdk.get_client().flush()
159+
spans = [item.payload for item in items]
160+
161+
assert len(spans) == 2
162+
(span1, span2) = spans
163+
164+
assert span1["name"] == "inner"
165+
assert span1.get("parent_span_id") != span2["span_id"]
166+
167+
assert span2["name"] == "outer"
168+
169+
170+
@pytest.mark.asyncio
171+
async def test_trace_decorator_async_span_streaming(sentry_init, capture_items):
172+
sentry_init(
173+
traces_sample_rate=1.0,
174+
_experiments={"trace_lifecycle": "stream"},
175+
)
176+
177+
items = capture_items("span")
178+
179+
@sentry_sdk.traces.trace
180+
async def traced_function():
181+
return "ok"
182+
183+
result = await traced_function()
184+
assert result == "ok"
185+
186+
sentry_sdk.get_client().flush()
187+
spans = [item.payload for item in items]
188+
189+
assert len(spans) == 1
190+
(span,) = spans
191+
192+
assert (
193+
span["name"]
194+
== "test_decorator.test_trace_decorator_async_span_streaming.<locals>.traced_function"
195+
)
196+
assert span["status"] == "ok"
197+
198+
199+
@pytest.mark.asyncio
200+
async def test_trace_decorator_async_arguments_span_streaming(
201+
sentry_init, capture_items
202+
):
203+
sentry_init(
204+
traces_sample_rate=1.0,
205+
_experiments={"trace_lifecycle": "stream"},
206+
)
207+
208+
items = capture_items("span")
209+
210+
@sentry_sdk.traces.trace(name="traced", attributes={"traced.attribute": 123})
211+
async def traced_function():
212+
return "ok"
213+
214+
result = await traced_function()
215+
assert result == "ok"
216+
217+
sentry_sdk.get_client().flush()
218+
spans = [item.payload for item in items]
219+
220+
assert len(spans) == 1
221+
(span,) = spans
222+
223+
assert span["name"] == "traced"
224+
assert span["attributes"]["traced.attribute"] == 123
225+
assert span["status"] == "ok"
226+
227+
228+
@pytest.mark.asyncio
229+
async def test_trace_decorator_async_inactive_span_streaming(
230+
sentry_init, capture_items
231+
):
232+
sentry_init(
233+
traces_sample_rate=1.0,
234+
_experiments={"trace_lifecycle": "stream"},
235+
)
236+
237+
items = capture_items("span")
238+
239+
@sentry_sdk.traces.trace(name="outer", active=False)
240+
async def traced_function():
241+
with sentry_sdk.traces.start_span(name="inner"):
242+
return "ok"
243+
244+
result = await traced_function()
245+
assert result == "ok"
246+
247+
sentry_sdk.get_client().flush()
248+
spans = [item.payload for item in items]
249+
250+
assert len(spans) == 2
251+
(span1, span2) = spans
252+
253+
assert span1["name"] == "inner"
254+
assert span1.get("parent_span_id") != span2["span_id"]
255+
256+
assert span2["name"] == "outer"
257+
258+
259+
def test_trace_decorator_child_span_streaming(sentry_init, capture_items):
260+
"""Spans created with @trace show up as children if a span is active."""
261+
sentry_init(
262+
traces_sample_rate=1.0,
263+
_experiments={
264+
"trace_lifecycle": "stream",
265+
},
266+
)
267+
268+
items = capture_items("span")
269+
270+
@sentry_sdk.traces.trace
271+
def _some_function_traced_stream(a, b, c):
272+
return True
273+
274+
with sentry_sdk.traces.start_span(name="segment") as segment:
275+
result = _some_function_traced_stream(1, 2, 3)
276+
277+
assert result is True
278+
279+
sentry_sdk.flush()
280+
281+
assert len(items) == 2
282+
child_span, segment_span = items[0].payload, items[1].payload
283+
284+
assert (
285+
child_span["name"]
286+
== "test_decorator.test_trace_decorator_child_span_streaming.<locals>._some_function_traced_stream"
287+
)
288+
assert child_span["parent_span_id"] == segment.span_id
289+
assert segment_span["name"] == "segment"
290+
assert "parent_span_id" not in segment_span
291+
292+
293+
@pytest.mark.asyncio
294+
async def test_trace_decorator_async_child_span_streaming(sentry_init, capture_items):
295+
"""Spans created with @trace show up as children if a span is active."""
296+
sentry_init(
297+
traces_sample_rate=1.0,
298+
_experiments={
299+
"trace_lifecycle": "stream",
300+
},
301+
)
302+
303+
items = capture_items("span")
304+
305+
@sentry_sdk.traces.trace
306+
async def _some_function_traced_stream(a, b, c):
307+
return True
308+
309+
with sentry_sdk.traces.start_span(name="segment") as segment:
310+
result = await _some_function_traced_stream(1, 2, 3)
311+
312+
assert result is True
313+
314+
sentry_sdk.flush()
315+
316+
assert len(items) == 2
317+
child_span, segment_span = items[0].payload, items[1].payload
318+
319+
assert (
320+
child_span["name"]
321+
== "test_decorator.test_trace_decorator_async_child_span_streaming.<locals>._some_function_traced_stream"
322+
)
323+
assert child_span["parent_span_id"] == segment.span_id
324+
assert segment_span["name"] == "segment"
325+
assert "parent_span_id" not in segment_span
326+
327+
89328
def test_functions_to_trace_signature_unchanged_sync(sentry_init):
90329
sentry_init(
91330
traces_sample_rate=1.0,
@@ -94,14 +333,22 @@ def test_functions_to_trace_signature_unchanged_sync(sentry_init):
94333
def _some_function(a, b, c):
95334
pass
96335

97-
@trace
336+
@sentry_sdk.trace
98337
def _some_function_traced(a, b, c):
99338
pass
100339

340+
@sentry_sdk.traces.trace
341+
def _some_function_traced_stream(a, b, c):
342+
pass
343+
101344
assert inspect.getcallargs(_some_function, 1, 2, 3) == inspect.getcallargs(
102345
_some_function_traced, 1, 2, 3
103346
)
104347

348+
assert inspect.getcallargs(_some_function, 1, 2, 3) == inspect.getcallargs(
349+
_some_function_traced_stream, 1, 2, 3
350+
)
351+
105352

106353
@pytest.mark.asyncio
107354
async def test_functions_to_trace_signature_unchanged_async(sentry_init):
@@ -112,13 +359,20 @@ async def test_functions_to_trace_signature_unchanged_async(sentry_init):
112359
async def _some_function(a, b, c):
113360
pass
114361

115-
@trace
362+
@sentry_sdk.trace
116363
async def _some_function_traced(a, b, c):
117364
pass
118365

366+
@sentry_sdk.traces.trace
367+
async def _some_function_traced_stream(a, b, c):
368+
pass
369+
119370
assert inspect.getcallargs(_some_function, 1, 2, 3) == inspect.getcallargs(
120371
_some_function_traced, 1, 2, 3
121372
)
373+
assert inspect.getcallargs(_some_function, 1, 2, 3) == inspect.getcallargs(
374+
_some_function_traced_stream, 1, 2, 3
375+
)
122376

123377

124378
@pytest.mark.parametrize("stream_gen_ai_spans", [True, False])

0 commit comments

Comments
 (0)