Skip to content

Commit 2ccae39

Browse files
oakbanithomaszurkan-optimizely
authored andcommitted
feat: Cache OptimizelyConfig and set Pyyaml version (#234)
* feat: Cache OptimizelyConfig * tests: Check with different content * ci: Use pyyaml 5.2 to run for Python 3.4
1 parent 1785902 commit 2ccae39

File tree

5 files changed

+77
-4
lines changed

5 files changed

+77
-4
lines changed

optimizely/config_manager.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2019, Optimizely
1+
# Copyright 2019-2020, 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,7 @@
2626
from .notification_center import NotificationCenter
2727
from .helpers import enums
2828
from .helpers import validator
29+
from .optimizely_config import OptimizelyConfigService
2930

3031
ABC = abc.ABCMeta('ABC', (object,), {'__slots__': ()})
3132

@@ -89,6 +90,7 @@ def __init__(
8990
logger=logger, error_handler=error_handler, notification_center=notification_center,
9091
)
9192
self._config = None
93+
self.optimizely_config = None
9294
self.validate_schema = not skip_json_validation
9395
self._set_config(datafile)
9496

@@ -128,6 +130,7 @@ def _set_config(self, datafile):
128130
return
129131

130132
self._config = config
133+
self.optimizely_config = OptimizelyConfigService(config).get_config()
131134
self.notification_center.send_notifications(enums.NotificationTypes.OPTIMIZELY_CONFIG_UPDATE)
132135
self.logger.debug(
133136
'Received new datafile and updated config. '

optimizely/optimizely.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -751,4 +751,8 @@ def get_optimizely_config(self):
751751
self.logger.error(enums.Errors.INVALID_PROJECT_CONFIG.format('get_optimizely_config'))
752752
return None
753753

754+
# Customized Config Manager may not have optimizely_config defined.
755+
if hasattr(self.config_manager, 'optimizely_config'):
756+
return self.config_manager.optimizely_config
757+
754758
return OptimizelyConfigService(project_config).get_config()

requirements/test.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@ flake8==3.6.0
33
funcsigs==0.4
44
mock==1.3.0
55
nose==1.3.7
6+
pyyaml==5.2
67
python-coveralls==2.7.0
78
tabulate==0.7.5

tests/test_config_manager.py

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2019, Optimizely
1+
# Copyright 2019-2020, 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
@@ -18,6 +18,7 @@
1818

1919
from optimizely import config_manager
2020
from optimizely import exceptions as optimizely_exceptions
21+
from optimizely import optimizely_config
2122
from optimizely import project_config
2223
from optimizely.helpers import enums
2324

@@ -75,13 +76,19 @@ def test_set_config__success(self):
7576
)
7677
mock_notification_center.send_notifications.assert_called_once_with('OPTIMIZELY_CONFIG_UPDATE')
7778

78-
def test_set_config__twice(self):
79+
self.assertIsInstance(
80+
project_config_manager.optimizely_config,
81+
optimizely_config.OptimizelyConfig
82+
)
83+
84+
def test_set_config__twice__with_same_content(self):
7985
""" Test calling set_config twice with same content to ensure config is not updated. """
8086
test_datafile = json.dumps(self.config_dict_with_features)
8187
mock_logger = mock.Mock()
8288
mock_notification_center = mock.Mock()
8389

84-
with mock.patch('optimizely.config_manager.BaseConfigManager._validate_instantiation_options'):
90+
with mock.patch('optimizely.config_manager.BaseConfigManager._validate_instantiation_options'), \
91+
mock.patch('optimizely.optimizely_config.OptimizelyConfigService.get_config') as mock_opt_service:
8592
project_config_manager = config_manager.StaticConfigManager(
8693
datafile=test_datafile, logger=mock_logger, notification_center=mock_notification_center,
8794
)
@@ -92,14 +99,49 @@ def test_set_config__twice(self):
9299
)
93100
self.assertEqual(1, mock_logger.debug.call_count)
94101
mock_notification_center.send_notifications.assert_called_once_with('OPTIMIZELY_CONFIG_UPDATE')
102+
self.assertEqual(1, mock_opt_service.call_count)
95103

