@@ -533,14 +533,109 @@ def test_get_feature_flag_result_flag_not_in_response(
533533
534534 @mock .patch ("posthog.client.flags" )
535535 @mock .patch .object (Client , "capture" )
536- def test_get_feature_flag_result_request_error (self , patch_capture , patch_flags ):
537- """Test that when the /flags call throws an exception, we capture it in the event.
536+ def test_get_feature_flag_result_unknown_error (self , patch_capture , patch_flags ):
537+ """Test that unexpected exceptions are captured as unknown_error."""
538+ patch_flags .side_effect = Exception ("Unexpected error" )
538539
539- This simulates what likely happened in production: the remote evaluation failed
540- (network error, timeout, etc.), so request_id is never set, and we capture the
541- $feature_flag_called event with a null response, no request_id, and an error.
542- """
543- patch_flags .side_effect = Exception ("Network timeout" )
540+ flag_result = self .client .get_feature_flag_result ("my-flag" , "some-distinct-id" )
541+
542+ self .assertIsNone (flag_result )
543+ patch_capture .assert_called_with (
544+ "$feature_flag_called" ,
545+ distinct_id = "some-distinct-id" ,
546+ properties = {
547+ "$feature_flag" : "my-flag" ,
548+ "$feature_flag_response" : None ,
549+ "locally_evaluated" : False ,
550+ "$feature/my-flag" : None ,
551+ "$feature_flag_error" : "unknown_error" ,
552+ },
553+ groups = {},
554+ disable_geoip = None ,
555+ )
556+
557+ @mock .patch ("posthog.client.flags" )
558+ @mock .patch .object (Client , "capture" )
559+ def test_get_feature_flag_result_timeout_error (self , patch_capture , patch_flags ):
560+ """Test that timeout errors are captured specifically."""
561+ import requests .exceptions
562+
563+ patch_flags .side_effect = requests .exceptions .Timeout ("Request timed out" )
564+
565+ flag_result = self .client .get_feature_flag_result ("my-flag" , "some-distinct-id" )
566+
567+ self .assertIsNone (flag_result )
568+ patch_capture .assert_called_with (
569+ "$feature_flag_called" ,
570+ distinct_id = "some-distinct-id" ,
571+ properties = {
572+ "$feature_flag" : "my-flag" ,
573+ "$feature_flag_response" : None ,
574+ "locally_evaluated" : False ,
575+ "$feature/my-flag" : None ,
576+ "$feature_flag_error" : "timeout" ,
577+ },
578+ groups = {},
579+ disable_geoip = None ,
580+ )
581+
582+ @mock .patch ("posthog.client.flags" )
583+ @mock .patch .object (Client , "capture" )
584+ def test_get_feature_flag_result_connection_error (self , patch_capture , patch_flags ):
585+ """Test that connection errors are captured specifically."""
586+ import requests .exceptions
587+
588+ patch_flags .side_effect = requests .exceptions .ConnectionError ("Connection refused" )
589+
590+ flag_result = self .client .get_feature_flag_result ("my-flag" , "some-distinct-id" )
591+
592+ self .assertIsNone (flag_result )
593+ patch_capture .assert_called_with (
594+ "$feature_flag_called" ,
595+ distinct_id = "some-distinct-id" ,
596+ properties = {
597+ "$feature_flag" : "my-flag" ,
598+ "$feature_flag_response" : None ,
599+ "locally_evaluated" : False ,
600+ "$feature/my-flag" : None ,
601+ "$feature_flag_error" : "connection_error" ,
602+ },
603+ groups = {},
604+ disable_geoip = None ,
605+ )
606+
607+ @mock .patch ("posthog.client.flags" )
608+ @mock .patch .object (Client , "capture" )
609+ def test_get_feature_flag_result_api_error (self , patch_capture , patch_flags ):
610+ """Test that API errors include the status code."""
611+ from posthog .request import APIError
612+
613+ patch_flags .side_effect = APIError (500 , "Internal server error" )
614+
615+ flag_result = self .client .get_feature_flag_result ("my-flag" , "some-distinct-id" )
616+
617+ self .assertIsNone (flag_result )
618+ patch_capture .assert_called_with (
619+ "$feature_flag_called" ,
620+ distinct_id = "some-distinct-id" ,
621+ properties = {
622+ "$feature_flag" : "my-flag" ,
623+ "$feature_flag_response" : None ,
624+ "locally_evaluated" : False ,
625+ "$feature/my-flag" : None ,
626+ "$feature_flag_error" : "api_error_500" ,
627+ },
628+ groups = {},
629+ disable_geoip = None ,
630+ )
631+
632+ @mock .patch ("posthog.client.flags" )
633+ @mock .patch .object (Client , "capture" )
634+ def test_get_feature_flag_result_quota_limited (self , patch_capture , patch_flags ):
635+ """Test that quota limit errors are captured specifically."""
636+ from posthog .request import QuotaLimitError
637+
638+ patch_flags .side_effect = QuotaLimitError (429 , "Rate limit exceeded" )
544639
545640 flag_result = self .client .get_feature_flag_result ("my-flag" , "some-distinct-id" )
546641
@@ -553,7 +648,7 @@ def test_get_feature_flag_result_request_error(self, patch_capture, patch_flags)
553648 "$feature_flag_response" : None ,
554649 "locally_evaluated" : False ,
555650 "$feature/my-flag" : None ,
556- "$feature_flag_error" : "request_error " ,
651+ "$feature_flag_error" : "quota_limited " ,
557652 },
558653 groups = {},
559654 disable_geoip = None ,
0 commit comments