Skip to content

Commit 2d500bb

Browse files
committed
Add production-style multivariate dependency chain test
Port the "evaluates production-style multivariate dependency chain" test from posthog-node to posthog-python. This test verifies complex multivariate flag dependencies with three levels: - multivariate-leaf-flag (fruit variants: pineapple, mango, papaya, kiwi) - multivariate-intermediate-flag (color variants: blue, red) - depends on leaf flag - multivariate-root-flag (show variants: breaking-bad, the-wire) - depends on intermediate flag Tests both successful dependency chains and broken chains when dependencies fail.
1 parent bee5d81 commit 2d500bb

File tree

1 file changed

+260
-15
lines changed

1 file changed

+260
-15
lines changed

posthog/test/test_feature_flags.py

Lines changed: 260 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1867,20 +1867,23 @@ def test_multi_level_multivariate_dependency_chain(self, patch_get, patch_flags)
18671867
{
18681868
"key": "email",
18691869
"type": "person",
1870-
"value": "[email protected]",
1870+
"value": "[email protected]",
18711871
"operator": "exact",
18721872
}
18731873
],
18741874
"rollout_percentage": 100,
18751875
"variant": "test",
18761876
},
1877-
{"rollout_percentage": 50, "variant": "control"}, # Default fallback
1877+
{
1878+
"rollout_percentage": 50,
1879+
"variant": "control",
1880+
}, # Default fallback
18781881
],
18791882
"multivariate": {
18801883
"variants": [
18811884
{
18821885
"key": "control",
1883-
"name": "Control",
1886+
"name": "Control",
18841887
"rollout_percentage": 50,
18851888
},
18861889
{"key": "test", "name": "Test", "rollout_percentage": 50},
@@ -1911,7 +1914,7 @@ def test_multi_level_multivariate_dependency_chain(self, patch_get, patch_flags)
19111914
"type": "person",
19121915
"value": "blue",
19131916
"operator": "exact",
1914-
}
1917+
},
19151918
],
19161919
"rollout_percentage": 100,
19171920
"variant": "blue",
@@ -1930,11 +1933,11 @@ def test_multi_level_multivariate_dependency_chain(self, patch_get, patch_flags)
19301933
"type": "person",
19311934
"value": "green",
19321935
"operator": "exact",
1933-
}
1936+
},
19341937
],
19351938
"rollout_percentage": 100,
19361939
"variant": "green",
1937-
}
1940+
},
19381941
],
19391942
"multivariate": {
19401943
"variants": [
@@ -2001,7 +2004,7 @@ def test_multi_level_multivariate_dependency_chain(self, patch_get, patch_flags)
20012004
"any-user",
20022005
person_properties={
20032006
"email": "[email protected]",
2004-
"variant_type": "blue"
2007+
"variant_type": "blue",
20052008
},
20062009
),
20072010
)
@@ -2013,7 +2016,7 @@ def test_multi_level_multivariate_dependency_chain(self, patch_get, patch_flags)
20132016
"any-user",
20142017
person_properties={
20152018
"email": "[email protected]",
2016-
"variant_type": "green"
2019+
"variant_type": "green",
20172020
},
20182021
),
20192022
)
@@ -2026,7 +2029,7 @@ def test_multi_level_multivariate_dependency_chain(self, patch_get, patch_flags)
20262029
"any-user",
20272030
person_properties={
20282031
"email": "[email protected]", # This makes leaf-flag="test", breaking dependency
2029-
"variant_type": "blue"
2032+
"variant_type": "blue",
20302033
},
20312034
),
20322035
)
@@ -2039,7 +2042,7 @@ def test_multi_level_multivariate_dependency_chain(self, patch_get, patch_flags)
20392042
"any-user",
20402043
person_properties={
20412044
"email": "[email protected]",
2042-
"variant_type": "blue"
2045+
"variant_type": "blue",
20432046
},
20442047
),
20452048
)
@@ -2052,7 +2055,7 @@ def test_multi_level_multivariate_dependency_chain(self, patch_get, patch_flags)
20522055
"any-user",
20532056
person_properties={
20542057
"email": "[email protected]",
2055-
"variant_type": "green"
2058+
"variant_type": "green",
20562059
},
20572060
),
20582061
)
@@ -2063,10 +2066,7 @@ def test_multi_level_multivariate_dependency_chain(self, patch_get, patch_flags)
20632066
client.get_feature_flag(
20642067
"dependent-flag",
20652068
"any-user",
2066-
person_properties={
2067-
"email": "[email protected]",
2068-
"variant_type": "blue"
2069-
},
2069+
person_properties={"email": "[email protected]", "variant_type": "blue"},
20702070
),
20712071
)
20722072

