Skip to content

Commit 77e3dfc

Browse files
authored
Merge branch 'master' into rashid/add-revision
2 parents 434dd75 + a669f63 commit 77e3dfc

File tree

6 files changed

+397
-0
lines changed

6 files changed

+397
-0
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,8 @@ dist
1010

1111
# Output of running coverage locally
1212
.coverage
13+
14+
# From python-testapp.git
15+
.idea/
16+
.virt/
17+
datafile.json

tests/testapp/Dockerfile

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
FROM python:2.7.10
2+
3+
LABEL maintainer="developers@optimizely.com"
4+
5+
# GitHub branch from which to build the SDK. Defaults to master
6+
ARG SDK_BRANCH=master
7+
8+
ENV INSTALL_PATH /usr/src/app
9+
RUN mkdir -p $INSTALL_PATH
10+
COPY . $INSTALL_PATH
11+
WORKDIR $INSTALL_PATH
12+
13+
RUN pip install --upgrade pip
14+
RUN pip install git+git://github.com/optimizely/python-sdk@${SDK_BRANCH}
15+
RUN pip install -r requirements.txt
16+
17+
EXPOSE 3000
18+
CMD ["python", "application.py"]

tests/testapp/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# python-testapp
2+
Test application used in end-to-end testing of Optimizely X Full Stack Python projects.

tests/testapp/application.py

