Skip to content

Commit 2302488

Browse files
authored
[FSSDK-9026]: Adds tests for redis cache. (#384)
* Adding tests for redis cache.
1 parent b6f4bf4 commit 2302488

File tree

6 files changed

+170
-13
lines changed

6 files changed

+170
-13
lines changed

.github/workflows/agent.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,10 @@ jobs:
106106
uses: actions/setup-python@v3
107107
with:
108108
python-version: 3.9
109+
- name: Start Redis
110+
uses: supercharge/[email protected]
111+
with:
112+
redis-version: 4
109113
- name: acceptance test
110114
run: |
111115
make -e setup build

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ help: ## help
9393
test-acceptance:
9494
export OPTIMIZELY_SERVER_BATCHREQUESTS_OPERATIONSLIMIT='3' && \
9595
export OPTIMIZELY_CLIENT_USERPROFILESERVICE='{"default":"in-memory","services":{"in-memory":{"storagestrategy":"fifo"}}}' && \
96+
export OPTIMIZELY_CLIENT_ODP_SEGMENTSCACHE='{"default":"redis","services":{"redis":{"host":"localhost:6379","password":"","timeout":"0s","database": 0}}}' && \
9697
make clean && \
9798
make setup && \
9899
make run & \

plugins/odpcache/services/redis_cache.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,14 @@ func (r *RedisCache) Lookup(key string) (segments interface{}) {
5757
return
5858
}
5959

60+
var fSegments []string
6061
// Check if result was unmarshalled successfully
61-
err := json.Unmarshal([]byte(result), &segments)
62+
err := json.Unmarshal([]byte(result), &fSegments)
6263
if err != nil {
6364
log.Error().Msg(err.Error())
6465
return
6566
}
66-
return segments
67+
return fSegments
6768
}
6869

6970
// Save is used to save segments

tests/acceptance/requirements.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ pytest==7.0.0
22
pytest-clarity==1.0.1
33
requests==2.27.1
44
openapi_core==0.14.2
5-
openapi_spec_validator==0.4.0
5+
openapi_spec_validator==0.4.0
6+
redis==4.2.2

tests/acceptance/test_acceptance/test_odp_decide.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@
1313
"ruleKey": "default-rollout-52207-23726430538",
1414
"flagKey": "flag1",
1515
"userContext": {
16-
"userId": "fs-id-1",
16+
"userId": "matjaz-user-1",
1717
"attributes": {}
1818
},
1919
"reasons": ['an error occurred while evaluating nested tree for audience ID "23783030150"',
2020
'Audiences for experiment ab_experiment collectively evaluated to false.',
21-
'User "fs-id-1" does not meet conditions to be in experiment "ab_experiment".',
21+
'User "matjaz-user-1" does not meet conditions to be in experiment "ab_experiment".',
2222
'Audiences for experiment default-rollout-52207-23726430538 collectively evaluated to true.',
23-
'User "fs-id-1" meets conditions for targeting rule "Everyone Else".']
23+
'User "matjaz-user-1" meets conditions for targeting rule "Everyone Else".']
2424
}
2525

2626
expected_no_segments_fetched = {
@@ -45,7 +45,7 @@
4545
"ruleKey": "ab_experiment",
4646
"flagKey": "flag1",
4747
"userContext": {
48-
"userId": "fs-id-1",
48+
"userId": "matjaz-user-1",
4949
"attributes": {}
5050
},
5151
"reasons": ["Audiences for experiment ab_experiment collectively evaluated to true."]
@@ -57,11 +57,11 @@
5757
"ruleKey": "default-rollout-52231-23726430538",
5858
"flagKey": "flag2",
5959
"userContext": {
60-
"userId": "fs-id-1",
60+
"userId": "matjaz-user-1",
6161
"attributes": {}
6262
},
6363
"reasons": ['Audiences for experiment default-rollout-52231-23726430538 collectively evaluated to true.',
64-
'User "fs-id-1" meets conditions for targeting rule "Everyone Else".']
64+
'User "matjaz-user-1" meets conditions for targeting rule "Everyone Else".']
6565
}
6666

