@@ -969,6 +969,186 @@ def raise_effect():
969969
970970 self .assertFalse (client .feature_enabled ("doesnt-exist" , "distinct_id" ))
971971
972+ @mock .patch ("posthog.client.decide" )
973+ def test_get_feature_flag_with_variant_overrides (self , patch_decide ):
974+ patch_decide .return_value = {"featureFlags" : {"beta-feature" : "variant-1" }}
975+ client = Client (FAKE_TEST_API_KEY , personal_api_key = "test" )
976+ client .feature_flags = [
977+ {
978+ "id" : 1 ,
979+ "name" : "Beta Feature" ,
980+ "key" : "beta-feature" ,
981+ "is_simple_flag" : False ,
982+ "active" : True ,
983+ "rollout_percentage" : 100 ,
984+ "filters" : {
985+ "groups" : [
986+ {
987+ "properties" : [
988+ {"key" : "email" , "type" : "person" , "value" : "test@posthog.com" , "operator" : "exact" }
989+ ],
990+ "rollout_percentage" : 100 ,
991+ "variant" : "second-variant" ,
992+ },
993+ {"rollout_percentage" : 50 , "variant" : "first-variant" },
994+ ],
995+ "multivariate" : {
996+ "variants" : [
997+ {"key" : "first-variant" , "name" : "First Variant" , "rollout_percentage" : 50 },
998+ {"key" : "second-variant" , "name" : "Second Variant" , "rollout_percentage" : 25 },
999+ {"key" : "third-variant" , "name" : "Third Variant" , "rollout_percentage" : 25 },
1000+ ]
1001+ },
1002+ },
1003+ }
1004+ ]
1005+ self .assertEqual (
1006+ client .get_feature_flag ("beta-feature" , "test_id" , person_properties = {"email" : "test@posthog.com" }),
1007+ "second-variant" ,
1008+ )
1009+ self .assertEqual (client .get_feature_flag ("beta-feature" , "example_id" ), "first-variant" )
1010+ # decide not called because this can be evaluated locally
1011+ self .assertEqual (patch_decide .call_count , 0 )
1012+
1013+ @mock .patch ("posthog.client.decide" )
1014+ def test_flag_with_clashing_variant_overrides (self , patch_decide ):
1015+ patch_decide .return_value = {"featureFlags" : {"beta-feature" : "variant-1" }}
1016+ client = Client (FAKE_TEST_API_KEY , personal_api_key = "test" )
1017+ client .feature_flags = [
1018+ {
1019+ "id" : 1 ,
1020+ "name" : "Beta Feature" ,
1021+ "key" : "beta-feature" ,
1022+ "is_simple_flag" : False ,
1023+ "active" : True ,
1024+ "rollout_percentage" : 100 ,
1025+ "filters" : {
1026+ "groups" : [
1027+ {
1028+ "properties" : [
1029+ {"key" : "email" , "type" : "person" , "value" : "test@posthog.com" , "operator" : "exact" }
1030+ ],
1031+ "rollout_percentage" : 100 ,
1032+ "variant" : "second-variant" ,
1033+ },
1034+ # since second-variant comes first in the list, it will be the one that gets picked
1035+ {
1036+ "properties" : [
1037+ {"key" : "email" , "type" : "person" , "value" : "test@posthog.com" , "operator" : "exact" }
1038+ ],
1039+ "rollout_percentage" : 100 ,
1040+ "variant" : "first-variant" ,
1041+ },
1042+ {"rollout_percentage" : 50 , "variant" : "first-variant" },
1043+ ],
1044+ "multivariate" : {
1045+ "variants" : [
1046+ {"key" : "first-variant" , "name" : "First Variant" , "rollout_percentage" : 50 },
1047+ {"key" : "second-variant" , "name" : "Second Variant" , "rollout_percentage" : 25 },
1048+ {"key" : "third-variant" , "name" : "Third Variant" , "rollout_percentage" : 25 },
1049+ ]
1050+ },
1051+ },
1052+ }
1053+ ]
1054+ self .assertEqual (
1055+ client .get_feature_flag ("beta-feature" , "test_id" , person_properties = {"email" : "test@posthog.com" }),
1056+ "second-variant" ,
1057+ )
1058+ self .assertEqual (
1059+ client .get_feature_flag ("beta-feature" , "example_id" , person_properties = {"email" : "test@posthog.com" }),
1060+ "second-variant" ,
1061+ )
1062+ # decide not called because this can be evaluated locally
1063+ self .assertEqual (patch_decide .call_count , 0 )
1064+
1065+ @mock .patch ("posthog.client.decide" )
1066+ def test_flag_with_invalid_variant_overrides (self , patch_decide ):
1067+ patch_decide .return_value = {"featureFlags" : {"beta-feature" : "variant-1" }}
1068+ client = Client (FAKE_TEST_API_KEY , personal_api_key = "test" )
1069+ client .feature_flags = [
1070+ {
1071+ "id" : 1 ,
1072+ "name" : "Beta Feature" ,
1073+ "key" : "beta-feature" ,
1074+ "is_simple_flag" : False ,
1075+ "active" : True ,
1076+ "rollout_percentage" : 100 ,
1077+ "filters" : {
1078+ "groups" : [
1079+ {
1080+ "properties" : [
1081+ {"key" : "email" , "type" : "person" , "value" : "test@posthog.com" , "operator" : "exact" }
1082+ ],
1083+ "rollout_percentage" : 100 ,
1084+ "variant" : "second???" ,
1085+ },
1086+ {"rollout_percentage" : 50 , "variant" : "first??" },
1087+ ],
1088+ "multivariate" : {
1089+ "variants" : [
1090+ {"key" : "first-variant" , "name" : "First Variant" , "rollout_percentage" : 50 },
1091+ {"key" : "second-variant" , "name" : "Second Variant" , "rollout_percentage" : 25 },
1092+ {"key" : "third-variant" , "name" : "Third Variant" , "rollout_percentage" : 25 },
1093+ ]
1094+ },
1095+ },
1096+ }
1097+ ]
1098+ self .assertEqual (
1099+ client .get_feature_flag ("beta-feature" , "test_id" , person_properties = {"email" : "test@posthog.com" }),
1100+ "third-variant" ,
1101+ )
1102+ self .assertEqual (client .get_feature_flag ("beta-feature" , "example_id" ), "second-variant" )
1103+ # decide not called because this can be evaluated locally
1104+ self .assertEqual (patch_decide .call_count , 0 )
1105+
1106+ @mock .patch ("posthog.client.decide" )
1107+ def test_flag_with_multiple_variant_overrides (self , patch_decide ):
1108+ patch_decide .return_value = {"featureFlags" : {"beta-feature" : "variant-1" }}
1109+ client = Client (FAKE_TEST_API_KEY , personal_api_key = "test" )
1110+ client .feature_flags = [
1111+ {
1112+ "id" : 1 ,
1113+ "name" : "Beta Feature" ,
1114+ "key" : "beta-feature" ,
1115+ "is_simple_flag" : False ,
1116+ "active" : True ,
1117+ "rollout_percentage" : 100 ,
1118+ "filters" : {
1119+ "groups" : [
1120+ {
1121+ "rollout_percentage" : 100 ,
1122+ # The override applies even if the first condition matches all and gives everyone their default group
1123+ },
1124+ {
1125+ "properties" : [
1126+ {"key" : "email" , "type" : "person" , "value" : "test@posthog.com" , "operator" : "exact" }
1127+ ],
1128+ "rollout_percentage" : 100 ,
1129+ "variant" : "second-variant" ,
1130+ },
1131+ {"rollout_percentage" : 50 , "variant" : "third-variant" },
1132+ ],
1133+ "multivariate" : {
1134+ "variants" : [
1135+ {"key" : "first-variant" , "name" : "First Variant" , "rollout_percentage" : 50 },
1136+ {"key" : "second-variant" , "name" : "Second Variant" , "rollout_percentage" : 25 },
1137+ {"key" : "third-variant" , "name" : "Third Variant" , "rollout_percentage" : 25 },
1138+ ]
1139+ },
1140+ },
1141+ }
1142+ ]
1143+ self .assertEqual (
1144+ client .get_feature_flag ("beta-feature" , "test_id" , person_properties = {"email" : "test@posthog.com" }),
1145+ "second-variant" ,
1146+ )
1147+ self .assertEqual (client .get_feature_flag ("beta-feature" , "example_id" ), "third-variant" )
1148+ self .assertEqual (client .get_feature_flag ("beta-feature" , "another_id" ), "second-variant" )
1149+ # decide not called because this can be evaluated locally
1150+ self .assertEqual (patch_decide .call_count , 0 )
1151+
9721152
9731153class TestMatchProperties (unittest .TestCase ):
9741154 def property (self , key , value , operator = None ):
0 commit comments