96104
mock_logger.reset_mock()
97105
mock_notification_center.reset_mock()
106+
mock_opt_service.reset_mock()
98107

99108
# Call set config again and confirm that no new log message denoting config update is there
100109
project_config_manager._set_config(test_datafile)
101110
self.assertEqual(0, mock_logger.debug.call_count)
102111
self.assertEqual(0, mock_notification_center.call_count)
112+
# Assert that mock_opt_service is not called again.
113+
self.assertEqual(0, mock_opt_service.call_count)
114+
115+
def test_set_config__twice__with_diff_content(self):
116+
""" Test calling set_config twice with different content to ensure config is updated. """
117+
test_datafile = json.dumps(self.config_dict_with_features)
118+
mock_logger = mock.Mock()
119+
mock_notification_center = mock.Mock()
120+
121+
with mock.patch('optimizely.config_manager.BaseConfigManager._validate_instantiation_options'):
122+
project_config_manager = config_manager.StaticConfigManager(
123+
datafile=test_datafile, logger=mock_logger, notification_center=mock_notification_center,
124+
)
125+
126+
mock_logger.debug.assert_called_with(
127+
'Received new datafile and updated config. ' 'Old revision number: None. New revision number: 1.'
128+
)
129+
self.assertEqual(1, mock_logger.debug.call_count)
130+
mock_notification_center.send_notifications.assert_called_once_with('OPTIMIZELY_CONFIG_UPDATE')
131+
self.assertEqual('1', project_config_manager.optimizely_config.revision)
132+
133+
mock_logger.reset_mock()
134+
mock_notification_center.reset_mock()
135+
136+
# Call set config again
137+
other_datafile = json.dumps(self.config_dict_with_multiple_experiments)
138+
project_config_manager._set_config(other_datafile)
139+
mock_logger.debug.assert_called_with(
140+
'Received new datafile and updated config. ' 'Old revision number: 1. New revision number: 42.'
141+
)
142+
self.assertEqual(1, mock_logger.debug.call_count)
143+
mock_notification_center.send_notifications.assert_called_once_with('OPTIMIZELY_CONFIG_UPDATE')
144+
self.assertEqual('42', project_config_manager.optimizely_config.revision)
103145

104146
def test_set_config__schema_validation(self):
105147
""" Test set_config calls or does not call schema validation based on skip_json_validation value. """

tests/test_optimizely.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3945,6 +3945,29 @@ def test_get_optimizely_config_returns_instance_of_optimizely_config(self):
39453945
opt_config = opt_obj.get_optimizely_config()
39463946
self.assertIsInstance(opt_config, optimizely_config.OptimizelyConfig)
39473947

3948+
def test_get_optimizely_config_with_custom_config_manager(self):
3949+
""" Test that get_optimizely_config returns a valid instance of OptimizelyConfig
3950+
when a custom config manager is used. """
3951+
3952+
some_obj = optimizely.Optimizely(json.dumps(self.config_dict_with_features))
3953+
return_config = some_obj.config_manager.get_config()
3954+
3955+
class SomeConfigManager(object):
3956+
def get_config(self):
3957+
return return_config
3958+
3959+
opt_obj = optimizely.Optimizely(config_manager=SomeConfigManager())
3960+
self.assertIsInstance(
3961+
opt_obj.get_optimizely_config(),
3962+
optimizely_config.OptimizelyConfig
3963+
)
3964+
3965+
with mock.patch('optimizely.optimizely_config.OptimizelyConfigService.get_config') as mock_opt_service:
3966+
opt_obj = optimizely.Optimizely(config_manager=SomeConfigManager())
3967+
opt_obj.get_optimizely_config()
3968+
3969+
self.assertEqual(1, mock_opt_service.call_count)
3970+
39483971

39493972
class OptimizelyWithExceptionTest(base.BaseTest):
39503973
def setUp(self):

0 commit comments

Comments
 (0)