Skip to content

Commit 9e9c4d0

Browse files
sdk_key and environment_key support (#338)
* added sdk and environment key * [MAINTENANCE] Remove Deprecated warnings during build - assertRaisesRegexp -> assertRaisesRegex - assertEquals -> assertEqual - isAlive() -> is_alive() - Check added to base.py to confirm attribute assertRaisesRegex for backwards compatibility to Python2.7 * [OASIS-7757] Fix spelling of environment to fix testcases from failing * [OASIS-7757] - Added additional test cases to test_optimizely and test_user_context. * [OASIS-7757] - update copyright years and add more testcases for sdk_key and environment_key. Move decide tests to test_user_context from test_optimizely. Co-authored-by: ozayr-zaviar <[email protected]>
1 parent c3b191b commit 9e9c4d0

6 files changed

+158
-25
lines changed

optimizely/optimizely_config.py

+29-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2020, Optimizely
1+
# Copyright 2020-2021, Optimizely
22
# Licensed under the Apache License, Version 2.0 (the "License");
33
# you may not use this file except in compliance with the License.
44
# You may obtain a copy of the License at
@@ -17,11 +17,13 @@
1717

1818

1919
class OptimizelyConfig(object):
20-
def __init__(self, revision, experiments_map, features_map, datafile=None):
20+
def __init__(self, revision, experiments_map, features_map, datafile=None, sdk_key=None, environment_key=None):
2121
self.revision = revision
2222
self.experiments_map = experiments_map
2323
self.features_map = features_map
2424
self._datafile = datafile
25+
self.sdk_key = sdk_key
26+
self.environment_key = environment_key
2527

2628
def get_datafile(self):
2729
""" Get the datafile associated with OptimizelyConfig.
@@ -31,6 +33,22 @@ def get_datafile(self):
3133
"""
3234
return self._datafile
3335

36+
def get_sdk_key(self):
37+
""" Get the sdk key associated with OptimizelyConfig.
38+
39+
Returns:
40+
A string containing sdk key.
41+
"""
42+
return self.sdk_key
43+
44+
def get_environment_key(self):
45+
""" Get the environemnt key associated with OptimizelyConfig.
46+
47+
Returns:
48+
A string containing environment key.
49+
"""
50+
return self.environment_key
51+
3452

3553
class OptimizelyExperiment(object):
3654
def __init__(self, id, key, variations_map):
@@ -82,6 +100,8 @@ def __init__(self, project_config):
82100
self.feature_flags = project_config.feature_flags
83101
self.groups = project_config.groups
84102
self.revision = project_config.revision
103+
self.sdk_key = project_config.sdk_key
104+
self.environment_key = project_config.environment_key
85105

86106
self._create_lookup_maps()
87107

@@ -98,7 +118,13 @@ def get_config(self):
98118
experiments_key_map, experiments_id_map = self._get_experiments_maps()
99119
features_map = self._get_features_map(experiments_id_map)
100120

101-
return OptimizelyConfig(self.revision, experiments_key_map, features_map, self._datafile)
121+
return OptimizelyConfig(
122+
self.revision,
123+
experiments_key_map,
124+
features_map,
125+
self._datafile,
126+
self.sdk_key,
127+
self.environment_key)
102128

103129
def _create_lookup_maps(self):
104130
""" Creates lookup maps to avoid redundant iteration of config objects. """

optimizely/optimizely_factory.py

-1
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,6 @@ def default_instance_with_config_manager(config_manager):
113113
def custom_instance(sdk_key, datafile=None, event_dispatcher=None, logger=None, error_handler=None,
114114
skip_json_validation=None, user_profile_service=None, config_manager=None,
115115
notification_center=None):
116-
117116
""" Returns a new optimizely instance.
118117
if max_event_batch_size and max_event_flush_interval are None then default batch_size and flush_interval
119118
will be used to setup BatchEventProcessor.

optimizely/project_config.py

+21-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2016-2019, Optimizely
1+
# Copyright 2016-2019, 2021, Optimizely
22
# Licensed under the Apache License, Version 2.0 (the "License");
33
# you may not use this file except in compliance with the License.
44
# You may obtain a copy of the License at
@@ -52,6 +52,8 @@ def __init__(self, datafile, logger, error_handler):
5252
self.account_id = config.get('accountId')
5353
self.project_id = config.get('projectId')
5454
self.revision = config.get('revision')
55+
self.sdk_key = config.get('sdkKey', None)
56+
self.environment_key = config.get('environmentKey', None)
5557
self.groups = config.get('groups', [])
5658
self.experiments = config.get('experiments', [])
5759
self.events = config.get('events', [])
@@ -213,6 +215,24 @@ def get_revision(self):
213215

214216
return self.revision
215217

218+
def get_sdk_key(self):
219+
""" Get sdk key from the datafile.
220+
221+
Returns:
222+
Revision of the sdk key.
223+
"""
224+
225+
return self.sdk_key
226+
227+
def get_environment_key(self):
228+
""" Get environment key from the datafile.
229+
230+
Returns:
231+
Revision of the environment key.
232+
"""
233+
234+
return self.environment_key
235+
216236
def get_account_id(self):
217237
""" Get account ID from the config.
218238

tests/test_optimizely.py

-19
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
from optimizely import optimizely_config
2727
from optimizely import project_config
2828
from optimizely import version
29-
from optimizely.decision.optimizely_decide_option import OptimizelyDecideOption as DecideOption
3029
from optimizely.event.event_factory import EventFactory
3130
from optimizely.helpers import enums
3231
from . import base
@@ -677,24 +676,6 @@ def on_activate(experiment, user_id, attributes, variation, event):
677676
self.assertEqual(1, mock_process.call_count)
678677
self.assertEqual(True, access_callback[0])
679678

680-
def test_decide_experiment(self):
681-
""" Test that the feature is enabled for the user if bucketed into variation of a rollout.
682-
Also confirm that no impression event is processed. """
683-
684-
opt_obj = optimizely.Optimizely(json.dumps(self.config_dict_with_features))
685-
project_config = opt_obj.config_manager.get_config()
686-
687-
mock_experiment = project_config.get_experiment_from_key('test_experiment')
688-
mock_variation = project_config.get_variation_from_id('test_experiment', '111129')
689-
with mock.patch(
690-
'optimizely.decision_service.DecisionService.get_variation_for_feature',
691-
return_value=(decision_service.Decision(mock_experiment,
692-
mock_variation, enums.DecisionSources.FEATURE_TEST), []),
693-
):
694-
user_context = opt_obj.create_user_context('test_user')
695-
decision = user_context.decide('test_feature_in_experiment', [DecideOption.DISABLE_DECISION_EVENT])
696-
self.assertTrue(decision.enabled, "decision should be enabled")
697-
698679
def test_activate__with_attributes__audience_match(self):
699680
""" Test that activate calls process with right params and returns expected
700681
variation when attributes are provided and audience conditions are met. """

tests/test_optimizely_config.py

+59-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2020, Optimizely
1+
# Copyright 2020-2021, Optimizely
22
# Licensed under the Apache License, Version 2.0 (the "License");
33
# you may not use this file except in compliance with the License.
44
# You may obtain a copy of the License at
@@ -26,6 +26,8 @@ def setUp(self):
2626
self.opt_config_service = optimizely_config.OptimizelyConfigService(self.project_config)
2727

2828
self.expected_config = {
29+
'sdk_key': None,
30+
'environment_key': None,
2931
'experiments_map': {
3032
'test_experiment2': {
3133
'variations_map': {
@@ -732,3 +734,59 @@ def test__get_datafile(self):
732734
actual_datafile = self.actual_config.get_datafile()
733735

734736
self.assertEqual(expected_datafile, actual_datafile)
737+
738+
def test__get_sdk_key(self):
739+
""" Test that get_sdk_key returns the expected value. """
740+
741+
config = optimizely_config.OptimizelyConfig(
742+
revision='101',
743+
experiments_map={},
744+
features_map={},
745+
sdk_key='testSdkKey',
746+
)
747+
748+
expected_value = 'testSdkKey'
749+
750+
self.assertEqual(expected_value, config.get_sdk_key())
751+
752+
def test__get_sdk_key_invalid(self):
753+
""" Negative Test that tests get_sdk_key does not return the expected value. """
754+
755+
config = optimizely_config.OptimizelyConfig(
756+
revision='101',
757+
experiments_map={},
758+
features_map={},
759+
sdk_key='testSdkKey',
760+
)
761+
762+
invalid_value = 123
763+
764+
self.assertNotEqual(invalid_value, config.get_sdk_key())
765+
766+
def test__get_environment_key(self):
767+
""" Test that get_environment_key returns the expected value. """
768+
769+
config = optimizely_config.OptimizelyConfig(
770+
revision='101',
771+
experiments_map={},
772+
features_map={},
773+
environment_key='TestEnvironmentKey'
774+
)
775+
776+
expected_value = 'TestEnvironmentKey'
777+
778+
self.assertEqual(expected_value, config.get_environment_key())
779+
780+
def test__get_environment_key_invalid(self):
781+
""" Negative Test that tests get_environment_key does not return the expected value. """
782+
783+
config = optimizely_config.OptimizelyConfig(
784+
revision='101',
785+
experiments_map={},
786+
features_map={},
787+
environment_key='testEnvironmentKey'
788+
)
789+
790+
invalid_value = 321
791+
792+
self.assertNotEqual(invalid_value, config.get_environment_key())

tests/test_user_context.py

+49
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import mock
1616

1717
from optimizely.decision.optimizely_decision import OptimizelyDecision
18+
from optimizely.decision.optimizely_decide_option import OptimizelyDecideOption as DecideOption
1819
from optimizely.helpers import enums
1920
from . import base
2021
from optimizely import optimizely, decision_service
@@ -60,6 +61,23 @@ def test_user_context(self):
6061
self.assertEqual("firefox", uc.get_user_attributes()["browser"])
6162
self.assertEqual("red", uc.get_user_attributes()["color"])
6263

64+
def test_user_and_attributes_as_json(self):
65+
"""
66+
tests user context as json
67+
"""
68+
uc = OptimizelyUserContext(self.optimizely, "test_user")
69+
70+
# set an attribute
71+
uc.set_attribute("browser", "safari")
72+
73+
# set expected json obj
74+
expected_json = {
75+
"user_id": uc.user_id,
76+
"attributes": uc.get_user_attributes(),
77+
}
78+
79+
self.assertEqual(uc.as_json(), expected_json)
80+
6381
def test_attributes_are_cloned_when_passed_to_user_context(self):
6482
user_id = 'test_user'
6583
attributes = {"browser": "chrome"}
@@ -1247,3 +1265,34 @@ def test_decide_reasons__whitelisted_variation(self):
12471265
expected_reasons = ['User "user_1" is forced in variation "control".']
12481266

12491267
self.assertEqual(expected_reasons, actual.reasons)
1268+
1269+
def test_init__invalid_default_decide_options(self):
1270+
"""
1271+
Test to confirm that default decide options passed not as a list will trigger setting
1272+
self.deafulat_decide_options as an empty list.
1273+
"""
1274+
invalid_decide_options = {"testKey": "testOption"}
1275+
1276+
mock_client_logger = mock.MagicMock()
1277+
with mock.patch('optimizely.logger.reset_logger', return_value=mock_client_logger):
1278+
opt_obj = optimizely.Optimizely(default_decide_options=invalid_decide_options)
1279+
1280+
self.assertEqual(opt_obj.default_decide_options, [])
1281+
1282+
def test_decide_experiment(self):
1283+
""" Test that the feature is enabled for the user if bucketed into variation of a rollout.
1284+
Also confirm that no impression event is processed. """
1285+
1286+
opt_obj = optimizely.Optimizely(json.dumps(self.config_dict_with_features))
1287+
project_config = opt_obj.config_manager.get_config()
1288+
1289+
mock_experiment = project_config.get_experiment_from_key('test_experiment')
1290+
mock_variation = project_config.get_variation_from_id('test_experiment', '111129')
1291+
with mock.patch(
1292+
'optimizely.decision_service.DecisionService.get_variation_for_feature',
1293+
return_value=(decision_service.Decision(mock_experiment,
1294+
mock_variation, enums.DecisionSources.FEATURE_TEST), []),
1295+
):
1296+
user_context = opt_obj.create_user_context('test_user')
1297+
decision = user_context.decide('test_feature_in_experiment', [DecideOption.DISABLE_DECISION_EVENT])
1298+
self.assertTrue(decision.enabled, "decision should be enabled")

0 commit comments

Comments
 (0)