Skip to content

Commit c3746b2

Browse files
authored
test: Move conversation ID tests to their own file (#6699)
### Description For whatever reason, this collection of conversation ID tests was hidden away in `test_misc.py`. Move them to their own file. #### Issues <!-- * resolves: #1234 * resolves: LIN-1234 --> #### 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 7024d19 commit c3746b2

2 files changed

Lines changed: 185 additions & 184 deletions

File tree

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
import pytest
2+
3+
import sentry_sdk
4+
from sentry_sdk import start_span
5+
6+
7+
def test_conversation_id_propagates_to_span_with_gen_ai_operation_name(
8+
sentry_init, capture_events
9+
):
10+
"""Span with gen_ai.operation.name data should get conversation_id."""
11+
sentry_init(traces_sample_rate=1.0)
12+
events = capture_events()
13+
14+
scope = sentry_sdk.get_current_scope()
15+
scope.set_conversation_id("conv-op-name-test")
16+
17+
with sentry_sdk.start_transaction(name="test-tx"):
18+
with start_span(op="http.client") as span:
19+
span.set_data("gen_ai.operation.name", "chat")
20+
21+
(event,) = events
22+
span_data = event["spans"][0]["data"]
23+
assert span_data.get("gen_ai.conversation.id") == "conv-op-name-test"
24+
25+
26+
def test_conversation_id_propagates_to_span_with_ai_op(sentry_init, capture_events):
27+
"""Span with ai.* op should get conversation_id."""
28+
sentry_init(traces_sample_rate=1.0)
29+
events = capture_events()
30+
31+
scope = sentry_sdk.get_current_scope()
32+
scope.set_conversation_id("conv-ai-op-test")
33+
34+
with sentry_sdk.start_transaction(name="test-tx"):
35+
with start_span(op="ai.chat.completions"):
36+
pass
37+
38+
(event,) = events
39+
span_data = event["spans"][0]["data"]
40+
assert span_data.get("gen_ai.conversation.id") == "conv-ai-op-test"
41+
42+
43+
@pytest.mark.parametrize("stream_gen_ai_spans", [True, False])
44+
def test_conversation_id_propagates_to_span_with_gen_ai_op(
45+
sentry_init, capture_events, capture_items, stream_gen_ai_spans
46+
):
47+
"""Span with gen_ai.* op should get conversation_id."""
48+
sentry_init(
49+
traces_sample_rate=1.0,
50+
stream_gen_ai_spans=stream_gen_ai_spans,
51+
)
52+
53+
if stream_gen_ai_spans:
54+
items = capture_items("span")
55+
56+
scope = sentry_sdk.get_current_scope()
57+
scope.set_conversation_id("conv-gen-ai-op-test")
58+
59+
with sentry_sdk.start_transaction(name="test-tx"):
60+
with start_span(op="gen_ai.invoke_agent"):
61+
pass
62+
63+
spans = [item.payload for item in items if item.type == "span"]
64+
span_data = spans[0]["attributes"]
65+
else:
66+
events = capture_events()
67+
68+
scope = sentry_sdk.get_current_scope()
69+
scope.set_conversation_id("conv-gen-ai-op-test")
70+
71+
with sentry_sdk.start_transaction(name="test-tx"):
72+
with start_span(op="gen_ai.invoke_agent"):
73+
pass
74+
75+
(event,) = events
76+
span_data = event["spans"][0]["data"]
77+
78+
assert span_data.get("gen_ai.conversation.id") == "conv-gen-ai-op-test"
79+
80+
81+
def test_conversation_id_not_propagated_to_non_ai_span(sentry_init, capture_events):
82+
"""Non-AI span should NOT get conversation_id."""
83+
sentry_init(traces_sample_rate=1.0)
84+
events = capture_events()
85+
86+
scope = sentry_sdk.get_current_scope()
87+
scope.set_conversation_id("conv-should-not-appear")
88+
89+
with sentry_sdk.start_transaction(name="test-tx"):
90+
with start_span(op="http.client") as span:
91+
span.set_data("some.other.data", "value")
92+
93+
(event,) = events
94+
span_data = event["spans"][0]["data"]
95+
assert "gen_ai.conversation.id" not in span_data
96+
97+
98+
def test_conversation_id_not_propagated_when_not_set(sentry_init, capture_events):
99+
"""AI span should not have conversation_id if not set on scope."""
100+
sentry_init(traces_sample_rate=1.0)
101+
events = capture_events()
102+
103+
# Ensure no conversation_id is set
104+
scope = sentry_sdk.get_current_scope()
105+
scope.remove_conversation_id()
106+
107+
with sentry_sdk.start_transaction(name="test-tx"):
108+
with start_span(op="ai.chat.completions"):
109+
pass
110+
111+
(event,) = events
112+
span_data = event["spans"][0]["data"]
113+
assert "gen_ai.conversation.id" not in span_data
114+
115+
116+
def test_conversation_id_not_propagated_to_span_without_op(sentry_init, capture_events):
117+
"""Span without op and without gen_ai.operation.name should NOT get conversation_id."""
118+
sentry_init(traces_sample_rate=1.0)
119+
events = capture_events()
120+
121+
scope = sentry_sdk.get_current_scope()
122+
scope.set_conversation_id("conv-no-op-test")
123+
124+
with sentry_sdk.start_transaction(name="test-tx"):
125+
with start_span(name="unnamed-span") as span:
126+
span.set_data("regular.data", "value")
127+
128+
(event,) = events
129+
span_data = event["spans"][0]["data"]
130+
assert "gen_ai.conversation.id" not in span_data
131+
132+
133+
def test_conversation_id_propagates_with_gen_ai_operation_name_no_op(
134+
sentry_init, capture_events
135+
):
136+
"""Span with gen_ai.operation.name but no op should still get conversation_id."""
137+
sentry_init(traces_sample_rate=1.0)
138+
events = capture_events()
139+
140+
scope = sentry_sdk.get_current_scope()
141+
scope.set_conversation_id("conv-no-op-but-data-test")
142+
143+
with sentry_sdk.start_transaction(name="test-tx"):
144+
with start_span(name="unnamed-span") as span:
145+
span.set_data("gen_ai.operation.name", "embedding")
146+
147+
(event,) = events
148+
span_data = event["spans"][0]["data"]
149+
assert span_data.get("gen_ai.conversation.id") == "conv-no-op-but-data-test"
150+
151+
152+
def test_conversation_id_propagates_to_transaction_with_ai_op(
153+
sentry_init, capture_events
154+
):
155+
"""Transaction with ai.* op should get conversation_id."""
156+
sentry_init(traces_sample_rate=1.0)
157+
events = capture_events()
158+
159+
scope = sentry_sdk.get_current_scope()
160+
scope.set_conversation_id("conv-tx-ai-op-test")
161+
162+
with sentry_sdk.start_transaction(op="ai.workflow", name="AI Workflow"):
163+
pass
164+
165+
(event,) = events
166+
trace_data = event["contexts"]["trace"]["data"]
167+
assert trace_data.get("gen_ai.conversation.id") == "conv-tx-ai-op-test"
168+
169+
170+
def test_conversation_id_not_propagated_to_non_ai_transaction(
171+
sentry_init, capture_events
172+
):
173+
"""Non-AI transaction should NOT get conversation_id."""
174+
sentry_init(traces_sample_rate=1.0)
175+
events = capture_events()
176+
177+
scope = sentry_sdk.get_current_scope()
178+
scope.set_conversation_id("conv-tx-should-not-appear")
179+
180+
with sentry_sdk.start_transaction(op="http.server", name="HTTP Request"):
181+
pass
182+
183+
(event,) = events
184+
trace_data = event["contexts"]["trace"]["data"]
185+
assert "gen_ai.conversation.id" not in trace_data

tests/tracing/test_misc.py

Lines changed: 0 additions & 184 deletions
Original file line numberDiff line numberDiff line change
@@ -606,187 +606,3 @@ def test_update_current_span(sentry_init, capture_events):
606606
"thread.id": mock.ANY,
607607
"thread.name": mock.ANY,
608608
}
609-
610-
611-
class TestConversationIdPropagation:
612-
"""Tests for conversation_id propagation to AI spans."""
613-
614-
def test_conversation_id_propagates_to_span_with_gen_ai_operation_name(
615-
self, sentry_init, capture_events
616-
):
617-
"""Span with gen_ai.operation.name data should get conversation_id."""
618-
sentry_init(traces_sample_rate=1.0)
619-
events = capture_events()
620-
621-
scope = sentry_sdk.get_current_scope()
622-
scope.set_conversation_id("conv-op-name-test")
623-
624-
with sentry_sdk.start_transaction(name="test-tx"):
625-
with start_span(op="http.client") as span:
626-
span.set_data("gen_ai.operation.name", "chat")
627-
628-
(event,) = events
629-
span_data = event["spans"][0]["data"]
630-
assert span_data.get("gen_ai.conversation.id") == "conv-op-name-test"
631-
632-
def test_conversation_id_propagates_to_span_with_ai_op(
633-
self, sentry_init, capture_events
634-
):
635-
"""Span with ai.* op should get conversation_id."""
636-
sentry_init(traces_sample_rate=1.0)
637-
events = capture_events()
638-
639-
scope = sentry_sdk.get_current_scope()
640-
scope.set_conversation_id("conv-ai-op-test")
641-
642-
with sentry_sdk.start_transaction(name="test-tx"):
643-
with start_span(op="ai.chat.completions"):
644-
pass
645-
646-
(event,) = events
647-
span_data = event["spans"][0]["data"]
648-
assert span_data.get("gen_ai.conversation.id") == "conv-ai-op-test"
649-
650-
@pytest.mark.parametrize("stream_gen_ai_spans", [True, False])
651-
def test_conversation_id_propagates_to_span_with_gen_ai_op(
652-
self, sentry_init, capture_events, capture_items, stream_gen_ai_spans
653-
):
654-
"""Span with gen_ai.* op should get conversation_id."""
655-
sentry_init(
656-
traces_sample_rate=1.0,
657-
stream_gen_ai_spans=stream_gen_ai_spans,
658-
)
659-
660-
if stream_gen_ai_spans:
661-
items = capture_items("span")
662-
663-
scope = sentry_sdk.get_current_scope()
664-
scope.set_conversation_id("conv-gen-ai-op-test")
665-
666-
with sentry_sdk.start_transaction(name="test-tx"):
667-
with start_span(op="gen_ai.invoke_agent"):
668-
pass
669-
670-
spans = [item.payload for item in items if item.type == "span"]
671-
span_data = spans[0]["attributes"]
672-
else:
673-
events = capture_events()
674-
675-
scope = sentry_sdk.get_current_scope()
676-
scope.set_conversation_id("conv-gen-ai-op-test")
677-
678-
with sentry_sdk.start_transaction(name="test-tx"):
679-
with start_span(op="gen_ai.invoke_agent"):
680-
pass
681-
682-
(event,) = events
683-
span_data = event["spans"][0]["data"]
684-
685-
assert span_data.get("gen_ai.conversation.id") == "conv-gen-ai-op-test"
686-
687-
def test_conversation_id_not_propagated_to_non_ai_span(
688-
self, sentry_init, capture_events
689-
):
690-
"""Non-AI span should NOT get conversation_id."""
691-
sentry_init(traces_sample_rate=1.0)
692-
events = capture_events()
693-
694-
scope = sentry_sdk.get_current_scope()
695-
scope.set_conversation_id("conv-should-not-appear")
696-
697-
with sentry_sdk.start_transaction(name="test-tx"):
698-
with start_span(op="http.client") as span:
699-
span.set_data("some.other.data", "value")
700-
701-
(event,) = events
702-
span_data = event["spans"][0]["data"]
703-
assert "gen_ai.conversation.id" not in span_data
704-
705-
def test_conversation_id_not_propagated_when_not_set(
706-
self, sentry_init, capture_events
707-
):
708-
"""AI span should not have conversation_id if not set on scope."""
709-
sentry_init(traces_sample_rate=1.0)
710-
events = capture_events()
711-
712-
# Ensure no conversation_id is set
713-
scope = sentry_sdk.get_current_scope()
714-
scope.remove_conversation_id()
715-
716-
with sentry_sdk.start_transaction(name="test-tx"):
717-
with start_span(op="ai.chat.completions"):
718-
pass
719-
720-
(event,) = events
721-
span_data = event["spans"][0]["data"]
722-
assert "gen_ai.conversation.id" not in span_data
723-
724-
def test_conversation_id_not_propagated_to_span_without_op(
725-
self, sentry_init, capture_events
726-
):
727-
"""Span without op and without gen_ai.operation.name should NOT get conversation_id."""
728-
sentry_init(traces_sample_rate=1.0)
729-
events = capture_events()
730-
731-
scope = sentry_sdk.get_current_scope()
732-
scope.set_conversation_id("conv-no-op-test")
733-
734-
with sentry_sdk.start_transaction(name="test-tx"):
735-
with start_span(name="unnamed-span") as span:
736-
span.set_data("regular.data", "value")
737-
738-
(event,) = events
739-
span_data = event["spans"][0]["data"]
740-
assert "gen_ai.conversation.id" not in span_data
741-
742-
def test_conversation_id_propagates_with_gen_ai_operation_name_no_op(
743-
self, sentry_init, capture_events
744-
):
745-
"""Span with gen_ai.operation.name but no op should still get conversation_id."""
746-
sentry_init(traces_sample_rate=1.0)
747-
events = capture_events()
748-
749-
scope = sentry_sdk.get_current_scope()
750-
scope.set_conversation_id("conv-no-op-but-data-test")
751-
752-
with sentry_sdk.start_transaction(name="test-tx"):
753-
with start_span(name="unnamed-span") as span:
754-
span.set_data("gen_ai.operation.name", "embedding")
755-
756-
(event,) = events
757-
span_data = event["spans"][0]["data"]
758-
assert span_data.get("gen_ai.conversation.id") == "conv-no-op-but-data-test"
759-
760-
def test_conversation_id_propagates_to_transaction_with_ai_op(
761-
self, sentry_init, capture_events
762-
):
763-
"""Transaction with ai.* op should get conversation_id."""
764-
sentry_init(traces_sample_rate=1.0)
765-
events = capture_events()
766-
767-
scope = sentry_sdk.get_current_scope()
768-
scope.set_conversation_id("conv-tx-ai-op-test")
769-
770-
with sentry_sdk.start_transaction(op="ai.workflow", name="AI Workflow"):
771-
pass
772-
773-
(event,) = events
774-
trace_data = event["contexts"]["trace"]["data"]
775-
assert trace_data.get("gen_ai.conversation.id") == "conv-tx-ai-op-test"
776-
777-
def test_conversation_id_not_propagated_to_non_ai_transaction(
778-
self, sentry_init, capture_events
779-
):
780-
"""Non-AI transaction should NOT get conversation_id."""
781-
sentry_init(traces_sample_rate=1.0)
782-
events = capture_events()
783-
784-
scope = sentry_sdk.get_current_scope()
785-
scope.set_conversation_id("conv-tx-should-not-appear")
786-
787-
with sentry_sdk.start_transaction(op="http.server", name="HTTP Request"):
788-
pass
789-
790-
(event,) = events
791-
trace_data = event["contexts"]["trace"]["data"]
792-
assert "gen_ai.conversation.id" not in trace_data

0 commit comments

Comments
 (0)