1313# limitations under the License.
1414
1515import sys
16- import unittest
17- from unittest import mock
1816
19- import pkg_resources
17+ import httpretty
2018import requests
2119import urllib3
2220
2321import opentelemetry .ext .http_requests
24- from opentelemetry import trace
22+ from opentelemetry import context , propagators , trace
23+ from opentelemetry .test .mock_httptextformat import MockHTTPTextFormat
24+ from opentelemetry .test .test_base import TestBase
2525
2626
27- class TestRequestsIntegration (unittest .TestCase ):
27+ class TestRequestsIntegration (TestBase ):
28+ URL = "http://httpbin.org/status/200"
2829
29- # TODO: Copy & paste from test_wsgi_middleware
3030 def setUp (self ):
31- self .span_attrs = {}
32- self .tracer_provider = trace .DefaultTracerProvider ()
33- self .tracer = trace .DefaultTracer ()
34- self .get_tracer_patcher = mock .patch .object (
35- self .tracer_provider ,
36- "get_tracer" ,
37- autospec = True ,
38- spec_set = True ,
39- return_value = self .tracer ,
40- )
41- self .get_tracer = self .get_tracer_patcher .start ()
42- self .span_context_manager = mock .MagicMock ()
43- self .span = mock .create_autospec (trace .Span , spec_set = True )
44- self .span .get_context .return_value = trace .INVALID_SPAN_CONTEXT
45- self .span_context_manager .__enter__ .return_value = self .span
46-
47- def setspanattr (key , value ):
48- self .assertIsInstance (key , str )
49- self .span_attrs [key ] = value
50-
51- self .span .set_attribute = setspanattr
52- self .start_span_patcher = mock .patch .object (
53- self .tracer ,
54- "start_as_current_span" ,
55- autospec = True ,
56- spec_set = True ,
57- return_value = self .span_context_manager ,
58- )
59-
60- mocked_response = requests .models .Response ()
61- mocked_response .status_code = 200
62- mocked_response .reason = "Roger that!"
63- self .send_patcher = mock .patch .object (
64- requests .Session ,
65- "send" ,
66- autospec = True ,
67- spec_set = True ,
68- return_value = mocked_response ,
69- )
70-
71- self .start_as_current_span = self .start_span_patcher .start ()
72- self .send = self .send_patcher .start ()
73-
31+ super ().setUp ()
7432 opentelemetry .ext .http_requests .enable (self .tracer_provider )
75- distver = pkg_resources .get_distribution (
76- "opentelemetry-ext-http-requests"
77- ).version
78- self .get_tracer .assert_called_with (
79- opentelemetry .ext .http_requests .__name__ , distver
33+ httpretty .enable ()
34+ httpretty .register_uri (
35+ httpretty .GET , self .URL , body = "Hello!" ,
8036 )
8137
8238 def tearDown (self ):
39+ super ().tearDown ()
8340 opentelemetry .ext .http_requests .disable ()
84- self .get_tracer_patcher .stop ()
85- self .send_patcher .stop ()
86- self .start_span_patcher .stop ()
41+ httpretty .disable ()
8742
8843 def test_basic (self ):
89- url = "https://www.example.org/foo/bar?x=y#top"
90- requests . get ( url = url )
91- self . assertEqual ( 1 , len ( self .send . call_args_list ) )
92- self .tracer . start_as_current_span . assert_called_with ( # pylint:disable=no-member
93- "/foo/bar" , kind = trace . SpanKind . CLIENT
94- )
95- self .span_context_manager . __enter__ . assert_called_with ( )
96- self . span_context_manager . __exit__ . assert_called_with ( None , None , None )
44+ result = requests . get ( self . URL )
45+ self . assertEqual ( result . text , "Hello!" )
46+ span_list = self .memory_exporter . get_finished_spans ( )
47+ self .assertEqual ( len ( span_list ), 1 )
48+ span = span_list [ 0 ]
49+ self . assertIs ( span . kind , trace . SpanKind . CLIENT )
50+ self .assertEqual ( span . name , "/status/200" )
51+
9752 self .assertEqual (
98- self . span_attrs ,
53+ span . attributes ,
9954 {
10055 "component" : "http" ,
10156 "http.method" : "GET" ,
102- "http.url" : url ,
57+ "http.url" : self . URL ,
10358 "http.status_code" : 200 ,
104- "http.status_text" : "Roger that! " ,
59+ "http.status_text" : "OK " ,
10560 },
10661 )
10762
@@ -114,20 +69,84 @@ def test_invalid_url(self):
11469 exception_type = ValueError
11570
11671 with self .assertRaises (exception_type ):
117- requests .post (url = url )
118- call_args = (
119- self .tracer .start_as_current_span .call_args # pylint:disable=no-member
120- )
121- self .assertTrue (
122- call_args [0 ][0 ].startswith ("<Unparsable URL" ),
123- msg = self .tracer .start_as_current_span .call_args , # pylint:disable=no-member
124- )
125- self .span_context_manager .__enter__ .assert_called_with ()
126- exitspan = self .span_context_manager .__exit__
127- self .assertEqual (1 , len (exitspan .call_args_list ))
128- self .assertIs (exception_type , exitspan .call_args [0 ][0 ])
129- self .assertIsInstance (exitspan .call_args [0 ][1 ], exception_type )
72+ requests .post (url )
73+
74+ span_list = self .memory_exporter .get_finished_spans ()
75+ self .assertEqual (len (span_list ), 1 )
76+ span = span_list [0 ]
77+
78+ self .assertTrue (span .name .startswith ("<Unparsable URL" ))
13079 self .assertEqual (
131- self . span_attrs ,
80+ span . attributes ,
13281 {"component" : "http" , "http.method" : "POST" , "http.url" : url },
13382 )
83+
84+ def test_disable (self ):
85+ opentelemetry .ext .http_requests .disable ()
86+ result = requests .get (self .URL )
87+ self .assertEqual (result .text , "Hello!" )
88+ span_list = self .memory_exporter .get_finished_spans ()
89+ self .assertEqual (len (span_list ), 0 )
90+
91+ def test_disable_session (self ):
92+ session1 = requests .Session ()
93+ opentelemetry .ext .http_requests .disable_session (session1 )
94+
95+ result = session1 .get (self .URL )
96+ self .assertEqual (result .text , "Hello!" )
97+ span_list = self .memory_exporter .get_finished_spans ()
98+ self .assertEqual (len (span_list ), 0 )
99+
100+ # Test that other sessions as well as global requests is still
101+ # instrumented
102+ session2 = requests .Session ()
103+ result = session2 .get (self .URL )
104+ self .assertEqual (result .text , "Hello!" )
105+ span_list = self .memory_exporter .get_finished_spans ()
106+ self .assertEqual (len (span_list ), 1 )
107+
108+ self .memory_exporter .clear ()
109+
110+ result = requests .get (self .URL )
111+ self .assertEqual (result .text , "Hello!" )
112+ span_list = self .memory_exporter .get_finished_spans ()
113+ self .assertEqual (len (span_list ), 1 )
114+
115+ def test_suppress_instrumentation (self ):
116+ token = context .attach (
117+ context .set_value ("suppress_instrumentation" , True )
118+ )
119+ try :
120+ result = requests .get (self .URL )
121+ self .assertEqual (result .text , "Hello!" )
122+ finally :
123+ context .detach (token )
124+
125+ span_list = self .memory_exporter .get_finished_spans ()
126+ self .assertEqual (len (span_list ), 0 )
127+
128+ def test_distributed_context (self ):
129+ previous_propagator = propagators .get_global_httptextformat ()
130+ try :
131+ propagators .set_global_httptextformat (MockHTTPTextFormat ())
132+ result = requests .get (self .URL )
133+ self .assertEqual (result .text , "Hello!" )
134+
135+ span_list = self .memory_exporter .get_finished_spans ()
136+ self .assertEqual (len (span_list ), 1 )
137+ span = span_list [0 ]
138+
139+ headers = dict (httpretty .last_request ().headers )
140+ self .assertIn (MockHTTPTextFormat .TRACE_ID_KEY , headers )
141+ self .assertEqual (
142+ str (span .get_context ().trace_id ),
143+ headers [MockHTTPTextFormat .TRACE_ID_KEY ],
144+ )
145+ self .assertIn (MockHTTPTextFormat .SPAN_ID_KEY , headers )
146+ self .assertEqual (
147+ str (span .get_context ().span_id ),
148+ headers [MockHTTPTextFormat .SPAN_ID_KEY ],
149+ )
150+
151+ finally :
152+ propagators .set_global_httptextformat (previous_propagator )
0 commit comments