Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion optimizely/config_manager.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2019, Optimizely
# Copyright 2019-2020, Optimizely
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
Expand Down Expand Up @@ -26,6 +26,7 @@
from .notification_center import NotificationCenter
from .helpers import enums
from .helpers import validator
from .optimizely_config import OptimizelyConfigService

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

Expand Down Expand Up @@ -89,6 +90,7 @@ def __init__(
logger=logger, error_handler=error_handler, notification_center=notification_center,
)
self._config = None
self.optimizely_config = None
self.validate_schema = not skip_json_validation
self._set_config(datafile)

Expand Down Expand Up @@ -128,6 +130,7 @@ def _set_config(self, datafile):
return

self._config = config
self.optimizely_config = OptimizelyConfigService(config).get_config()
self.notification_center.send_notifications(enums.NotificationTypes.OPTIMIZELY_CONFIG_UPDATE)
self.logger.debug(
'Received new datafile and updated config. '
Expand Down
4 changes: 4 additions & 0 deletions optimizely/optimizely.py
Original file line number Diff line number Diff line change
Expand Up @@ -751,4 +751,8 @@ def get_optimizely_config(self):
self.logger.error(enums.Errors.INVALID_PROJECT_CONFIG.format('get_optimizely_config'))
return None

# Customized Config Manager may not have optimizely_config defined.
if hasattr(self.config_manager, 'optimizely_config'):
return self.config_manager.optimizely_config

return OptimizelyConfigService(project_config).get_config()
1 change: 1 addition & 0 deletions requirements/test.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ flake8==3.6.0
funcsigs==0.4
mock==1.3.0
nose==1.3.7
pyyaml==5.2
python-coveralls==2.7.0
tabulate==0.7.5
48 changes: 45 additions & 3 deletions tests/test_config_manager.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2019, Optimizely
# Copyright 2019-2020, Optimizely
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
Expand All @@ -18,6 +18,7 @@

from optimizely import config_manager
from optimizely import exceptions as optimizely_exceptions
from optimizely import optimizely_config
from optimizely import project_config
from optimizely.helpers import enums

Expand Down Expand Up @@ -75,13 +76,19 @@ def test_set_config__success(self):
)
mock_notification_center.send_notifications.assert_called_once_with('OPTIMIZELY_CONFIG_UPDATE')

def test_set_config__twice(self):
self.assertIsInstance(
project_config_manager.optimizely_config,
optimizely_config.OptimizelyConfig
)

def test_set_config__twice__with_same_content(self):
""" Test calling set_config twice with same content to ensure config is not updated. """
test_datafile = json.dumps(self.config_dict_with_features)
mock_logger = mock.Mock()
mock_notification_center = mock.Mock()

with mock.patch('optimizely.config_manager.BaseConfigManager._validate_instantiation_options'):
with mock.patch('optimizely.config_manager.BaseConfigManager._validate_instantiation_options'), \
mock.patch('optimizely.optimizely_config.OptimizelyConfigService.get_config') as mock_opt_service:
project_config_manager = config_manager.StaticConfigManager(
datafile=test_datafile, logger=mock_logger, notification_center=mock_notification_center,
)
Expand All @@ -92,14 +99,49 @@ def test_set_config__twice(self):
)
self.assertEqual(1, mock_logger.debug.call_count)
mock_notification_center.send_notifications.assert_called_once_with('OPTIMIZELY_CONFIG_UPDATE')
self.assertEqual(1, mock_opt_service.call_count)

mock_logger.reset_mock()
mock_notification_center.reset_mock()
mock_opt_service.reset_mock()

# Call set config again and confirm that no new log message denoting config update is there
project_config_manager._set_config(test_datafile)
self.assertEqual(0, mock_logger.debug.call_count)
self.assertEqual(0, mock_notification_center.call_count)
# Assert that mock_opt_service is not called again.
self.assertEqual(0, mock_opt_service.call_count)

def test_set_config__twice__with_diff_content(self):
""" Test calling set_config twice with different content to ensure config is updated. """
test_datafile = json.dumps(self.config_dict_with_features)
mock_logger = mock.Mock()
mock_notification_center = mock.Mock()

with mock.patch('optimizely.config_manager.BaseConfigManager._validate_instantiation_options'):
project_config_manager = config_manager.StaticConfigManager(
datafile=test_datafile, logger=mock_logger, notification_center=mock_notification_center,
)

mock_logger.debug.assert_called_with(
'Received new datafile and updated config. ' 'Old revision number: None. New revision number: 1.'
)
self.assertEqual(1, mock_logger.debug.call_count)
mock_notification_center.send_notifications.assert_called_once_with('OPTIMIZELY_CONFIG_UPDATE')
self.assertEqual('1', project_config_manager.optimizely_config.revision)

mock_logger.reset_mock()
mock_notification_center.reset_mock()

# Call set config again
other_datafile = json.dumps(self.config_dict_with_multiple_experiments)
project_config_manager._set_config(other_datafile)
mock_logger.debug.assert_called_with(
'Received new datafile and updated config. ' 'Old revision number: 1. New revision number: 42.'
)
self.assertEqual(1, mock_logger.debug.call_count)
mock_notification_center.send_notifications.assert_called_once_with('OPTIMIZELY_CONFIG_UPDATE')
self.assertEqual('42', project_config_manager.optimizely_config.revision)

def test_set_config__schema_validation(self):
""" Test set_config calls or does not call schema validation based on skip_json_validation value. """
Expand Down
23 changes: 23 additions & 0 deletions tests/test_optimizely.py
Original file line number Diff line number Diff line change
Expand Up @@ -3945,6 +3945,29 @@ def test_get_optimizely_config_returns_instance_of_optimizely_config(self):
opt_config = opt_obj.get_optimizely_config()
self.assertIsInstance(opt_config, optimizely_config.OptimizelyConfig)

def test_get_optimizely_config_with_custom_config_manager(self):
""" Test that get_optimizely_config returns a valid instance of OptimizelyConfig
when a custom config manager is used. """

some_obj = optimizely.Optimizely(json.dumps(self.config_dict_with_features))
return_config = some_obj.config_manager.get_config()

class SomeConfigManager(object):
def get_config(self):
return return_config

opt_obj = optimizely.Optimizely(config_manager=SomeConfigManager())
self.assertIsInstance(
opt_obj.get_optimizely_config(),
optimizely_config.OptimizelyConfig
)

with mock.patch('optimizely.optimizely_config.OptimizelyConfigService.get_config') as mock_opt_service:
opt_obj = optimizely.Optimizely(config_manager=SomeConfigManager())
opt_obj.get_optimizely_config()

self.assertEqual(1, mock_opt_service.call_count)


class OptimizelyWithExceptionTest(base.BaseTest):
def setUp(self):
Expand Down