From 2ee24cf2f0a5a6e60bf9e490b15f5ae5ac53bda7 Mon Sep 17 00:00:00 2001 From: Jake Brown Date: Mon, 28 Jun 2021 15:09:25 -0400 Subject: [PATCH] Add attributes and events support to config (#339) * 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-7800] Updated optimizely_config with attributes and events * [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. * [OASIS-7800] Updated optimizely_config with attributes and events * Run autopep8 to fix formatting issues after rebase * [OASIS-7800] - Added test cases for attribute map and events map * Remove unused import from optimizely config * Corrected comment wording in get functions for events. Co-authored-by: ozayr-zaviar --- optimizely/optimizely_config.py | 74 +++++++++++++++++++- tests/test_optimizely_config.py | 115 ++++++++++++++++++++++++++++++++ 2 files changed, 187 insertions(+), 2 deletions(-) diff --git a/optimizely/optimizely_config.py b/optimizely/optimizely_config.py index 50543f85..47dae824 100644 --- a/optimizely/optimizely_config.py +++ b/optimizely/optimizely_config.py @@ -17,13 +17,16 @@ class OptimizelyConfig(object): - def __init__(self, revision, experiments_map, features_map, datafile=None, sdk_key=None, environment_key=None): + def __init__(self, revision, experiments_map, features_map, datafile=None, + sdk_key=None, environment_key=None, attributes=None, events=None): self.revision = revision self.experiments_map = experiments_map self.features_map = features_map self._datafile = datafile self.sdk_key = sdk_key self.environment_key = environment_key + self.attributes = attributes or [] + self.events = events or [] def get_datafile(self): """ Get the datafile associated with OptimizelyConfig. @@ -49,6 +52,22 @@ def get_environment_key(self): """ return self.environment_key + def get_attributes(self): + """ Get the attributes associated with OptimizelyConfig + + returns: + A list of attributes. + """ + return self.attributes + + def get_events(self): + """ Get the events associated with OptimizelyConfig + + returns: + A list of events. + """ + return self.events + class OptimizelyExperiment(object): def __init__(self, id, key, variations_map): @@ -81,6 +100,19 @@ def __init__(self, id, key, variable_type, value): self.value = value +class OptimizelyAttribute(object): + def __init__(self, id, key): + self.id = id + self.key = key + + +class OptimizelyEvent(object): + def __init__(self, id, key, experiment_ids): + self.id = id + self.key = key + self.experiment_ids = experiment_ids + + class OptimizelyConfigService(object): """ Class encapsulating methods to be used in creating instance of OptimizelyConfig. """ @@ -102,6 +134,8 @@ def __init__(self, project_config): self.revision = project_config.revision self.sdk_key = project_config.sdk_key self.environment_key = project_config.environment_key + self.attributes = project_config.attributes + self.events = project_config.events self._create_lookup_maps() @@ -124,7 +158,9 @@ def get_config(self): features_map, self._datafile, self.sdk_key, - self.environment_key) + self.environment_key, + self.attributes, + self.events) def _create_lookup_maps(self): """ Creates lookup maps to avoid redundant iteration of config objects. """ @@ -259,3 +295,37 @@ def _get_features_map(self, experiments_id_map): features_map[feature['key']] = optly_feature return features_map + + def get_attributes_map(self): + """ Gets attributes map for the project config. + + Returns: + dict -- Attribute key, OptimizelyAttribute map + """ + + attributes_map = {} + + for attribute in self.attributes: + optly_attribute = OptimizelyAttribute( + attribute['id'], attribute['key'] + ) + attributes_map[attribute['key']] = optly_attribute + + return attributes_map + + def get_events_map(self): + """ Gets events map for the project config. + + Returns: + dict -- Event key, OptimizelyEvent map + """ + + events_map = {} + + for event in self.events: + optly_event = OptimizelyEvent( + event['id'], event['key'], event.get('experimentIds', []) + ) + events_map[event['key']] = optly_event + + return events_map diff --git a/tests/test_optimizely_config.py b/tests/test_optimizely_config.py index d86c7a74..8ff8986b 100644 --- a/tests/test_optimizely_config.py +++ b/tests/test_optimizely_config.py @@ -28,6 +28,8 @@ def setUp(self): self.expected_config = { 'sdk_key': None, 'environment_key': None, + 'attributes': [{'key': 'test_attribute', 'id': '111094'}], + 'events': [{'key': 'test_event', 'experimentIds': ['111127'], 'id': '111095'}], 'experiments_map': { 'test_experiment2': { 'variations_map': { @@ -790,3 +792,116 @@ def test__get_environment_key_invalid(self): invalid_value = 321 self.assertNotEqual(invalid_value, config.get_environment_key()) + + def test__get_attributes(self): + """ Test that the get_attributes returns the expected value. """ + + config = optimizely_config.OptimizelyConfig( + revision='101', + experiments_map={}, + features_map={}, + attributes=[{ + 'id': '123', + 'key': '123' + }, + { + 'id': '234', + 'key': '234' + }] + ) + + expected_value = [{ + 'id': '123', + 'key': '123' + }, + { + 'id': '234', + 'key': '234' + }] + + self.assertEqual(expected_value, config.get_attributes()) + self.assertEqual(len(config.get_attributes()), 2) + + def test__get_events(self): + """ Test that the get_events returns the expected value. """ + + config = optimizely_config.OptimizelyConfig( + revision='101', + experiments_map={}, + features_map={}, + events=[{ + 'id': '123', + 'key': '123', + 'experiment_ids': { + '54321' + } + }, + { + 'id': '234', + 'key': '234', + 'experiment_ids': { + '3211', '54365' + } + }] + ) + + expected_value = [{ + 'id': '123', + 'key': '123', + 'experiment_ids': { + '54321' + } + }, + { + 'id': '234', + 'key': '234', + 'experiment_ids': { + '3211', + '54365' + } + }] + + self.assertEqual(expected_value, config.get_events()) + self.assertEqual(len(config.get_events()), 2) + + def test__get_attributes_map(self): + """ Test to check get_attributes_map returns the correct value """ + + actual_attributes_map = self.opt_config_service.get_attributes_map() + expected_attributes = self.expected_config['attributes'] + + expected_attributes_map = {} + + for expected_attribute in expected_attributes: + optly_attribute = optimizely_config.OptimizelyAttribute( + expected_attribute['id'], expected_attribute['key'] + ) + expected_attributes_map[expected_attribute['key']] = optly_attribute + + for attribute in actual_attributes_map.values(): + self.assertIsInstance(attribute, optimizely_config.OptimizelyAttribute) + + self.assertEqual(len(expected_attributes), len(actual_attributes_map)) + self.assertEqual(self.to_dict(actual_attributes_map), self.to_dict(expected_attributes_map)) + + def test__get_events_map(self): + """ Test to check that get_events_map returns the correct value """ + + actual_events_map = self.opt_config_service.get_events_map() + expected_events = self.expected_config['events'] + + expected_events_map = {} + + for expected_event in expected_events: + optly_event = optimizely_config.OptimizelyEvent( + expected_event['id'], + expected_event['key'], + expected_event['experimentIds'] + ) + expected_events_map[expected_event['key']] = optly_event + + for event in actual_events_map.values(): + self.assertIsInstance(event, optimizely_config.OptimizelyEvent) + + self.assertEqual(len(expected_events), len(actual_events_map)) + self.assertEqual(self.to_dict(actual_events_map), self.to_dict(expected_events_map))