@@ -79,15 +79,20 @@ class In_subsegment(NamedTuple):
79
79
80
80
81
81
def test_tracer_lambda_handler (mocker , dummy_response , provider_stub , in_subsegment_mock ):
82
+ # GIVEN Tracer is initialized with booking as the service name
82
83
provider = provider_stub (in_subsegment = in_subsegment_mock .in_subsegment )
83
84
tracer = Tracer (provider = provider , service = "booking" )
84
85
86
+ # WHEN lambda_handler decorator is used
85
87
@tracer .capture_lambda_handler
86
88
def handler (event , context ):
87
89
return dummy_response
88
90
89
91
handler ({}, mocker .MagicMock ())
90
92
93
+ # THEN we should have a subsegment named handler
94
+ # annotate cold start, and add its response as trace metadata
95
+ # and use service name as a metadata namespace
91
96
assert in_subsegment_mock .in_subsegment .call_count == 1
92
97
assert in_subsegment_mock .in_subsegment .call_args == mocker .call (name = "## handler" )
93
98
assert in_subsegment_mock .put_metadata .call_args == mocker .call (
@@ -98,141 +103,180 @@ def handler(event, context):
98
103
99
104
100
105
def test_tracer_method (mocker , dummy_response , provider_stub , in_subsegment_mock ):
106
+ # GIVEN Tracer is initialized with booking as the service name
101
107
provider = provider_stub (in_subsegment = in_subsegment_mock .in_subsegment )
102
- Tracer (provider = provider , service = "booking" )
108
+ tracer = Tracer (provider = provider , service = "booking" )
109
+
110
+ # WHEN capture_method decorator is used
111
+ @tracer .capture_method
112
+ def greeting (name , message ):
113
+ return dummy_response
114
+
115
+ greeting (name = "Foo" , message = "Bar" )
116
+
117
+ # THEN we should have a subsegment named after the method name
118
+ # and add its response as trace metadata
119
+ # and use service name as a metadata namespace
120
+ assert in_subsegment_mock .in_subsegment .call_count == 1
121
+ assert in_subsegment_mock .in_subsegment .call_args == mocker .call (name = "## greeting" )
122
+ assert in_subsegment_mock .put_metadata .call_args == mocker .call (
123
+ key = "greeting response" , value = dummy_response , namespace = "booking"
124
+ )
103
125
104
126
105
127
def test_tracer_custom_metadata (mocker , dummy_response , provider_stub ):
128
+ # GIVEN Tracer is initialized with booking as the service name
106
129
put_metadata_mock = mocker .MagicMock ()
107
- annotation_key = "Booking response"
108
- annotation_value = {"bookingStatus" : "CONFIRMED" }
109
-
110
130
provider = provider_stub (put_metadata_mock = put_metadata_mock )
111
131
tracer = Tracer (provider = provider , service = "booking" )
132
+
133
+ # WHEN put_metadata is used
134
+ annotation_key = "Booking response"
135
+ annotation_value = {"bookingStatus" : "CONFIRMED" }
112
136
tracer .put_metadata (annotation_key , annotation_value )
113
137
138
+ # THEN we should have metadata expected and booking as namespace
114
139
assert put_metadata_mock .call_count == 1
115
140
assert put_metadata_mock .call_args_list [0 ] == mocker .call (
116
141
key = annotation_key , value = annotation_value , namespace = "booking"
117
142
)
118
143
119
144
120
145
def test_tracer_custom_annotation (mocker , dummy_response , provider_stub ):
146
+ # GIVEN Tracer is initialized
121
147
put_annotation_mock = mocker .MagicMock ()
122
- annotation_key = "BookingId"
123
- annotation_value = "123456"
124
-
125
148
provider = provider_stub (put_annotation_mock = put_annotation_mock )
126
- tracer = Tracer (provider = provider , service = "booking" )
149
+ tracer = Tracer (provider = provider )
127
150
151
+ # WHEN put_metadata is used
152
+ annotation_key = "BookingId"
153
+ annotation_value = "123456"
128
154
tracer .put_annotation (annotation_key , annotation_value )
129
155
156
+ # THEN we should have an annotation as expected
130
157
assert put_annotation_mock .call_count == 1
131
158
assert put_annotation_mock .call_args == mocker .call (key = annotation_key , value = annotation_value )
132
159
133
160
134
161
@mock .patch ("aws_lambda_powertools.tracing.Tracer.patch" )
135
162
def test_tracer_autopatch (patch_mock ):
136
- # GIVEN tracer is instantiated
137
- # WHEN default options were used, or patch() was called
138
- # THEN tracer should patch all modules
163
+ # GIVEN tracer is initialized
164
+ # WHEN auto_patch hasn't been explicitly disabled
139
165
Tracer (disabled = True )
166
+
167
+ # THEN tracer should patch all modules
140
168
assert patch_mock .call_count == 1
141
169
142
170
143
171
@mock .patch ("aws_lambda_powertools.tracing.Tracer.patch" )
144
172
def test_tracer_no_autopatch (patch_mock ):
145
- # GIVEN tracer is instantiated
173
+ # GIVEN tracer is initialized
146
174
# WHEN auto_patch is disabled
147
- # THEN tracer should not patch any module
148
175
Tracer (disabled = True , auto_patch = False )
176
+
177
+ # THEN tracer should not patch any module
149
178
assert patch_mock .call_count == 0
150
179
151
180
152
- def test_tracer_lambda_handler_empty_response_metadata (mocker , provider_stub ):
181
+ def test_tracer_lambda_handler_does_not_add_empty_response_as_metadata (mocker , provider_stub ):
182
+ # GIVEN tracer is initialized
153
183
put_metadata_mock = mocker .MagicMock ()
154
184
provider = provider_stub (put_metadata_mock = put_metadata_mock )
155
185
tracer = Tracer (provider = provider )
156
186
187
+ # WHEN capture_lambda_handler decorator is used
188
+ # and the handler response is empty
157
189
@tracer .capture_lambda_handler
158
190
def handler (event , context ):
159
191
return
160
192
161
193
handler ({}, mocker .MagicMock ())
162
194
195
+ # THEN we should not add empty metadata
163
196
assert put_metadata_mock .call_count == 0
164
197
165
198
166
- def test_tracer_method_empty_response_metadata (mocker , provider_stub ):
199
+ def test_tracer_method_does_not_add_empty_response_as_metadata (mocker , provider_stub ):
200
+ # GIVEN tracer is initialized
167
201
put_metadata_mock = mocker .MagicMock ()
168
202
provider = provider_stub (put_metadata_mock = put_metadata_mock )
169
203
tracer = Tracer (provider = provider )
170
204
205
+ # WHEN capture_method decorator is used
206
+ # and the method response is empty
171
207
@tracer .capture_method
172
208
def greeting (name , message ):
173
209
return
174
210
175
211
greeting (name = "Foo" , message = "Bar" )
176
212
213
+ # THEN we should not add empty metadata
177
214
assert put_metadata_mock .call_count == 0
178
215
179
216
180
217
@mock .patch ("aws_lambda_powertools.tracing.tracer.aws_xray_sdk.core.patch" )
181
- @mock .patch ("aws_lambda_powertools.tracing.tracer.aws_xray_sdk.core.patch_all" )
182
- def test_tracer_patch (xray_patch_all_mock , xray_patch_mock , mocker ):
183
- # GIVEN tracer is instantiated
184
- # WHEN default X-Ray provider client is mocked
185
- # THEN tracer should run just fine
186
-
187
- Tracer ()
188
- assert xray_patch_all_mock .call_count == 1
189
-
218
+ def test_tracer_patch_modules (xray_patch_mock , mocker ):
219
+ # GIVEN tracer is initialized with a list of modules to patch
190
220
modules = ["boto3" ]
221
+
222
+ # WHEN modules are supported by X-Ray
191
223
Tracer (service = "booking" , patch_modules = modules )
192
224
225
+ # THEN tracer should run just fine
193
226
assert xray_patch_mock .call_count == 1
194
227
assert xray_patch_mock .call_args == mocker .call (modules )
195
228
196
229
197
230
def test_tracer_method_exception_metadata (mocker , provider_stub , in_subsegment_mock ):
198
-
231
+ # GIVEN tracer is initialized
199
232
provider = provider_stub (in_subsegment = in_subsegment_mock .in_subsegment )
200
233
tracer = Tracer (provider = provider , service = "booking" )
201
234
235
+ # WHEN capture_method decorator is used
236
+ # and the method raises an exception
202
237
@tracer .capture_method
203
238
def greeting (name , message ):
204
239
raise ValueError ("test" )
205
240
206
241
with pytest .raises (ValueError ):
207
242
greeting (name = "Foo" , message = "Bar" )
208
243
244
+ # THEN we should add the exception using method name as key plus error
245
+ # and their service name as the namespace
209
246
put_metadata_mock_args = in_subsegment_mock .put_metadata .call_args [1 ]
210
247
assert put_metadata_mock_args ["key" ] == "greeting error"
211
248
assert put_metadata_mock_args ["namespace" ] == "booking"
212
249
213
250
214
251
def test_tracer_lambda_handler_exception_metadata (mocker , provider_stub , in_subsegment_mock ):
215
-
252
+ # GIVEN tracer is initialized
216
253
provider = provider_stub (in_subsegment = in_subsegment_mock .in_subsegment )
217
254
tracer = Tracer (provider = provider , service = "booking" )
218
255
256
+ # WHEN capture_lambda_handler decorator is used
257
+ # and the method raises an exception
219
258
@tracer .capture_lambda_handler
220
259
def handler (event , context ):
221
260
raise ValueError ("test" )
222
261
223
262
with pytest .raises (ValueError ):
224
263
handler ({}, mocker .MagicMock ())
225
264
265
+ # THEN we should add the exception using handler name as key plus error
266
+ # and their service name as the namespace
226
267
put_metadata_mock_args = in_subsegment_mock .put_metadata .call_args [1 ]
227
- assert put_metadata_mock_args ["key" ] == "booking error"
268
+ assert put_metadata_mock_args ["key" ] == "handler error"
269
+
228
270
assert put_metadata_mock_args ["namespace" ] == "booking"
229
271
230
272
231
273
@pytest .mark .asyncio
232
274
async def test_tracer_method_nested_async (mocker , dummy_response , provider_stub , in_subsegment_mock ):
275
+ # GIVEN tracer is initialized
233
276
provider = provider_stub (in_subsegment_async = in_subsegment_mock .in_subsegment )
234
277
tracer = Tracer (provider = provider , service = "booking" )
235
278
279
+ # WHEN capture_method decorator is used for nested async methods
236
280
@tracer .capture_method
237
281
async def greeting_2 (name , message ):
238
282
return dummy_response
@@ -250,6 +294,7 @@ async def greeting(name, message):
250
294
) = in_subsegment_mock .in_subsegment .call_args_list
251
295
put_metadata_greeting2_call_args , put_metadata_greeting_call_args = in_subsegment_mock .put_metadata .call_args_list
252
296
297
+ # THEN we should add metadata for each response like we would for a sync decorated method
253
298
assert in_subsegment_mock .in_subsegment .call_count == 2
254
299
assert in_subsegment_greeting_call_args == mocker .call (name = "## greeting" )
255
300
assert in_subsegment_greeting2_call_args == mocker .call (name = "## greeting_2" )
@@ -265,9 +310,10 @@ async def greeting(name, message):
265
310
266
311
@pytest .mark .asyncio
267
312
async def test_tracer_method_nested_async_disabled (dummy_response ):
268
-
313
+ # GIVEN tracer is initialized and explicitly disabled
269
314
tracer = Tracer (service = "booking" , disabled = True )
270
315
316
+ # WHEN capture_method decorator is used
271
317
@tracer .capture_method
272
318
async def greeting_2 (name , message ):
273
319
return dummy_response
@@ -277,23 +323,28 @@ async def greeting(name, message):
277
323
await greeting_2 (name , message )
278
324
return dummy_response
279
325
326
+ # THEN we should run the decorator methods without side effects
280
327
ret = await greeting (name = "Foo" , message = "Bar" )
281
-
282
328
assert ret == dummy_response
283
329
284
330
285
331
@pytest .mark .asyncio
286
332
async def test_tracer_method_exception_metadata_async (mocker , provider_stub , in_subsegment_mock ):
333
+ # GIVEN tracer is initialized
287
334
provider = provider_stub (in_subsegment_async = in_subsegment_mock .in_subsegment )
288
335
tracer = Tracer (provider = provider , service = "booking" )
289
336
337
+ # WHEN capture_method decorator is used in an async method
338
+ # and the method raises an exception
290
339
@tracer .capture_method
291
340
async def greeting (name , message ):
292
341
raise ValueError ("test" )
293
342
294
343
with pytest .raises (ValueError ):
295
344
await greeting (name = "Foo" , message = "Bar" )
296
345
346
+ # THEN we should add the exception using method name as key plus error
347
+ # and their service name as the namespace
297
348
put_metadata_mock_args = in_subsegment_mock .put_metadata .call_args [1 ]
298
349
assert put_metadata_mock_args ["key" ] == "greeting error"
299
350
assert put_metadata_mock_args ["namespace" ] == "booking"
0 commit comments