@@ -86,7 +86,6 @@ def setUp(self):
86
86
super ().setUp ()
87
87
self .event_logger = mock .Mock (spec = DebugLogger )
88
88
self .mock_span = mock .MagicMock (spec = ServerSpan )
89
- self .mock_span .context = None
90
89
91
90
def test_make_client_without_timeout_set (self , file_watcher_mock ):
92
91
with create_temp_config_file ({}) as f :
@@ -219,7 +218,8 @@ def test_make_object_for_context_and_decider_context(self):
219
218
self .assertEqual (decider_event_dict ["canonical_url" ], CANONICAL_URL )
220
219
self .assertEqual (decider_event_dict ["request" ]["canonical_url" ], CANONICAL_URL )
221
220
222
- def test_make_object_for_context_and_decider_context_without_span (self ):
221
+ @mock .patch ("reddit_decider.experiments_client_counter.labels" )
222
+ def test_make_object_for_context_without_span (self , metric_counter_labels ):
223
223
with create_temp_config_file ({}) as f :
224
224
decider_ctx_factory = decider_client_from_config (
225
225
{"experiments.path" : f .name , "experiments.timeout" : "2 seconds" },
@@ -236,13 +236,56 @@ def test_make_object_for_context_and_decider_context_without_span(self):
236
236
assert len (captured .records ) == 1
237
237
self .assertEqual (["WARNING:root:Dummy warning" ], captured .output )
238
238
239
+ metric_counter_labels .assert_called_once_with (
240
+ operation = "make_object_for_context" ,
241
+ success = "false" ,
242
+ error_type = "missing:'span'" ,
243
+ pkg_version = mock .ANY ,
244
+ )
245
+
239
246
self .assertIsInstance (decider , Decider )
240
247
241
248
decider_ctx_dict = decider ._decider_context .to_dict ()
242
249
self .assertEqual (decider_ctx_dict ["user_id" ], None )
243
250
244
- def test_make_object_for_context_and_decider_context_with_broken_decider_field_extractor (self ):
245
- def broken_decider_field_extractor (_request : RequestContext ):
251
+ @mock .patch ("reddit_decider.experiments_client_counter.labels" )
252
+ def test_make_object_for_context_with_span_context_as_None (self , metric_counter_labels ):
253
+ with create_temp_config_file ({}) as f :
254
+ decider_ctx_factory = decider_client_from_config (
255
+ {"experiments.path" : f .name , "experiments.timeout" : "2 seconds" },
256
+ self .event_logger ,
257
+ prefix = "experiments." ,
258
+ request_field_extractor = decider_field_extractor ,
259
+ )
260
+
261
+ mock_span = mock .MagicMock (spec = ServerSpan )
262
+ # span is missing context
263
+
264
+ with self .assertLogs (logger , logging .WARN ) as captured :
265
+ # ensure no warnings are printed except for the dummy one
266
+ # https://stackoverflow.com/a/61381576/4260179
267
+ logger .warning ("Dummy warning" )
268
+
269
+ decider = decider_ctx_factory .make_object_for_context (name = "test" , span = mock_span )
270
+ assert len (captured .records ) == 1
271
+ self .assertEqual (["WARNING:root:Dummy warning" ], captured .output )
272
+
273
+ metric_counter_labels .assert_called_once_with (
274
+ operation = "make_object_for_context" ,
275
+ success = "false" ,
276
+ error_type = "missing:'span.context'" ,
277
+ pkg_version = mock .ANY ,
278
+ )
279
+
280
+ self .assertIsInstance (decider , Decider )
281
+
282
+ decider_ctx_dict = decider ._decider_context .to_dict ()
283
+ self .assertEqual (decider_ctx_dict ["user_id" ], None )
284
+
285
+ def test_make_object_for_context_and_decider_context_with_malformed_decider_field_extractor (
286
+ self ,
287
+ ):
288
+ def decider_field_extractor_with_malformed_fields (_request : RequestContext ):
246
289
return {
247
290
"app_name" : {},
248
291
"build_number" : BUILD_NUMBER ,
@@ -256,7 +299,7 @@ def broken_decider_field_extractor(_request: RequestContext):
256
299
{"experiments.path" : f .name , "experiments.timeout" : "2 seconds" },
257
300
self .event_logger ,
258
301
prefix = "experiments." ,
259
- request_field_extractor = broken_decider_field_extractor ,
302
+ request_field_extractor = decider_field_extractor_with_malformed_fields ,
260
303
)
261
304
262
305
with self .assertLogs () as captured :
@@ -280,6 +323,39 @@ def broken_decider_field_extractor(_request: RequestContext):
280
323
for x in captured .records
281
324
)
282
325
326
+ @mock .patch ("reddit_decider.experiments_client_counter.labels" )
327
+ def test_make_object_for_context_with_broken_decider_field_extractor_raises_exception (
328
+ self , metric_counter_labels
329
+ ):
330
+ class SomeException (Exception ):
331
+ pass
332
+
333
+ def broken_decider_field_extractor (_request : RequestContext ):
334
+ raise SomeException ("bad extractor" )
335
+
336
+ with create_temp_config_file ({}) as f :
337
+ decider_ctx_factory = decider_client_from_config (
338
+ {"experiments.path" : f .name , "experiments.timeout" : "2 seconds" },
339
+ self .event_logger ,
340
+ prefix = "experiments." ,
341
+ request_field_extractor = broken_decider_field_extractor ,
342
+ )
343
+
344
+ with self .assertRaises (SomeException ) as e :
345
+ decider_ctx_factory .make_object_for_context (name = "test" , span = self .mock_span )
346
+
347
+ self .assertEqual (
348
+ str (e .exception ),
349
+ "bad extractor" ,
350
+ )
351
+
352
+ metric_counter_labels .assert_called_once_with (
353
+ operation = "make_object_for_context" ,
354
+ success = "false" ,
355
+ error_type = "request_field_extractor" ,
356
+ pkg_version = mock .ANY ,
357
+ )
358
+
283
359
284
360
# Todo: test DeciderClient()
285
361
# @mock.patch("reddit_decider.FileWatcher")
0 commit comments