@@ -969,6 +969,186 @@ def raise_effect():
969
969
970
970
self .assertFalse (client .feature_enabled ("doesnt-exist" , "distinct_id" ))
971
971
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" :
"[email protected] " ,
"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" :
"[email protected] " }),
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" :
"[email protected] " ,
"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" :
"[email protected] " ,
"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" :
"[email protected] " }),
1056
+ "second-variant" ,
1057
+ )
1058
+ self .assertEqual (
1059
+ client .
get_feature_flag (
"beta-feature" ,
"example_id" ,
person_properties = {
"email" :
"[email protected] " }),
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" :
"[email protected] " ,
"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" :
"[email protected] " }),
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" :
"[email protected] " ,
"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" :
"[email protected] " }),
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
+
972
1152
973
1153
class TestMatchProperties (unittest .TestCase ):
974
1154
def property (self , key , value , operator = None ):
0 commit comments