6767
expected_fetch_failed = {
@@ -71,9 +71,9 @@
7171

7272
@pytest.mark.parametrize(
7373
"flag_key, expected_response, expected_status_code, fetch_segments, user_id", [
74-
("flag1", expected_fetch_disabled, 200, False, 'fs-id-1'),
75-
("flag1", expected_fetch_enabled, 200, True, 'fs-id-1'),
76-
("flag2", expected_fetch_enabled_default_rollout, 200, True, 'fs-id-1'),
74+
("flag1", expected_fetch_disabled, 200, False, 'matjaz-user-1'),
75+
("flag1", expected_fetch_enabled, 200, True, 'matjaz-user-1'),
76+
("flag2", expected_fetch_enabled_default_rollout, 200, True, 'matjaz-user-1'),
7777
("flag1", expected_no_segments_fetched, 200, True, 'test_user'),
7878
])
7979
def test_decide_fetch_qualified_segments(session_override_sdk_key_odp, flag_key, expected_response, expected_status_code, fetch_segments, user_id):
@@ -124,7 +124,7 @@ def test_decide_fetch_qualified_segments_odp_not_integrated(session_obj, flag_ke
124124
"""
125125

126126
payload = {
127-
"userId": "fs-id-1",
127+
"userId": "matjaz-user-1",
128128
"decideOptions": [
129129
"ENABLED_FLAGS_ONLY",
130130
"INCLUDE_REASONS"
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
import json
2+
3+
import pytest
4+
import requests
5+
import redis
6+
import time
7+
8+
from tests.acceptance.helpers import ENDPOINT_DECIDE
9+
from tests.acceptance.helpers import create_and_validate_request_and_response
10+
from tests.acceptance.helpers import sort_response
11+
12+
expected_redis_save = {
13+
"variationKey": "variation_b",
14+
"enabled": True,
15+
"ruleKey": "ab_experiment",
16+
"flagKey": "flag1",
17+
"userContext": {
18+
"userId": "matjaz-user-1",
19+
"attributes": {}
20+
},
21+
"reasons": ['User "matjaz-user-1" was previously bucketed into variation "variation_b" of experiment "ab_experiment".']
22+
}
23+
24+
expected_redis_lookup = {
25+
"variationKey": "variation_a",
26+
"enabled": True,
27+
"ruleKey": "ab_experiment",
28+
"flagKey": "flag1",
29+
"userContext": {
30+
"userId": "matjaz-user-2",
31+
"attributes": {}
32+
},
33+
"reasons": ["Audiences for experiment ab_experiment collectively evaluated to true."]
34+
}
35+
36+
expected_redis_reset = {
37+
"variationKey": "variation_b",
38+
"enabled": True,
39+
"ruleKey": "ab_experiment",
40+
"flagKey": "flag1",
41+
"userContext": {
42+
"userId": "matjaz-user-4",
43+
"attributes": {}
44+
},
45+
"reasons": ["Audiences for experiment ab_experiment collectively evaluated to true."]
46+
}
47+
48+
def test_redis_save(session_override_sdk_key_odp):
49+
"""
50+
Test that first fetch call saves segments in redis successfuly.
51+
:param session_override_sdk_key_odp: sdk key to override the session using odp key
52+
"""
53+
54+
expected_segments = ["atsbugbashsegmenthaspurchased", "atsbugbashsegmentdob"]
55+
uId = "fs_user_id-$-matjaz-user-1"
56+
r = redis.Redis(host='localhost', port=6379, db=0)
57+
# clean redis before testing since several tests use same user_id
58+
r.flushdb()
59+
60+
payload = {
61+
"userId": "matjaz-user-1",
62+
"decideOptions": [
63+
"ENABLED_FLAGS_ONLY",
64+
"INCLUDE_REASONS"
65+
],
66+
"userAttributes": {},
67+
"fetchSegments": True,
68+
}
69+
70+
params = {"keys": "flag1"}
71+
resp = create_and_validate_request_and_response(ENDPOINT_DECIDE, "post", session_override_sdk_key_odp, payload=json.dumps(payload),
72+
params=params)
73+
74+
# Check saved segments
75+
assert json.loads(json.dumps(expected_segments)) == json.loads(r.get(uId))
76+
77+
assert json.loads(json.dumps(expected_redis_save)) == resp.json()
78+
assert resp.status_code == 200, resp.text
79+
resp.raise_for_status()
80+
81+
82+
def test_redis_lookup(session_override_sdk_key_odp):
83+
"""
84+
Test that saved segments in redis are used successfuly by segment manager using lookup.
85+
:param session_override_sdk_key_odp: sdk key to override the session using odp key
86+
"""
87+
88+
expected_segments = ["atsbugbashsegmenthaspurchased", "atsbugbashsegmentdob"]
89+
uId = "fs_user_id-$-matjaz-user-2"
90+
r = redis.Redis(host='localhost', port=6379, db=0)
91+
r.set(uId, json.dumps(expected_segments))
92+
93+
payload = {
94+
"userId": "matjaz-user-2",
95+
"decideOptions": [
96+
"ENABLED_FLAGS_ONLY",
97+
"INCLUDE_REASONS"
98+
],
99+
"userAttributes": {},
100+
"fetchSegments": True,
101+
}
102+
103+
params = {"keys": "flag1"}
104+
resp = create_and_validate_request_and_response(ENDPOINT_DECIDE, "post", session_override_sdk_key_odp, payload=json.dumps(payload),
105+
params=params)
106+
107+
# Check saved segments
108+
assert json.loads(json.dumps(expected_segments)) == json.loads(r.get(uId))
109+
110+
assert json.loads(json.dumps(expected_redis_lookup)) == resp.json()
111+
assert resp.status_code == 200, resp.text
112+
resp.raise_for_status()
113+
114+
115+
def test_redis_reset(session_override_sdk_key_odp):
116+
"""
117+
Test that reset option resets segments in redis.
118+
:param session_override_sdk_key_odp: sdk key to override the session using odp key
119+
"""
120+
121+
expected_segments_after_reset = ['atsbugbashsegmentdob', 'atsbugbashsegmentgender']
122+
uId = "fs_user_id-$-matjaz-user-4"
123+
r = redis.Redis(host='localhost', port=6379, db=0)
124+
125+
# Manually add invalid segments for matjaz-user-4 in redis
126+
r.set(uId, json.dumps(["invalid_segments"]))
127+
# Check invalid segments were saved
128+
assert json.loads(json.dumps(["invalid_segments"])) == json.loads(r.get(uId))
129+
130+
payload = {
131+
"userId": "matjaz-user-4",
132+
"decideOptions": [
133+
"ENABLED_FLAGS_ONLY",
134+
"INCLUDE_REASONS"
135+
],
136+
"userAttributes": {},
137+
"fetchSegments": True,
138+
"fetchSegmentsOptions": ["RESET_CACHE"],
139+
}
140+
141+
params = {"keys": "flag1"}
142+
resp = create_and_validate_request_and_response(ENDPOINT_DECIDE, "post", session_override_sdk_key_odp, payload=json.dumps(payload),
143+
params=params)
144+
145+
# Check old segments were removed and newly fetched were saved
146+
assert json.loads(json.dumps(expected_segments_after_reset)) == json.loads(r.get(uId))
147+
148+
assert json.loads(json.dumps(expected_redis_reset)) == resp.json()
149+
assert resp.status_code == 200, resp.text
150+
resp.raise_for_status()

0 commit comments

Comments
 (0)