11import os
2+ import socket
23import datetime
34from http .client import HTTPConnection , HTTPSConnection
45from http .server import BaseHTTPRequestHandler , HTTPServer
@@ -202,15 +203,31 @@ def test_httplib_misuse(sentry_init, capture_events, request):
202203 )
203204
204205
205- def test_outgoing_trace_headers (sentry_init , monkeypatch ):
206- # HTTPSConnection.send is passed a string containing (among other things)
207- # the headers on the request. Mock it so we can check the headers, and also
208- # so it doesn't try to actually talk to the internet.
209- mock_send = mock .Mock ()
210- monkeypatch .setattr (HTTPSConnection , "send" , mock_send )
211-
206+ def test_outgoing_trace_headers (sentry_init , capture_events ):
212207 sentry_init (traces_sample_rate = 1.0 )
213208
209+ already_patched_getresponse = HTTPSConnection .getresponse
210+
211+ request_headers = {}
212+
213+ class HTTPSConnectionRecordingRequestHeaders (HTTPSConnection ):
214+ def send (self , * args , ** kwargs ) -> None :
215+ request_str = args [0 ]
216+ for line in request_str .decode ("utf-8" ).split ("\r \n " )[1 :]:
217+ if line :
218+ key , val = line .split (": " )
219+ request_headers [key ] = val
220+
221+ server_sock , client_sock = socket .socketpair ()
222+ server_sock .sendall (b"HTTP/1.1 200 OK\r \n \r \n " )
223+ server_sock .close ()
224+ self .sock = client_sock
225+
226+ def getresponse (self , * args , ** kwargs ):
227+ return already_patched_getresponse (self , * args , ** kwargs )
228+
229+ events = capture_events ()
230+
214231 headers = {
215232 "sentry-trace" : "771a43a4192642f0b136d5159a501700-1234567890abcdef-1" ,
216233 "baggage" : (
@@ -228,73 +245,83 @@ def test_outgoing_trace_headers(sentry_init, monkeypatch):
228245 op = "greeting.sniff" ,
229246 trace_id = "12312012123120121231201212312012" ,
230247 ) as transaction :
231- HTTPSConnection ("www.squirrelchasers.com" ).request ("GET" , "/top-chasers" )
232-
233- (request_str ,) = mock_send .call_args [0 ]
234- request_headers = {}
235- for line in request_str .decode ("utf-8" ).split ("\r \n " )[1 :]:
236- if line :
237- key , val = line .split (": " )
238- request_headers [key ] = val
239-
240- request_span = transaction ._span_recorder .spans [- 1 ]
241- expected_sentry_trace = "{trace_id}-{parent_span_id}-{sampled}" .format (
242- trace_id = transaction .trace_id ,
243- parent_span_id = request_span .span_id ,
244- sampled = 1 ,
245- )
246- assert request_headers ["sentry-trace" ] == expected_sentry_trace
247-
248- expected_outgoing_baggage = (
249- "sentry-trace_id=771a43a4192642f0b136d5159a501700,"
250- "sentry-public_key=49d0f7386ad645858ae85020e393bef3,"
251- "sentry-sample_rate=1.0,"
252- "sentry-user_id=Am%C3%A9lie,"
253- "sentry-sample_rand=0.132521102938283"
254- )
248+ connection = HTTPSConnectionRecordingRequestHeaders ("localhost" , port = PORT )
249+ connection .request ("GET" , "/top-chasers" )
250+ connection .getresponse ()
255251
256- assert request_headers ["baggage" ] == expected_outgoing_baggage
252+ (event ,) = events
253+ request_span = event ["spans" ][- 1 ]
254+ expected_sentry_trace = "{trace_id}-{parent_span_id}-{sampled}" .format (
255+ trace_id = event ["contexts" ]["trace" ]["trace_id" ],
256+ parent_span_id = request_span ["span_id" ],
257+ sampled = 1 ,
258+ )
259+ assert request_headers ["sentry-trace" ] == expected_sentry_trace
260+
261+ expected_outgoing_baggage = (
262+ "sentry-trace_id=771a43a4192642f0b136d5159a501700,"
263+ "sentry-public_key=49d0f7386ad645858ae85020e393bef3,"
264+ "sentry-sample_rate=1.0,"
265+ "sentry-user_id=Am%C3%A9lie,"
266+ "sentry-sample_rand=0.132521102938283"
267+ )
257268
269+ assert request_headers ["baggage" ] == expected_outgoing_baggage
258270
259- def test_outgoing_trace_headers_head_sdk (sentry_init , monkeypatch ):
260- # HTTPSConnection.send is passed a string containing (among other things)
261- # the headers on the request. Mock it so we can check the headers, and also
262- # so it doesn't try to actually talk to the internet.
263- mock_send = mock .Mock ()
264- monkeypatch .setattr (HTTPSConnection , "send" , mock_send )
265271
272+ def test_outgoing_trace_headers_head_sdk (sentry_init , capture_events ):
266273 sentry_init (traces_sample_rate = 0.5 , release = "foo" )
274+
275+ already_patched_getresponse = HTTPSConnection .getresponse
276+
277+ request_headers = {}
278+
279+ class HTTPSConnectionRecordingRequestHeaders (HTTPSConnection ):
280+ def send (self , * args , ** kwargs ) -> None :
281+ request_str = args [0 ]
282+ for line in request_str .decode ("utf-8" ).split ("\r \n " )[1 :]:
283+ if line :
284+ key , val = line .split (": " )
285+ request_headers [key ] = val
286+
287+ server_sock , client_sock = socket .socketpair ()
288+ server_sock .sendall (b"HTTP/1.1 200 OK\r \n \r \n " )
289+ server_sock .close ()
290+ self .sock = client_sock
291+
292+ def getresponse (self , * args , ** kwargs ):
293+ return already_patched_getresponse (self , * args , ** kwargs )
294+
295+ events = capture_events ()
296+
267297 with mock .patch ("sentry_sdk.tracing_utils.Random.randrange" , return_value = 250000 ):
268298 transaction = continue_trace ({})
269299
270300 with start_transaction (transaction = transaction , name = "Head SDK tx" ) as transaction :
271- HTTPSConnection ("www.squirrelchasers.com" ).request ("GET" , "/top-chasers" )
272-
273- (request_str ,) = mock_send .call_args [0 ]
274- request_headers = {}
275- for line in request_str .decode ("utf-8" ).split ("\r \n " )[1 :]:
276- if line :
277- key , val = line .split (": " )
278- request_headers [key ] = val
279-
280- request_span = transaction ._span_recorder .spans [- 1 ]
281- expected_sentry_trace = "{trace_id}-{parent_span_id}-{sampled}" .format (
282- trace_id = transaction .trace_id ,
283- parent_span_id = request_span .span_id ,
284- sampled = 1 ,
285- )
286- assert request_headers ["sentry-trace" ] == expected_sentry_trace
301+ connection = HTTPSConnectionRecordingRequestHeaders ("localhost" , port = PORT )
302+ connection .request ("GET" , "/top-chasers" )
303+ connection .getresponse ()
304+
305+ (event ,) = events
306+ request_span = event ["spans" ][- 1 ]
307+ expected_sentry_trace = "{trace_id}-{parent_span_id}-{sampled}" .format (
308+ trace_id = event ["contexts" ]["trace" ]["trace_id" ],
309+ parent_span_id = request_span ["span_id" ],
310+ sampled = 1 ,
311+ )
312+
313+ assert request_headers ["sentry-trace" ] == expected_sentry_trace
287314
288- expected_outgoing_baggage = (
289- "sentry-trace_id=%s,"
290- "sentry-sample_rand=0.250000,"
291- "sentry-environment=production,"
292- "sentry-release=foo,"
293- "sentry-sample_rate=0.5,"
294- "sentry-sampled=%s"
295- ) % (transaction .trace_id , "true" if transaction .sampled else "false" )
315+ expected_outgoing_baggage = (
316+ "sentry-trace_id=%s,"
317+ "sentry-sample_rand=0.250000,"
318+ "sentry-environment=production,"
319+ "sentry-release=foo,"
320+ "sentry-sample_rate=0.5,"
321+ "sentry-sampled=%s"
322+ ) % (transaction .trace_id , "true" if transaction .sampled else "false" )
296323
297- assert request_headers ["baggage" ] == expected_outgoing_baggage
324+ assert request_headers ["baggage" ] == expected_outgoing_baggage
298325
299326
300327@pytest .mark .parametrize (
@@ -357,19 +384,33 @@ def test_outgoing_trace_headers_head_sdk(sentry_init, monkeypatch):
357384 ],
358385)
359386def test_option_trace_propagation_targets (
360- sentry_init , monkeypatch , trace_propagation_targets , host , path , trace_propagated
387+ sentry_init , trace_propagation_targets , host , path , trace_propagated
361388):
362- # HTTPSConnection.send is passed a string containing (among other things)
363- # the headers on the request. Mock it so we can check the headers, and also
364- # so it doesn't try to actually talk to the internet.
365- mock_send = mock .Mock ()
366- monkeypatch .setattr (HTTPSConnection , "send" , mock_send )
367-
368389 sentry_init (
369390 trace_propagation_targets = trace_propagation_targets ,
370391 traces_sample_rate = 1.0 ,
371392 )
372393
394+ already_patched_getresponse = HTTPSConnection .getresponse
395+
396+ request_headers = {}
397+
398+ class HTTPSConnectionRecordingRequestHeaders (HTTPSConnection ):
399+ def send (self , * args , ** kwargs ) -> None :
400+ request_str = args [0 ]
401+ for line in request_str .decode ("utf-8" ).split ("\r \n " )[1 :]:
402+ if line :
403+ key , val = line .split (": " )
404+ request_headers [key ] = val
405+
406+ server_sock , client_sock = socket .socketpair ()
407+ server_sock .sendall (b"HTTP/1.1 200 OK\r \n \r \n " )
408+ server_sock .close ()
409+ self .sock = client_sock
410+
411+ def getresponse (self , * args , ** kwargs ):
412+ return already_patched_getresponse (self , * args , ** kwargs )
413+
373414 headers = {
374415 "baggage" : (
375416 "sentry-trace_id=771a43a4192642f0b136d5159a501700, "
@@ -385,21 +426,16 @@ def test_option_trace_propagation_targets(
385426 op = "greeting.sniff" ,
386427 trace_id = "12312012123120121231201212312012" ,
387428 ) as transaction :
388- HTTPSConnection (host ).request ("GET" , path )
389-
390- (request_str ,) = mock_send .call_args [0 ]
391- request_headers = {}
392- for line in request_str .decode ("utf-8" ).split ("\r \n " )[1 :]:
393- if line :
394- key , val = line .split (": " )
395- request_headers [key ] = val
396-
397- if trace_propagated :
398- assert "sentry-trace" in request_headers
399- assert "baggage" in request_headers
400- else :
401- assert "sentry-trace" not in request_headers
402- assert "baggage" not in request_headers
429+ connection = HTTPSConnectionRecordingRequestHeaders (host )
430+ connection .request ("GET" , path )
431+ connection .getresponse ()
432+
433+ if trace_propagated :
434+ assert "sentry-trace" in request_headers
435+ assert "baggage" in request_headers
436+ else :
437+ assert "sentry-trace" not in request_headers
438+ assert "baggage" not in request_headers
403439
404440
405441def test_request_source_disabled (sentry_init , capture_events ):
0 commit comments