66from unittest .mock import patch
77
88from devcycle_python_sdk import DevCycleCloudClient , DevCycleCloudOptions
9+ from devcycle_python_sdk .managers .eval_hooks_manager import BeforeHookError , AfterHookError
10+ from devcycle_python_sdk .models .eval_hook import EvalHook
911from devcycle_python_sdk .models .user import DevCycleUser
1012from devcycle_python_sdk .models .variable import Variable , TypeEnum
1113from devcycle_python_sdk .models .event import DevCycleEvent
@@ -27,6 +29,7 @@ def setUp(self) -> None:
2729 self .test_user_empty_id = DevCycleUser (user_id = "" )
2830
2931 def tearDown (self ) -> None :
32+ self .test_client .clear_hooks ()
3033 pass
3134
3235 def test_create_client_invalid_sdk_key (self ):
@@ -281,6 +284,62 @@ def test_track_exceptions(self, mock_track_call):
281284 ),
282285 )
283286
287+ @patch ("devcycle_python_sdk.api.bucketing_client.BucketingAPIClient.variable" )
288+ def test_hooks (self , mock_variable_call ):
289+ mock_variable_call .return_value = Variable (
290+ _id = "123" , key = "strKey" , value = 999 , type = TypeEnum .NUMBER
291+ )
292+ # Test adding hooks
293+ hook_called = {"before" : False , "after" : False , "finally" : False , "error" : False }
294+
295+ def before_hook (context ):
296+ hook_called ["before" ] = True
297+ return context
298+ def after_hook (context , variable ):
299+ hook_called ["after" ] = True
300+ def finally_hook (context , variable ):
301+ hook_called ["finally" ] = True
302+ def error_hook (context , error ):
303+ hook_called ["error" ] = True
304+
305+ self .test_client .add_hook (EvalHook (before_hook , after_hook , finally_hook , error_hook ))
306+
307+ # Test hooks called during variable evaluation
308+ variable = self .test_client .variable (self .test_user , "strKey" , 42 )
309+ self .assertTrue (hook_called ["before" ])
310+ self .assertTrue (hook_called ["after" ])
311+ self .assertTrue (hook_called ["finally" ])
312+ self .assertFalse (hook_called ["error" ])
313+
314+ @patch ("devcycle_python_sdk.api.bucketing_client.BucketingAPIClient.variable" )
315+ def test_hook_exceptions (self , mock_variable_call ):
316+ mock_variable_call .return_value = Variable (
317+ _id = "123" , key = "strKey" , value = 999 , type = TypeEnum .NUMBER
318+ )
319+ # Test adding hooks
320+ hook_called = {"before" : False , "after" : False , "finally" : False , "error" : False }
321+
322+ def before_hook (context ):
323+ hook_called ["before" ] = True
324+ raise Exception ("Before hook failed" )
325+ def after_hook (context , variable ):
326+ hook_called ["after" ] = True
327+ def finally_hook (context , variable ):
328+ hook_called ["finally" ] = True
329+ def error_hook (context , error ):
330+ hook_called ["error" ] = True
331+
332+ self .test_client .add_hook (EvalHook (before_hook , after_hook , finally_hook , error_hook ))
333+
334+ # Test hooks called during variable evaluation
335+ variable = self .test_client .variable (self .test_user , "strKey" , 42 )
336+ self .assertTrue (variable .value == 999 )
337+ self .assertFalse (variable .isDefaulted )
338+
339+ self .assertTrue (hook_called ["before" ])
340+ self .assertFalse (hook_called ["after" ])
341+ self .assertTrue (hook_called ["finally" ])
342+ self .assertTrue (hook_called ["error" ])
284343
285344if __name__ == "__main__" :
286345 unittest .main ()
0 commit comments