@@ -2100,6 +2100,251 @@ def test_matches_dependency_value(self):
21002100
self.assertFalse(matches_dependency_value(123, "control"))
21012101
self.assertFalse(matches_dependency_value("control", True))
21022102

2103+
@mock.patch("posthog.client.flags")
2104+
@mock.patch("posthog.client.get")
2105+
def test_production_style_multivariate_dependency_chain(
2106+
self, patch_get, patch_flags
2107+
):
2108+
"""Test production-style multivariate dependency chain: multivariate-root-flag -> multivariate-intermediate-flag -> multivariate-leaf-flag"""
2109+
client = Client(FAKE_TEST_API_KEY, personal_api_key=FAKE_TEST_API_KEY)
2110+
client.feature_flags = [
2111+
# Leaf flag: multivariate with fruit variants
2112+
{
2113+
"id": 451,
2114+
"name": "Multivariate Leaf Flag (Base)",
2115+
"key": "multivariate-leaf-flag",
2116+
"active": True,
2117+
"rollout_percentage": 100,
2118+
"filters": {
2119+
"groups": [
2120+
{
2121+
"properties": [
2122+
{
2123+
"key": "email",
2124+
"type": "person",
2125+
"value": ["[email protected]"],
2126+
"operator": "exact",
2127+
}
2128+
],
2129+
"rollout_percentage": 100,
2130+
"variant": "pineapple",
2131+
},
2132+
{
2133+
"properties": [
2134+
{
2135+
"key": "email",
2136+
"type": "person",
2137+
"value": ["[email protected]"],
2138+
"operator": "exact",
2139+
}
2140+
],
2141+
"rollout_percentage": 100,
2142+
"variant": "mango",
2143+
},
2144+
{
2145+
"properties": [
2146+
{
2147+
"key": "email",
2148+
"type": "person",
2149+
"value": ["[email protected]"],
2150+
"operator": "exact",
2151+
}
2152+
],
2153+
"rollout_percentage": 100,
2154+
"variant": "papaya",
2155+
},
2156+
{
2157+
"properties": [
2158+
{
2159+
"key": "email",
2160+
"type": "person",
2161+
"value": ["[email protected]"],
2162+
"operator": "exact",
2163+
}
2164+
],
2165+
"rollout_percentage": 100,
2166+
"variant": "kiwi",
2167+
},
2168+
{
2169+
"properties": [],
2170+
"rollout_percentage": 0, # Force default to false for unknown emails
2171+
},
2172+
],
2173+
"multivariate": {
2174+
"variants": [
2175+
{"key": "pineapple", "rollout_percentage": 25},
2176+
{"key": "mango", "rollout_percentage": 25},
2177+
{"key": "papaya", "rollout_percentage": 25},
2178+
{"key": "kiwi", "rollout_percentage": 25},
2179+
]
2180+
},
2181+
},
2182+
},
2183+
# Intermediate flag: multivariate with color variants, depends on fruit
2184+
{
2185+
"id": 467,
2186+
"name": "Multivariate Intermediate Flag (Depends on fruit)",
2187+
"key": "multivariate-intermediate-flag",
2188+
"active": True,
2189+
"rollout_percentage": 100,
2190+
"filters": {
2191+
"groups": [
2192+
{
2193+
"properties": [
2194+
{
2195+
"key": "multivariate-leaf-flag",
2196+
"type": "flag",
2197+
"value": "pineapple",
2198+
"operator": "flag_evaluates_to",
2199+
"dependency_chain": ["multivariate-leaf-flag"],
2200+
}
2201+
],
2202+
"rollout_percentage": 100,
2203+
"variant": "blue",
2204+
},
2205+
{
2206+
"properties": [
2207+
{
2208+
"key": "multivariate-leaf-flag",
2209+
"type": "flag",
2210+
"value": "mango",
2211+
"operator": "flag_evaluates_to",
2212+
"dependency_chain": ["multivariate-leaf-flag"],
2213+
}
2214+
],
2215+
"rollout_percentage": 100,
2216+
"variant": "red",
2217+
},
2218+
],
2219+
"multivariate": {
2220+
"variants": [
2221+
{"key": "blue", "rollout_percentage": 100},
2222+
{"key": "red", "rollout_percentage": 0},
2223+
{"key": "green", "rollout_percentage": 0},
2224+
{"key": "black", "rollout_percentage": 0},
2225+
]
2226+
},
2227+
},
2228+
},
2229+
# Root flag: multivariate with show variants, depends on color
2230+
{
2231+
"id": 468,
2232+
"name": "Multivariate Root Flag (Depends on color)",
2233+
"key": "multivariate-root-flag",
2234+
"active": True,
2235+
"rollout_percentage": 100,
2236+
"filters": {
2237+
"groups": [
2238+
{
2239+
"properties": [
2240+
{
2241+
"key": "multivariate-intermediate-flag",
2242+
"type": "flag",
2243+
"value": "blue",
2244+
"operator": "flag_evaluates_to",
2245+
"dependency_chain": [
2246+
"multivariate-leaf-flag",
2247+
"multivariate-intermediate-flag",
2248+
],
2249+
}
2250+
],
2251+
"rollout_percentage": 100,
2252+
"variant": "breaking-bad",
2253+
},
2254+
{
2255+
"properties": [
2256+
{
2257+
"key": "multivariate-intermediate-flag",
2258+
"type": "flag",
2259+
"value": "red",
2260+
"operator": "flag_evaluates_to",
2261+
"dependency_chain": [
2262+
"multivariate-leaf-flag",
2263+
"multivariate-intermediate-flag",
2264+
],
2265+
}
2266+
],
2267+
"rollout_percentage": 100,
2268+
"variant": "the-wire",
2269+
},
2270+
],
2271+
"multivariate": {
2272+
"variants": [
2273+
{"key": "breaking-bad", "rollout_percentage": 100},
2274+
{"key": "the-wire", "rollout_percentage": 0},
2275+
{"key": "game-of-thrones", "rollout_percentage": 0},
2276+
{"key": "the-expanse", "rollout_percentage": 0},
2277+
]
2278+
},
2279+
},
2280+
},
2281+
]
2282+
2283+
# Test successful pineapple -> blue -> breaking-bad chain
2284+
leaf_result = client.get_feature_flag(
2285+
"multivariate-leaf-flag",
2286+
"test-user",
2287+
person_properties={"email": "[email protected]"},
2288+
)
2289+
intermediate_result = client.get_feature_flag(
2290+
"multivariate-intermediate-flag",
2291+
"test-user",
2292+
person_properties={"email": "[email protected]"},
2293+
)
2294+
root_result = client.get_feature_flag(
2295+
"multivariate-root-flag",
2296+
"test-user",
2297+
person_properties={"email": "[email protected]"},
2298+
)
2299+
2300+
self.assertEqual(leaf_result, "pineapple")
2301+
self.assertEqual(intermediate_result, "blue")
2302+
self.assertEqual(root_result, "breaking-bad")
2303+
2304+
# Test successful mango -> red -> the-wire chain
2305+
mango_leaf_result = client.get_feature_flag(
2306+
"multivariate-leaf-flag",
2307+
"test-user",
2308+
person_properties={"email": "[email protected]"},
2309+
)
2310+
mango_intermediate_result = client.get_feature_flag(
2311+
"multivariate-intermediate-flag",
2312+
"test-user",
2313+
person_properties={"email": "[email protected]"},
2314+
)
2315+
mango_root_result = client.get_feature_flag(
2316+
"multivariate-root-flag",
2317+
"test-user",
2318+
person_properties={"email": "[email protected]"},
2319+
)
2320+
2321+
self.assertEqual(mango_leaf_result, "mango")
2322+
self.assertEqual(mango_intermediate_result, "red")
2323+
self.assertEqual(mango_root_result, "the-wire")
2324+
2325+
# Test broken chain - user without matching email gets default/false results
2326+
unknown_leaf_result = client.get_feature_flag(
2327+
"multivariate-leaf-flag",
2328+
"test-user",
2329+
person_properties={"email": "[email protected]"},
2330+
)
2331+
unknown_intermediate_result = client.get_feature_flag(
2332+
"multivariate-intermediate-flag",
2333+
"test-user",
2334+
person_properties={"email": "[email protected]"},
2335+
)
2336+
unknown_root_result = client.get_feature_flag(
2337+
"multivariate-root-flag",
2338+
"test-user",
2339+
person_properties={"email": "[email protected]"},
2340+
)
2341+
2342+
self.assertEqual(
2343+
unknown_leaf_result, False
2344+
) # No matching email -> null variant -> false
2345+
self.assertEqual(unknown_intermediate_result, False) # Dependency not satisfied
2346+
self.assertEqual(unknown_root_result, False) # Chain broken
2347+
21032348
@mock.patch("posthog.client.Poller")
21042349
@mock.patch("posthog.client.get")
21052350
def test_load_feature_flags(self, patch_get, patch_poll):

0 commit comments

Comments
 (0)