Lines changed: 335 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,335 @@
1+
# Copyright 2016-2018, Optimizely
2+
# Licensed under the Apache License, Version 2.0 (the "License");
3+
# you may not use this file except in compliance with the License.
4+
# You may obtain a copy of the License at
5+
#
6+
# http://www.apache.org/licenses/LICENSE-2.0
7+
8+
# Unless required by applicable law or agreed to in writing, software
9+
# distributed under the License is distributed on an "AS IS" BASIS,
10+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
# See the License for the specific language governing permissions and
12+
# limitations under the License.
13+
14+
import json
15+
import logging
16+
from os import environ
17+
import types
18+
from flask import Flask
19+
from flask import request
20+
from optimizely import logger
21+
from optimizely import notification_center
22+
from optimizely import optimizely
23+
from optimizely.helpers import enums
24+
from optimizely import entities
25+
from optimizely import event_builder
26+
27+
import user_profile_service
28+
29+
app = Flask(__name__)
30+
31+
datafile = open('datafile.json', 'r')
32+
datafile_content = datafile.read()
33+
datafile.close()
34+
35+
optimizely_instance = None
36+
user_profile_service_instance = None
37+
listener_return_maps = None
38+
39+
40+
def copy_func(f, name=None):
41+
return types.FunctionType(f.func_code, f.func_globals, name or f.func_name,
42+
f.func_defaults, f.func_closure)
43+
44+
45+
def on_activate(experiment, _user_id, _attributes, variation, event):
46+
# listener callback for activate.
47+
global listener_return_maps
48+
49+
listener_return_map = {'experiment_key': experiment.key, 'user_id': _user_id,
50+
'attributes': _attributes or {},
51+
'variation_key': variation.key}
52+
53+
if listener_return_maps is None:
54+
listener_return_maps = [listener_return_map]
55+
else:
56+
listener_return_maps.append(listener_return_map)
57+
58+
59+
def on_track(_event_key, _user_id, _attributes, _event_tags, event):
60+
# listener callback for track
61+
global listener_return_maps
62+
63+
listener_return_map = {'event_key': _event_key, "user_id": _user_id,
64+
'attributes': _attributes or {},
65+
'event_tags': _event_tags or {}}
66+
if listener_return_maps is None:
67+
listener_return_maps = [listener_return_map]
68+
else:
69+
listener_return_maps.append(listener_return_map)
70+
71+
72+
@app.before_request
73+
def before_request():
74+
global user_profile_service_instance
75+
global optimizely_instance
76+
77+
user_profile_service_instance = None
78+
optimizely_instance = None
79+
80+
request.payload = request.get_json()
81+
user_profile_service_instance = request.payload.get('user_profile_service')
82+
if user_profile_service_instance:
83+
ups_class = getattr(user_profile_service, request.payload.get('user_profile_service'))
84+
user_profile_service_instance = ups_class(request.payload.get('user_profiles'))
85+
86+
with_listener = request.payload.get('with_listener')
87+
88+
log_level = environ.get('OPTIMIZELY_SDK_LOG_LEVEL', 'DEBUG')
89+
min_level = getattr(logging, log_level)
90+
optimizely_instance = optimizely.Optimizely(datafile_content, logger=logger.SimpleLogger(min_level=min_level),
91+
user_profile_service=user_profile_service_instance)
92+
93+
if with_listener is not None:
94+
for listener_add in with_listener:
95+
if listener_add['type'] == 'Activate':
96+
count = int(listener_add['count'])
97+
for i in range(count):
98+
# make a value copy so that we can add multiple callbacks.
99+
a_cb = copy_func(on_activate)
100+
optimizely_instance.notification_center.add_notification_listener(enums.NotificationTypes.ACTIVATE, a_cb)
101+
if listener_add['type'] == 'Track':
102+
count = int(listener_add['count'])
103+
for i in range(count):
104+
# make a value copy so that we can add multiple callbacks.
105+
t_cb = copy_func(on_track)
106+
optimizely_instance.notification_center.add_notification_listener(enums.NotificationTypes.TRACK, t_cb)
107+
108+
109+
@app.after_request
110+
def after_request(response):
111+
global optimizely_instance
112+
global listener_return_maps
113+
114+
optimizely_instance.notification_center.clear_all_notifications()
115+
listener_return_maps = None
116+
return response
117+
118+
119+
@app.route('/activate', methods=['POST'])
120+
def activate():
121+
payload = request.get_json()
122+
experiment_key = payload.get('experiment_key')
123+
user_id = payload.get('user_id')
124+
attributes = payload.get('attributes')
125+
126+
variation = optimizely_instance.activate(experiment_key, user_id, attributes=attributes)
127+
user_profiles = user_profile_service_instance.user_profiles.values() if user_profile_service_instance else []
128+
129+
payload = {'result': variation, 'user_profiles': user_profiles, 'listener_called': listener_return_maps}
130+
return json.dumps(payload), 200, {'content-type': 'application/json'}
131+
132+
133+
@app.route('/get_variation', methods=['POST'])
134+
def get_variation():
135+
payload = request.get_json()
136+
experiment_key = payload.get('experiment_key')
137+
user_id = payload.get('user_id')
138+
attributes = payload.get('attributes')
139+
variation = optimizely_instance.get_variation(experiment_key, user_id, attributes=attributes)
140+
user_profiles = user_profile_service_instance.user_profiles.values() if user_profile_service_instance else []
141+
return json.dumps({'result': variation, 'user_profiles': user_profiles}), 200, {'content-type': 'application/json'}
142+
143+
144+
@app.route('/track', methods=['POST'])
145+
def track():
146+
payload = request.get_json()
147+
event_key = payload.get('event_key')
148+
user_id = payload.get('user_id')
149+
attributes = payload.get('attributes')
150+
event_tags = payload.get('event_tags')
151+
152+
result = optimizely_instance.track(event_key, user_id, attributes, event_tags)
153+
154+
user_profiles = user_profile_service_instance.user_profiles.values() if user_profile_service_instance else []
155+
156+
payload = {'result': result, 'user_profiles': user_profiles, 'listener_called': listener_return_maps}
157+
return json.dumps(payload), 200, {'content-type': 'application/json'}
158+
159+
160+
@app.route('/is_feature_enabled', methods=['POST'])
161+
def is_feature_enabled():
162+
payload = request.get_json()
163+
feature_flag_key = payload.get('feature_flag_key')
164+
user_id = payload.get('user_id')
165+
attributes = payload.get('attributes')
166+
167+
feature_enabled = optimizely_instance.is_feature_enabled(feature_flag_key, user_id, attributes)
168+
user_profiles = user_profile_service_instance.user_profiles.values() if user_profile_service_instance else {}
169+
170+
result = feature_enabled if feature_enabled is None else 'true' if feature_enabled is True else 'false'
171+
return json.dumps({'result': result, 'user_profiles': user_profiles}), 200, {'content-type': 'application/json'}
172+
173+
174+
@app.route('/get_enabled_features', methods=['POST'])
175+
def get_enabled_features():
176+
payload = request.get_json()
177+
user_id = payload.get('user_id')
178+
attributes = payload.get('attributes')
179+
180+
enabled_features = optimizely_instance.get_enabled_features(user_id, attributes)
181+
user_profiles = user_profile_service_instance.user_profiles.values() if user_profile_service_instance else {}
182+
183+
payload = {'result': enabled_features, 'user_profiles': user_profiles, 'listener_called': listener_return_maps}
184+
return json.dumps(payload), 200, {'content-type': 'application/json'}
185+
186+
187+
@app.route('/get_feature_variable_boolean', methods=['POST'])
188+
def get_feature_variable_boolean():
189+
payload = request.get_json()
190+
feature_flag_key = payload.get('feature_flag_key')
191+
variable_key = payload.get('variable_key')
192+
user_id = payload.get('user_id')
193+
attributes = payload.get('attributes')
194+
195+
boolean_value = optimizely_instance.get_feature_variable_boolean(feature_flag_key,
196+
variable_key,
197+
user_id,
198+
attributes)
199+
user_profiles = user_profile_service_instance.user_profiles.values() if user_profile_service_instance else {}
200+
return json.dumps({'result': boolean_value,
201+
'user_profiles': user_profiles}), 200, {'content-type': 'application/json'}
202+
203+
204+
@app.route('/get_feature_variable_double', methods=['POST'])
205+
def get_feature_variable_double():
206+
payload = request.get_json()
207+
feature_flag_key = payload.get('feature_flag_key')
208+
variable_key = payload.get('variable_key')
209+
user_id = payload.get('user_id')
210+
attributes = payload.get('attributes')
211+
212+
double_value = optimizely_instance.get_feature_variable_double(feature_flag_key,
213+
variable_key,
214+
user_id,
215+
attributes)
216+
217+
user_profiles = user_profile_service_instance.user_profiles.values() if user_profile_service_instance else {}
218+
return json.dumps({'result': double_value,
219+
'user_profiles': user_profiles}), 200, {'content-type': 'application/json'}
220+
221+
222+
@app.route('/get_feature_variable_integer', methods=['POST'])
223+
def get_feature_variable_integer():
224+
payload = request.get_json()
225+
feature_flag_key = payload.get('feature_flag_key')
226+
variable_key = payload.get('variable_key')
227+
user_id = payload.get('user_id')
228+
attributes = payload.get('attributes')
229+
230+
integer_value = optimizely_instance.get_feature_variable_integer(feature_flag_key,
231+
variable_key,
232+
user_id,
233+
attributes)
234+
235+
user_profiles = user_profile_service_instance.user_profiles.values() if user_profile_service_instance else {}
236+
return json.dumps({'result': integer_value,
237+
'user_profiles': user_profiles}), 200, {'content-type': 'application/json'}
238+
239+
240+
@app.route('/get_feature_variable_string', methods=['POST'])
241+
def get_feature_variable_string():
242+
payload = request.get_json()
243+
feature_flag_key = payload.get('feature_flag_key')
244+
variable_key = payload.get('variable_key')
245+
user_id = payload.get('user_id')
246+
attributes = payload.get('attributes')
247+
248+
string_value = optimizely_instance.get_feature_variable_string(feature_flag_key,
249+
variable_key,
250+
user_id,
251+
attributes)
252+
253+
user_profiles = user_profile_service_instance.user_profiles.values() if user_profile_service_instance else {}
254+
return json.dumps({'result': string_value, 'user_profiles': user_profiles}), 200, {'content-type': 'application/json'}
255+
256+
257+
@app.route('/forced_variation', methods=['POST'])
258+
def forced_variation():
259+
payload = request.get_json()
260+
user_id = payload.get('user_id')
261+
experiment_key = payload.get('experiment_key')
262+
forced_variation_key = payload.get('forced_variation_key')
263+
user_profiles = user_profile_service_instance.user_profiles.values() if user_profile_service_instance else []
264+
result = optimizely_instance.set_forced_variation(experiment_key, user_id, forced_variation_key)
265+
if result is False:
266+
return json.dumps({'result': None, 'user_profiles': user_profiles}), 400, {'content-type': 'application/json'}
267+
variation = optimizely_instance.get_forced_variation(experiment_key, user_id)
268+
return json.dumps({'result': variation, 'user_profiles': user_profiles}), 200, {'content-type': 'application/json'}
269+
270+
271+
@app.route('/forced_variation_multiple_sets', methods=['POST'])
272+
def forced_variation_multiple_sets():
273+
payload = request.get_json()
274+
user_id_1 = payload.get('user_id_1')
275+
user_id_2 = payload.get('user_id_2')
276+
experiment_key_1 = payload.get('experiment_key_1')
277+
experiment_key_2 = payload.get('experiment_key_2')
278+
forced_variation_key_1 = payload.get('forced_variation_key_1')
279+
forced_variation_key_2 = payload.get('forced_variation_key_2')
280+
user_profiles = user_profile_service_instance.user_profiles.values() if user_profile_service_instance else []
281+
result = optimizely_instance.set_forced_variation(experiment_key_1, user_id_1, forced_variation_key_1)
282+
if result is False:
283+
return json.dumps({'result': None, 'user_profiles': user_profiles}), 400, {'content-type': 'application/json'}
284+
result = optimizely_instance.set_forced_variation(experiment_key_2, user_id_1, forced_variation_key_2)
285+
if result is False:
286+
return json.dumps({'result': None, 'user_profiles': user_profiles}), 400, {'content-type': 'application/json'}
287+
result = optimizely_instance.set_forced_variation(experiment_key_1, user_id_2, forced_variation_key_1)
288+
if result is False:
289+
return json.dumps({'result': None, 'user_profiles': user_profiles}), 400, {'content-type': 'application/json'}
290+
result = optimizely_instance.set_forced_variation(experiment_key_2, user_id_2, forced_variation_key_2)
291+
if result is False:
292+
return json.dumps({'result': None, 'user_profiles': user_profiles}), 400, {'content-type': 'application/json'}
293+
variation_1 = optimizely_instance.get_forced_variation(experiment_key_1, user_id_1)
294+
variation_2 = optimizely_instance.get_forced_variation(experiment_key_2, user_id_1)
295+
variation_3 = optimizely_instance.get_forced_variation(experiment_key_1, user_id_2)
296+
variation_4 = optimizely_instance.get_forced_variation(experiment_key_2, user_id_2)
297+
return json.dumps({'result_1': variation_1,
298+
'result_2': variation_2,
299+
'result_3': variation_3,
300+
'result_4': variation_4,
301+
'user_profiles': user_profiles}), 200, {'content-type': 'application/json'}
302+
303+
304+
@app.route('/forced_variation_get_variation', methods=['POST'])
305+
def forced_variation_get_variation():
306+
payload = request.get_json()
307+
user_id = payload.get('user_id')
308+
attributes = payload.get('attributes')
309+
experiment_key = payload.get('experiment_key')
310+
forced_variation_key = payload.get('forced_variation_key')
311+
user_profiles = user_profile_service_instance.user_profiles.values() if user_profile_service_instance else []
312+
result = optimizely_instance.set_forced_variation(experiment_key, user_id, forced_variation_key)
313+
if result is False:
314+
return json.dumps({'result': None, 'user_profiles': user_profiles}), 400, {'content-type': 'application/json'}
315+
variation = optimizely_instance.get_variation(experiment_key, user_id, attributes=attributes)
316+
return json.dumps({'result': variation, 'user_profiles': user_profiles}), 200, {'content-type': 'application/json'}
317+
318+
319+
@app.route('/forced_variation_activate', methods=['POST'])
320+
def forced_variation_activate():
321+
payload = request.get_json()
322+
user_id = payload.get('user_id')
323+
attributes = payload.get('attributes')
324+
experiment_key = payload.get('experiment_key')
325+
forced_variation_key = payload.get('forced_variation_key')
326+
user_profiles = user_profile_service_instance.user_profiles.values() if user_profile_service_instance else []
327+
result = optimizely_instance.set_forced_variation(experiment_key, user_id, forced_variation_key)
328+
if result is False:
329+
return json.dumps({'result': None, 'user_profiles': user_profiles}), 400, {'content-type': 'application/json'}
330+
variation = optimizely_instance.activate(experiment_key, user_id, attributes=attributes)
331+
return json.dumps({'result': variation, 'user_profiles': user_profiles}), 200, {'content-type': 'application/json'}
332+
333+
334+
if __name__ == '__main__':
335+
app.run(host='0.0.0.0', port=3000)

tests/testapp/requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Flask==0.11.1

0 commit comments

Comments
 (0)