66
77import pytest
88
9- from sentry_sdk import capture_message , start_transaction
9+ from sentry_sdk import capture_message , start_span , continue_trace , isolation_scope
1010from sentry_sdk .consts import MATCH_ALL , SPANDATA
1111from sentry_sdk .tracing import Transaction
1212from sentry_sdk .integrations .stdlib import StdlibIntegration
1616PORT = create_mock_http_server ()
1717
1818
19+ @pytest .fixture
20+ def capture_request_headers (monkeypatch ):
21+ """
22+ HTTPConnection.send is passed a string containing (among other things)
23+ the headers on the request. Mock it so we can check the headers.
24+ """
25+
26+ def inner (do_send = True ):
27+ request_headers = {}
28+ old_send = HTTPConnection .send
29+
30+ def patched_send (self , data ):
31+ for line in data .decode ("utf-8" ).split ("\r \n " )[1 :]:
32+ if line :
33+ key , val = line .split (": " )
34+ request_headers [key ] = val
35+ if do_send :
36+ old_send (self , data )
37+
38+ monkeypatch .setattr (HTTPConnection , "send" , patched_send )
39+ return request_headers
40+
41+ return inner
42+
43+
1944def test_crumb_capture (sentry_init , capture_events ):
2045 sentry_init (integrations = [StdlibIntegration ()])
2146 events = capture_events ()
@@ -79,7 +104,7 @@ def test_empty_realurl(sentry_init):
79104 """
80105
81106 sentry_init (dsn = "" )
82- HTTPConnection ("example.com " , port = 443 ).putrequest ("POST" , None )
107+ HTTPConnection ("localhost " , PORT ).putrequest ("POST" , None )
83108
84109
85110def test_httplib_misuse (sentry_init , capture_events , request ):
@@ -131,40 +156,28 @@ def test_httplib_misuse(sentry_init, capture_events, request):
131156 )
132157
133158
134- def test_outgoing_trace_headers (sentry_init , monkeypatch , capture_envelopes ):
135- # HTTPSConnection.send is passed a string containing (among other things)
136- # the headers on the request. Mock it so we can check the headers, and also
137- # so it doesn't try to actually talk to the internet.
138- mock_send = mock .Mock ()
139- monkeypatch .setattr (HTTPSConnection , "send" , mock_send )
140-
159+ def test_outgoing_trace_headers (
160+ sentry_init , capture_envelopes , capture_request_headers , SortedBaggage
161+ ):
141162 sentry_init (traces_sample_rate = 1.0 )
142-
143163 envelopes = capture_envelopes ()
164+ request_headers = capture_request_headers ()
144165
145166 headers = {}
167+ headers ["sentry-trace" ] = "771a43a4192642f0b136d5159a501700-1234567890abcdef-1"
146168 headers ["baggage" ] = (
147169 "other-vendor-value-1=foo;bar;baz, sentry-trace_id=771a43a4192642f0b136d5159a501700, "
148- "sentry-public_key=49d0f7386ad645858ae85020e393bef3, sentry-sample_rate=0.01337, "
170+ "sentry-public_key=49d0f7386ad645858ae85020e393bef3, "
171+ "sentry-sampled=true, sentry-sample_rate=0.01337, "
149172 "sentry-user_id=Am%C3%A9lie, other-vendor-value-2=foo;bar;"
150173 )
151174
152- transaction = Transaction .continue_from_headers (headers )
153-
154- with start_transaction (
155- transaction = transaction ,
156- name = "/interactions/other-dogs/new-dog" ,
157- op = "greeting.sniff" ,
158- trace_id = "12312012123120121231201212312012" ,
159- ) as transaction :
160- HTTPSConnection ("www.squirrelchasers.com" ).request ("GET" , "/top-chasers" )
161-
162- (request_str ,) = mock_send .call_args [0 ]
163- request_headers = {}
164- for line in request_str .decode ("utf-8" ).split ("\r \n " )[1 :]:
165- if line :
166- key , val = line .split (": " )
167- request_headers [key ] = val
175+ with isolation_scope ():
176+ with continue_trace (headers ):
177+ with start_span (name = "/interactions/other-dogs/new-dog" ):
178+ conn = HTTPConnection ("localhost" , PORT )
179+ conn .request ("GET" , "/top-chasers" )
180+ conn .getresponse ()
168181
169182 (envelope ,) = envelopes
170183 transaction = envelope .get_transaction_event ()
@@ -180,38 +193,30 @@ def test_outgoing_trace_headers(sentry_init, monkeypatch, capture_envelopes):
180193 expected_outgoing_baggage = (
181194 "sentry-trace_id=771a43a4192642f0b136d5159a501700,"
182195 "sentry-public_key=49d0f7386ad645858ae85020e393bef3,"
196+ "sentry-sampled=true,"
183197 "sentry-sample_rate=0.01337,"
184198 "sentry-user_id=Am%C3%A9lie"
185199 )
186200
187- assert request_headers ["baggage" ] == expected_outgoing_baggage
201+ assert request_headers ["baggage" ] == SortedBaggage ( expected_outgoing_baggage )
188202
189203
190- def test_outgoing_trace_headers_head_sdk (sentry_init , monkeypatch , capture_envelopes ):
191- # HTTPSConnection.send is passed a string containing (among other things)
192- # the headers on the request. Mock it so we can check the headers, and also
193- # so it doesn't try to actually talk to the internet.
194- mock_send = mock .Mock ()
195- monkeypatch .setattr (HTTPSConnection , "send" , mock_send )
196-
204+ def test_outgoing_trace_headers_head_sdk (
205+ sentry_init , monkeypatch , capture_request_headers , capture_envelopes , SortedBaggage
206+ ):
197207 # make sure transaction is always sampled
198208 monkeypatch .setattr (random , "random" , lambda : 0.1 )
199209
200210 sentry_init (traces_sample_rate = 0.5 , release = "foo" )
201-
202211 envelopes = capture_envelopes ()
212+ request_headers = capture_request_headers ()
203213
204- transaction = Transaction .continue_from_headers ({})
205-
206- with start_transaction (transaction = transaction , name = "Head SDK tx" ) as transaction :
207- HTTPSConnection ("www.squirrelchasers.com" ).request ("GET" , "/top-chasers" )
208-
209- (request_str ,) = mock_send .call_args [0 ]
210- request_headers = {}
211- for line in request_str .decode ("utf-8" ).split ("\r \n " )[1 :]:
212- if line :
213- key , val = line .split (": " )
214- request_headers [key ] = val
214+ with isolation_scope ():
215+ with continue_trace ({}):
216+ with start_span (name = "Head SDK tx" ) as root_span :
217+ conn = HTTPConnection ("localhost" , PORT )
218+ conn .request ("GET" , "/top-chasers" )
219+ conn .getresponse ()
215220
216221 (envelope ,) = envelopes
217222 transaction = envelope .get_transaction_event ()
@@ -225,14 +230,15 @@ def test_outgoing_trace_headers_head_sdk(sentry_init, monkeypatch, capture_envel
225230 assert request_headers ["sentry-trace" ] == expected_sentry_trace
226231
227232 expected_outgoing_baggage = (
228- "sentry-trace_id=%s ,"
233+ f "sentry-trace_id={ root_span . trace_id } ,"
229234 "sentry-environment=production,"
230235 "sentry-release=foo,"
231236 "sentry-sample_rate=0.5,"
232- "sentry-sampled=%s"
233- ) % (transaction .trace_id , "true" if transaction .sampled else "false" )
237+ "sentry-sampled=true,"
238+ "sentry-transaction=Head%20SDK%20tx"
239+ )
234240
235- assert request_headers ["baggage" ] == expected_outgoing_baggage
241+ assert request_headers ["baggage" ] == SortedBaggage ( expected_outgoing_baggage )
236242
237243
238244@pytest .mark .parametrize (
@@ -295,42 +301,23 @@ def test_outgoing_trace_headers_head_sdk(sentry_init, monkeypatch, capture_envel
295301 ],
296302)
297303def test_option_trace_propagation_targets (
298- sentry_init , monkeypatch , trace_propagation_targets , host , path , trace_propagated
304+ sentry_init ,
305+ capture_request_headers ,
306+ trace_propagation_targets ,
307+ host ,
308+ path ,
309+ trace_propagated ,
299310):
300- # HTTPSConnection.send is passed a string containing (among other things)
301- # the headers on the request. Mock it so we can check the headers, and also
302- # so it doesn't try to actually talk to the internet.
303- mock_send = mock .Mock ()
304- monkeypatch .setattr (HTTPSConnection , "send" , mock_send )
305-
306311 sentry_init (
307312 trace_propagation_targets = trace_propagation_targets ,
308313 traces_sample_rate = 1.0 ,
309314 )
310315
311- headers = {
312- "baggage" : (
313- "sentry-trace_id=771a43a4192642f0b136d5159a501700, "
314- "sentry-public_key=49d0f7386ad645858ae85020e393bef3, sentry-sample_rate=0.01337, "
315- )
316- }
317-
318- transaction = Transaction .continue_from_headers (headers )
319-
320- with start_transaction (
321- transaction = transaction ,
322- name = "/interactions/other-dogs/new-dog" ,
323- op = "greeting.sniff" ,
324- trace_id = "12312012123120121231201212312012" ,
325- ) as transaction :
326- HTTPSConnection (host ).request ("GET" , path )
316+ request_headers = capture_request_headers (do_send = False )
327317
328- (request_str ,) = mock_send .call_args [0 ]
329- request_headers = {}
330- for line in request_str .decode ("utf-8" ).split ("\r \n " )[1 :]:
331- if line :
332- key , val = line .split (": " )
333- request_headers [key ] = val
318+ with start_span (name = "foo" ):
319+ HTTPSConnection (host ).request ("GET" , path )
320+ # don't invoke getresponse to avoid actual network traffic
334321
335322 if trace_propagated :
336323 assert "sentry-trace" in request_headers
@@ -344,8 +331,8 @@ def test_span_origin(sentry_init, capture_events):
344331 sentry_init (traces_sample_rate = 1.0 , debug = True )
345332 events = capture_events ()
346333
347- with start_transaction (name = "foo" ):
348- conn = HTTPSConnection ( "example.com" )
334+ with start_span (name = "foo" ):
335+ conn = HTTPConnection ( "localhost" , PORT )
349336 conn .request ("GET" , "/foo" )
350337 conn .getresponse ()
351338
@@ -364,9 +351,9 @@ def test_http_timeout(monkeypatch, sentry_init, capture_envelopes):
364351
365352 envelopes = capture_envelopes ()
366353
367- with start_transaction (op = "op" , name = "name" ):
354+ with start_span (op = "op" , name = "name" ):
368355 try :
369- conn = HTTPSConnection ( "www.squirrelchasers.com" )
356+ conn = HTTPConnection ( "localhost" , PORT )
370357 conn .request ("GET" , "/top-chasers" )
371358 conn .getresponse ()
372359 except Exception :
@@ -385,4 +372,4 @@ def test_http_timeout(monkeypatch, sentry_init, capture_envelopes):
385372
386373 span = transaction ["spans" ][0 ]
387374 assert span ["op" ] == "http.client"
388- assert span ["description" ] == "GET https ://www.squirrelchasers.com /top-chasers"
375+ assert span ["description" ] == f "GET http ://localhost: { PORT } /top-chasers"
0 commit comments