Skip to content

Commit 5f05c9b

Browse files
Gracefully handle v1 datafile (#44)
1 parent ae4b03c commit 5f05c9b

File tree

5 files changed

+50
-15
lines changed

5 files changed

+50
-15
lines changed

optimizely/helpers/enums.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,5 @@ class Errors(object):
3939
INVALID_DATAFILE = 'Datafile has invalid format. Failing "{}".'
4040
INVALID_GROUP_ID_ERROR = 'Provided group is not in datafile.'
4141
INVALID_VARIATION_ERROR = 'Provided variation is not in datafile.'
42-
UNSUPPORTED_DATAFILE_VERSION = 'Provided datafile has unsupported version.'
42+
UNSUPPORTED_DATAFILE_VERSION = 'Provided datafile has unsupported version. ' \
43+
'Please use SDK version 1.1.0 or earlier for datafile version 1.'

optimizely/optimizely.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,14 +66,14 @@ def __init__(self, datafile, event_dispatcher=None, logger=None, error_handler=N
6666
self.logger.log(enums.LogLevels.ERROR, enums.Errors.INVALID_INPUT_ERROR.format('datafile'))
6767
return
6868

69-
self.bucketer = bucketer.Bucketer(self.config)
70-
71-
try:
72-
self.event_builder = event_builder.EventBuilder(self.config, self.bucketer)
73-
except:
69+
if not self.config.was_parsing_successful():
7470
self.is_valid = False
7571
self.logger = SimpleLogger()
7672
self.logger.log(enums.LogLevels.ERROR, enums.Errors.UNSUPPORTED_DATAFILE_VERSION)
73+
return
74+
75+
self.bucketer = bucketer.Bucketer(self.config)
76+
self.event_builder = event_builder.EventBuilder(self.config, self.bucketer)
7777

7878
def _validate_inputs(self, datafile, skip_json_validation):
7979
""" Helper method to validate all input parameters.

optimizely/project_config.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
V1_CONFIG_VERSION = '1'
2323
V2_CONFIG_VERSION = '2'
2424

25+
SUPPORTED_VERSIONS = [V2_CONFIG_VERSION]
26+
UNSUPPORTED_VERSIONS = [V1_CONFIG_VERSION]
27+
2528

2629
class ProjectConfig(object):
2730
""" Representation of the Optimizely project config. """
@@ -36,17 +39,19 @@ def __init__(self, datafile, logger, error_handler):
3639
"""
3740

3841
config = json.loads(datafile)
42+
self.parsing_succeeded = False
3943
self.logger = logger
4044
self.error_handler = error_handler
4145
self.version = config.get('version')
46+
if self.version in UNSUPPORTED_VERSIONS:
47+
return
4248
self.account_id = config.get('accountId')
4349
self.project_id = config.get('projectId')
4450
self.revision = config.get('revision')
4551
self.groups = config.get('groups', [])
4652
self.experiments = config.get('experiments', [])
4753
self.events = config.get('events', [])
48-
self.attributes = config.get('dimensions', []) \
49-
if self.version == V1_CONFIG_VERSION else config.get('attributes', [])
54+
self.attributes = config.get('attributes', [])
5055
self.audiences = config.get('audiences', [])
5156

5257
# Utility maps for quick lookup
@@ -77,6 +82,8 @@ def __init__(self, datafile, logger, error_handler):
7782
for variation in self.variation_key_map.get(experiment.key).values():
7883
self.variation_id_map[experiment.key][variation.id] = variation
7984

85+
self.parsing_succeeded = True
86+
8087
@staticmethod
8188
def _generate_key_map(list, key, entity_class):
8289
""" Helper method to generate map from key to entity object for given list of dicts.
@@ -116,6 +123,15 @@ def _deserialize_audience(audience_map):
116123

117124
return audience_map
118125

126+
def was_parsing_successful(self):
127+
""" Helper method to determine if parsing the datafile was successful.
128+
129+
Returns:
130+
Boolean depending on whether parsing the datafile succeeded or not.
131+
"""
132+
133+
return self.parsing_succeeded
134+
119135
def get_version(self):
120136
""" Get version of the datafile.
121137

tests/helpers_tests/test_validator.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ def test_is_datafile_valid__returns_true(self):
112112
def test_is_datafile_valid__returns_false(self):
113113
""" Test that invalid datafile returns False. """
114114

115+
# When schema is not valid
115116
self.assertFalse(validator.is_datafile_valid(json.dumps({
116117
'invalid_key': 'invalid_value'
117118
})))
118-

tests/test_optimizely.py

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from optimizely import exceptions
1919
from optimizely import logger
2020
from optimizely import optimizely
21+
from optimizely import project_config
2122
from optimizely import version
2223
from optimizely.helpers import enums
2324
from . import base
@@ -37,9 +38,10 @@ def test_init__invalid_datafile__logs_error(self):
3738
""" Test that invalid datafile logs error on init. """
3839

3940
with mock.patch('optimizely.logger.SimpleLogger.log') as mock_logging:
40-
optimizely.Optimizely('invalid_datafile')
41+
opt_obj = optimizely.Optimizely('invalid_datafile')
4142

4243
mock_logging.assert_called_once_with(enums.LogLevels.ERROR, 'Provided "datafile" is in an invalid format.')
44+
self.assertFalse(opt_obj.is_valid)
4345

4446
def test_init__invalid_event_dispatcher__logs_error(self):
4547
""" Test that invalid event_dispatcher logs error on init. """
@@ -48,31 +50,47 @@ class InvalidDispatcher(object):
4850
pass
4951

5052
with mock.patch('optimizely.logger.SimpleLogger.log') as mock_logging:
51-
optimizely.Optimizely(json.dumps(self.config_dict), event_dispatcher=InvalidDispatcher)
53+
opt_obj = optimizely.Optimizely(json.dumps(self.config_dict), event_dispatcher=InvalidDispatcher)
5254

5355
mock_logging.assert_called_once_with(enums.LogLevels.ERROR, 'Provided "event_dispatcher" is in an invalid format.')
56+
self.assertFalse(opt_obj.is_valid)
5457

55-
def test_init__invalid_logger__raises(self):
58+
def test_init__invalid_logger__logs_error(self):
5659
""" Test that invalid logger logs error on init. """
5760

5861
class InvalidLogger(object):
5962
pass
6063

6164
with mock.patch('optimizely.logger.SimpleLogger.log') as mock_logging:
62-
optimizely.Optimizely(json.dumps(self.config_dict), logger=InvalidLogger)
65+
opt_obj = optimizely.Optimizely(json.dumps(self.config_dict), logger=InvalidLogger)
6366

6467
mock_logging.assert_called_once_with(enums.LogLevels.ERROR, 'Provided "logger" is in an invalid format.')
68+
self.assertFalse(opt_obj.is_valid)
6569

66-
def test_init__invalid_error_handler__raises(self):
70+
def test_init__invalid_error_handler__logs_error(self):
6771
""" Test that invalid error_handler logs error on init. """
6872

6973
class InvalidErrorHandler(object):
7074
pass
7175

7276
with mock.patch('optimizely.logger.SimpleLogger.log') as mock_logging:
73-
optimizely.Optimizely(json.dumps(self.config_dict), error_handler=InvalidErrorHandler)
77+
opt_obj = optimizely.Optimizely(json.dumps(self.config_dict), error_handler=InvalidErrorHandler)
7478

7579
mock_logging.assert_called_once_with(enums.LogLevels.ERROR, 'Provided "error_handler" is in an invalid format.')
80+
self.assertFalse(opt_obj.is_valid)
81+
82+
def test_init__v1_datafile__logs_error(self):
83+
""" Test that v1 datafile logs error on init. """
84+
85+
self.config_dict['version'] = project_config.V1_CONFIG_VERSION
86+
with mock.patch('optimizely.logger.SimpleLogger.log') as mock_logging:
87+
opt_obj = optimizely.Optimizely(json.dumps(self.config_dict))
88+
89+
mock_logging.assert_called_once_with(
90+
enums.LogLevels.ERROR,
91+
'Provided datafile has unsupported version. Please use SDK version 1.1.0 or earlier for datafile version 1.'
92+
)
93+
self.assertFalse(opt_obj.is_valid)
7694

7795
def test_skip_json_validation_true(self):
7896
""" Test that on setting skip_json_validation to true, JSON schema validation is not performed. """

0 commit comments

Comments
 (0)