def __init__(self, api_key, **kwargs): super(MainSplitFactory, self).__init__() config = dict() if 'config' in kwargs: config = kwargs['config'] labels_enabled = config.get('labelsEnabled', True) impression_listener = ImpressionListenerWrapper( config.get('impressionListener') ) if 'impressionListener' in config else None # noqa: E501,E261 if 'redisHost' in config or 'redisSentinels' in config: broker = get_redis_broker(api_key, **kwargs) self._client = Client(broker, labels_enabled, impression_listener) self._manager = RedisSplitManager(broker) else: if 'uwsgiClient' in config and config['uwsgiClient']: broker = get_uwsgi_broker(api_key, **kwargs) self._client = Client(broker, labels_enabled, impression_listener) self._manager = UWSGISplitManager(broker) else: broker = get_self_refreshing_broker(api_key, **kwargs) self._client = Client(broker, labels_enabled, impression_listener) self._manager = SelfRefreshingSplitManager(broker)
class RedisReadOnlyTest(TestCase, MockUtilsMixin): def setUp(self): self._some_config = mock.MagicMock() self._split_changes_file_name = join(dirname(__file__), 'splitChangesReadOnly.json') with open(self._split_changes_file_name) as f: self._json = load(f) split_definition = self._json['splits'][0] split_name = split_definition['name'] self._redis = get_redis({'redisPrefix': 'test'}) self._mocked_redis = ReadOnlyRedisMock(self._redis) self._redis_split_cache = RedisSplitCache(self._redis) self._redis_split_cache.add_split(split_name, split_definition) self._client = Client(RedisBroker(self._mocked_redis, self._some_config)) self._impression = mock.MagicMock() self._start = mock.MagicMock() self._operation = mock.MagicMock() def test_redis_read_only_mode(self): self.assertEqual(self._client.get_treatment('valid', 'test_read_only_1'), 'on') self.assertEqual(self._client.get_treatment('invalid', 'test_read_only_1'), 'off') self.assertEqual(self._client.get_treatment('valid', 'test_read_only_1_invalid'), 'control')
def setUp(self): self.some_config = mock.MagicMock() self.some_api_key = mock.MagicMock() self.redis = get_redis({'redisPrefix': 'test'}) self.client = Client(RedisBroker(self.redis, self.some_config)) input_validator._LOGGER.error = mock.MagicMock() self.logger_error = input_validator._LOGGER.error input_validator._LOGGER.warning = mock.MagicMock() self.logger_warning = input_validator._LOGGER.warning
def setUp(self): self.some_config = mock.MagicMock() self.some_api_key = mock.MagicMock() self.redis = get_redis({'redisPrefix': 'test'}) self.client = Client(RedisBroker(self.redis, self.some_config)) self.client._broker.fetch_feature = mock.MagicMock( return_value=Split("some_feature", 0, False, "default_treatment", "user", "ACTIVE", 123)) self.client._build_impression = mock.MagicMock() input_validator._LOGGER.error = mock.MagicMock() self.logger_error = input_validator._LOGGER.error input_validator._LOGGER.warning = mock.MagicMock() self.logger_warning = input_validator._LOGGER.warning
def test_client_raise_attribute_error(self): client_1 = Client(RedisBroker(self._redis, self._some_config), True, ImpressionListenerClientEmpty()) with self.assertRaises(AttributeError): client_1._impression_listener.log_impression( self.some_impression_0)
def setUp(self): self._some_config = mock.MagicMock() self._split_changes_file_name = join( dirname(__file__), 'splitCustomImpressionListener.json') with open(self._split_changes_file_name) as f: self._json = load(f) split_definition = self._json['splits'][0] split_name = split_definition['name'] self._redis = get_redis( {'redisPrefix': 'customImpressionListenerTest'}) self._redis_split_cache = RedisSplitCache(self._redis) self._redis_split_cache.add_split(split_name, split_definition) self._client = Client(RedisBroker(self._redis, self._some_config)) self.some_feature = 'feature_0' self.some_impression_0 = Impression(matching_key=mock.MagicMock(), feature_name=self.some_feature, treatment=mock.MagicMock(), label=mock.MagicMock(), change_number=mock.MagicMock(), bucketing_key=mock.MagicMock(), time=mock.MagicMock())
def setUp(self): self._some_config = mock.MagicMock() self._split_changes_file_name = join(dirname(__file__), 'splitGetTreatments.json') with open(self._split_changes_file_name) as f: self._json = load(f) split_definition = self._json['splits'][0] split_name = split_definition['name'] self._redis = get_redis({'redisPrefix': 'getTreatmentsTest'}) self._redis_split_cache = RedisSplitCache(self._redis) self._redis_split_cache.add_split(split_name, split_definition) self._client = Client(RedisBroker(self._redis, self._some_config)) self._config = { 'ready': 180000, 'redisDb': 0, 'redisHost': 'localhost', 'redisPosrt': 6379, 'redisPrefix': 'getTreatmentsTest' } self._factory = get_factory('asdqwe123456', config=self._config) self._split = self._factory.client()
def setUp(self): self.some_api_key = mock.MagicMock() self.broker = SelfRefreshingBroker(self.some_api_key) self.client = Client(self.broker) self.manager = SelfRefreshingSplitManager(self.broker) input_validator._LOGGER.error = mock.MagicMock() self.logger_error = input_validator._LOGGER.error
def setUp(self): self.some_api_key = mock.MagicMock() self.uwsgi = UWSGICacheEmulator() self.broker = UWSGIBroker(self.uwsgi, {'eventsQueueSize': 30}) self.client = Client(self.broker) self.manager = UWSGISplitManager(self.broker) input_validator._LOGGER.error = mock.MagicMock() self.logger_error = input_validator._LOGGER.error
def setUp(self): self._some_config = mock.MagicMock() self._split_changes_file_name = join(dirname(__file__), 'splitChangesReadOnly.json') with open(self._split_changes_file_name) as f: self._json = load(f) split_definition = self._json['splits'][0] split_name = split_definition['name'] self._redis = get_redis({'redisPrefix': 'test'}) self._mocked_redis = ReadOnlyRedisMock(self._redis) self._redis_split_cache = RedisSplitCache(self._redis) self._redis_split_cache.add_split(split_name, split_definition) self._client = Client(RedisBroker(self._mocked_redis, self._some_config)) self._impression = mock.MagicMock() self._start = mock.MagicMock() self._operation = mock.MagicMock()
def __init__(self, api_key, **kwargs): super(MainSplitFactory, self).__init__() config = dict() if 'config' in kwargs: config = kwargs['config'] labels_enabled = config.get('labelsEnabled', True) if 'redisHost' in config: broker = get_redis_broker(api_key, **kwargs) self._client = Client(broker, labels_enabled) self._manager = RedisSplitManager(broker) else: if 'uwsgiClient' in config and config['uwsgiClient']: broker = get_uwsgi_broker(api_key, **kwargs) self._client = Client(broker, labels_enabled) self._manager = UWSGISplitManager(broker) else: broker = get_self_refreshing_broker(api_key, **kwargs) self._client = Client(broker, labels_enabled) self._manager = SelfRefreshingSplitManager(broker)
def __init__(self, **kwargs): super(LocalhostSplitFactory, self).__init__() if 'split_definition_file_name' in kwargs: broker = get_self_refreshing_broker( 'localhost', split_definition_file_name=kwargs['split_definition_file_name'] ) else: broker = get_self_refreshing_broker('localhost') self._client = Client(broker) self._manager = LocalhostSplitManager(broker.get_split_fetcher())
class TestInputSanitizationGetTreatmentS(TestCase): def setUp(self): self.some_config = mock.MagicMock() self.some_api_key = mock.MagicMock() self.redis = get_redis({'redisPrefix': 'test'}) self.client = Client(RedisBroker(self.redis, self.some_config)) input_validator._LOGGER.error = mock.MagicMock() self.logger_error = input_validator._LOGGER.error input_validator._LOGGER.warning = mock.MagicMock() self.logger_warning = input_validator._LOGGER.warning def test_get_treatments_with_null_features(self): self.assertEqual(None, self.client.get_treatments("some_key", None)) self.logger_error \ .assert_called_once_with("get_treatments: features cannot be None.") def test_get_treatments_with_bool_type_of_features(self): self.assertEqual(None, self.client.get_treatments("some_key", True)) self.logger_error \ .assert_called_once_with("get_treatments: features must be a list.") def test_get_treatments_with_string_type_of_features(self): self.assertEqual(None, self.client.get_treatments("some_key", "some_string")) self.logger_error \ .assert_called_once_with("get_treatments: features must be a list.") def test_get_treatments_with_empty_features(self): self.assertEqual({}, self.client.get_treatments("some_key", [])) self.logger_warning \ .assert_called_once_with("get_treatments: features is an empty " "list or has None values.") def test_get_treatments_with_none_features(self): self.assertEqual({}, self.client.get_treatments("some_key", [None, None])) self.logger_warning \ .assert_called_once_with("get_treatments: features is an empty " "list or has None values.") def test_get_treatments_with_invalid_type_of_features(self): self.assertEqual({}, self.client.get_treatments("some_key", [True])) self.logger_error \ .assert_called_once_with("get_treatments: feature_name has to be of type string.")
def setUp(self): ''' ''' redis = get_redis({}) segment_cache = RedisSegmentCache(redis) split_parser = RedisSplitParser(segment_cache) self._client = Client(RedisBroker(redis)) self._splitObjects = {} raw_split = { 'name': 'test1', 'algo': 1, 'killed': False, 'status': 'ACTIVE', 'defaultTreatment': 'default', 'seed': -1222652054, 'orgId': None, 'environment': None, 'trafficTypeId': None, 'trafficTypeName': None, 'changeNumber': 1, 'conditions': [{ 'conditionType': 'WHITELIST', 'matcherGroup': { 'combiner': 'AND', 'matchers': [{ 'matcherType': 'ALL_KEYS', 'negate': False, 'userDefinedSegmentMatcherData': None, 'whitelistMatcherData': None }] }, 'partitions': [{ 'treatment': 'on', 'size': 100 }], 'label': 'in segment all' }] } self._splitObjects['whitelist'] = split_parser.parse(raw_split, True) raw_split['name'] = 'test2' raw_split['conditions'][0]['conditionType'] = 'ROLLOUT' self._splitObjects['rollout1'] = split_parser.parse(raw_split, True) raw_split['name'] = 'test3' raw_split['trafficAllocation'] = 1 raw_split['trafficAllocationSeed'] = -1 self._splitObjects['rollout2'] = split_parser.parse(raw_split, True) raw_split['name'] = 'test4' raw_split['trafficAllocation'] = None #must be mapped as 100 raw_split['trafficAllocationSeed'] = -1 self._splitObjects['rollout3'] = split_parser.parse(raw_split, True)
class TestInputSanitizationGetTreatment(TestCase): def setUp(self): self.some_config = mock.MagicMock() self.some_api_key = mock.MagicMock() self.redis = get_redis({'redisPrefix': 'test'}) self.client = Client(RedisBroker(self.redis, self.some_config)) self.client._broker.fetch_feature = mock.MagicMock( return_value=Split("some_feature", 0, False, "default_treatment", "user", "ACTIVE", 123)) self.client._build_impression = mock.MagicMock() input_validator._LOGGER.error = mock.MagicMock() self.logger_error = input_validator._LOGGER.error input_validator._LOGGER.warning = mock.MagicMock() self.logger_warning = input_validator._LOGGER.warning def test_get_treatment_with_null_key(self): self.assertEqual(CONTROL, self.client.get_treatment(None, "some_feature")) self.logger_error \ .assert_called_once_with("get_treatment: key cannot be None.") self.client._build_impression.assert_called_once_with( None, "some_feature", CONTROL, Label.EXCEPTION, 0, None, mock.ANY) def test_get_treatment_with_number_key(self): self.assertEqual("default_treatment", self.client.get_treatment(12345, "some_feature")) self.logger_warning \ .assert_called_once_with("get_treatment: key 12345 is not of type string, converting.") def test_get_treatment_with_bool_key(self): self.assertEqual(CONTROL, self.client.get_treatment(True, "some_feature")) self.logger_error \ .assert_called_once_with("get_treatment: key has to be of type string " "or object Key.") self.client._build_impression.assert_called_once_with( None, "some_feature", CONTROL, Label.EXCEPTION, 0, None, mock.ANY) def test_get_treatment_with_array_key(self): self.assertEqual(CONTROL, self.client.get_treatment([], "some_feature")) self.logger_error \ .assert_called_once_with("get_treatment: key has to be of type string " "or object Key.") self.client._build_impression.assert_called_once_with( None, "some_feature", CONTROL, Label.EXCEPTION, 0, None, mock.ANY) def test_get_treatment_with_null_feature_name(self): self.assertEqual(CONTROL, self.client.get_treatment("some_key", None)) self.logger_error \ .assert_called_once_with("get_treatment: feature_name cannot be None.") self.client._build_impression.assert_called_once_with( "some_key", None, CONTROL, Label.EXCEPTION, 0, None, mock.ANY) def test_get_treatment_with_numeric_feature_name(self): self.assertEqual(CONTROL, self.client.get_treatment("some_key", 12345)) self.logger_error \ .assert_called_once_with("get_treatment: feature_name has to be of type string.") self.client._build_impression.assert_called_once_with( "some_key", None, CONTROL, Label.EXCEPTION, 0, None, mock.ANY) def test_get_treatment_with_bool_feature_name(self): self.assertEqual(CONTROL, self.client.get_treatment("some_key", True)) self.logger_error \ .assert_called_once_with("get_treatment: feature_name has to be of type string.") self.client._build_impression.assert_called_once_with( "some_key", None, CONTROL, Label.EXCEPTION, 0, None, mock.ANY) def test_get_treatment_with_array_feature_name(self): self.assertEqual(CONTROL, self.client.get_treatment("some_key", [])) self.logger_error \ .assert_called_once_with("get_treatment: feature_name has to be of type string.") self.client._build_impression.assert_called_once_with( "some_key", None, CONTROL, Label.EXCEPTION, 0, None, mock.ANY) def test_get_treatment_with_valid_inputs(self): self.assertEqual("default_treatment", self.client.get_treatment("some_key", "some_feature")) self.logger_error.assert_not_called() self.logger_warning.assert_not_called() def test_get_tratment_with_null_matching_key(self): self.assertEqual( CONTROL, self.client.get_treatment(Key(None, "bucketing_key"), "some_feature")) self.logger_error \ .assert_called_once_with("get_treatment: Key should be an object with " "bucketingKey and matchingKey with valid string properties.") self.client._build_impression.assert_called_once_with( None, "some_feature", CONTROL, Label.EXCEPTION, 0, None, mock.ANY) def test_get_tratment_with_empty_matching_key(self): self.assertEqual( CONTROL, self.client.get_treatment(Key("", "bucketing_key"), "some_feature")) self.logger_error \ .assert_called_once_with("get_treatment: matching_key must not be empty.") self.client._build_impression.assert_called_once_with( None, "some_feature", CONTROL, Label.EXCEPTION, 0, None, mock.ANY) def test_get_tratment_with_bool_matching_key(self): self.assertEqual( CONTROL, self.client.get_treatment(Key(True, "bucketing_key"), "some_feature")) self.logger_error \ .assert_called_once_with("get_treatment: matching_key has to be of type string.") self.client._build_impression.assert_called_once_with( None, "some_feature", CONTROL, Label.EXCEPTION, 0, None, mock.ANY) def test_get_tratment_with_array_matching_key(self): self.assertEqual( CONTROL, self.client.get_treatment(Key([], "bucketing_key"), "some_feature")) self.logger_error \ .assert_called_once_with("get_treatment: matching_key has to be of type string.") self.client._build_impression.assert_called_once_with( None, "some_feature", CONTROL, Label.EXCEPTION, 0, None, mock.ANY) def test_get_tratment_with_numeric_matching_key(self): self.assertEqual( "default_treatment", self.client.get_treatment(Key(12345, "bucketing_key"), "some_feature")) self.logger_warning \ .assert_called_once_with("get_treatment: matching_key 12345 is not of type string, " "converting.") def test_get_tratment_with_null_bucketing_key(self): self.assertEqual( "default_treatment", self.client.get_treatment(Key("matching_key", None), "some_feature")) self.logger_warning \ .assert_called_once_with("get_treatment: Key object should have bucketingKey set.") def test_get_tratment_with_bool_bucketing_key(self): self.assertEqual( CONTROL, self.client.get_treatment(Key("matching_key", True), "some_feature")) self.logger_error \ .assert_called_once_with("get_treatment: bucketing_key has to be of type string.") self.client._build_impression.assert_called_once_with( None, "some_feature", CONTROL, Label.EXCEPTION, 0, None, mock.ANY) def test_get_tratment_with_array_bucketing_key(self): self.assertEqual( CONTROL, self.client.get_treatment(Key("matching_key", []), "some_feature")) self.logger_error \ .assert_called_once_with("get_treatment: bucketing_key has to be of type string.") self.client._build_impression.assert_called_once_with( None, "some_feature", CONTROL, Label.EXCEPTION, 0, None, mock.ANY) def test_get_tratment_with_numeric_bucketing_key(self): self.assertEqual( "default_treatment", self.client.get_treatment(Key("matching_key", 12345), "some_feature")) self.logger_warning \ .assert_called_once_with("get_treatment: bucketing_key 12345 is not of type string, " "converting.")
class TrafficAllocationTests(TestCase): ''' ''' def setUp(self): ''' ''' redis = get_redis({}) segment_cache = RedisSegmentCache(redis) split_parser = RedisSplitParser(segment_cache) self._client = Client(RedisBroker(redis)) self._splitObjects = {} raw_split = { 'name': 'test1', 'algo': 1, 'killed': False, 'status': 'ACTIVE', 'defaultTreatment': 'default', 'seed': -1222652054, 'orgId': None, 'environment': None, 'trafficTypeId': None, 'trafficTypeName': None, 'changeNumber': 1, 'conditions': [{ 'conditionType': 'WHITELIST', 'matcherGroup': { 'combiner': 'AND', 'matchers': [{ 'matcherType': 'ALL_KEYS', 'negate': False, 'userDefinedSegmentMatcherData': None, 'whitelistMatcherData': None }] }, 'partitions': [{ 'treatment': 'on', 'size': 100 }], 'label': 'in segment all' }] } self._splitObjects['whitelist'] = split_parser.parse(raw_split, True) raw_split['name'] = 'test2' raw_split['conditions'][0]['conditionType'] = 'ROLLOUT' self._splitObjects['rollout1'] = split_parser.parse(raw_split, True) raw_split['name'] = 'test3' raw_split['trafficAllocation'] = 1 raw_split['trafficAllocationSeed'] = -1 self._splitObjects['rollout2'] = split_parser.parse(raw_split, True) raw_split['name'] = 'test4' raw_split['trafficAllocation'] = None #must be mapped as 100 raw_split['trafficAllocationSeed'] = -1 self._splitObjects['rollout3'] = split_parser.parse(raw_split, True) def testTrafficAllocation(self): ''' ''' treatment1, label1 = self._client._get_treatment_for_split( self._splitObjects['whitelist'], 'testKey', None) self.assertEqual(treatment1, 'on') # Make sure traffic allocation is set to 100 at construction time if a # value is not provided. self.assertEqual(self._splitObjects['whitelist'].traffic_allocation, 100) treatment2, label1 = self._client._get_treatment_for_split( self._splitObjects['rollout1'], 'testKey', None) self.assertEqual(treatment2, 'on') treatment3, label1 = self._client._get_treatment_for_split( self._splitObjects['rollout2'], 'testKey', None) self.assertEqual(treatment3, 'default') treatment4, label1 = self._client._get_treatment_for_split( self._splitObjects['rollout3'], 'testKey', None) self.assertEqual(treatment4, 'on')
class TestInputSanitizationTrack(TestCase): def setUp(self): self.some_config = mock.MagicMock() self.some_api_key = mock.MagicMock() self.redis = get_redis({'redisPrefix': 'test'}) self.client = Client(RedisBroker(self.redis, self.some_config)) input_validator._LOGGER.error = mock.MagicMock() self.logger_error = input_validator._LOGGER.error input_validator._LOGGER.warning = mock.MagicMock() self.logger_warning = input_validator._LOGGER.warning def test_track_with_null_key(self): self.assertEqual( False, self.client.track(None, "traffic_type", "event_type", 1)) self.logger_error \ .assert_called_once_with("track: key cannot be None.") def test_track_with_numeric_key(self): self.assertEqual( True, self.client.track(12345, "traffic_type", "event_type", 1)) self.logger_warning \ .assert_called_once_with("track: key 12345 is not of type string," " converting.") def test_track_with_bool_key(self): self.assertEqual( False, self.client.track(True, "traffic_type", "event_type", 1)) self.logger_error \ .assert_called_once_with("track: key has to be of type string.") def test_track_with_array_key(self): self.assertEqual( False, self.client.track([], "traffic_type", "event_type", 1)) self.logger_error \ .assert_called_once_with("track: key has to be of type string.") def test_track_with_null_traffic_type(self): self.assertEqual(False, self.client.track("some_key", None, "event_type", 1)) self.logger_error \ .assert_called_once_with("track: traffic_type cannot be None.") def test_track_with_bool_traffic_type(self): self.assertEqual(False, self.client.track("some_key", True, "event_type", 1)) self.logger_error \ .assert_called_once_with("track: traffic_type has to be of type string.") def test_track_with_array_traffic_type(self): self.assertEqual(False, self.client.track("some_key", [], "event_type", 1)) self.logger_error \ .assert_called_once_with("track: traffic_type has to be of type string.") def test_track_with_numeric_traffic_type(self): self.assertEqual(False, self.client.track("some_key", 12345, "event_type", 1)) self.logger_error \ .assert_called_once_with("track: traffic_type has to be of type string.") def test_track_with_empty_traffic_type(self): self.assertEqual(False, self.client.track("some_key", "", "event_type", 1)) self.logger_error \ .assert_called_once_with("track: traffic_type must not be empty.") def test_track_with_null_event_type(self): self.assertEqual( False, self.client.track("some_key", "traffic_type", None, 1)) self.logger_error \ .assert_called_once_with("track: event_type cannot be None.") def test_track_with_bool_event_type(self): self.assertEqual( False, self.client.track("some_key", "traffic_type", True, 1)) self.logger_error \ .assert_called_once_with("track: event_type has to be of type string.") def test_track_with_array_event_type(self): self.assertEqual(False, self.client.track("some_key", "traffic_type", [], 1)) self.logger_error \ .assert_called_once_with("track: event_type has to be of type string.") def test_track_with_numeric_event_type(self): self.assertEqual( False, self.client.track("some_key", "traffic_type", 12345, 1)) self.logger_error \ .assert_called_once_with("track: event_type has to be of type string.") def test_track_with_event_type_does_not_conform_reg_exp(self): self.assertEqual( False, self.client.track("some_key", "traffic_type", "@@", 1)) self.logger_error \ .assert_called_once_with("track: event_type must adhere to the regular " "expression [a-zA-Z0-9][-_\\.a-zA-Z0-9]{0,62}.") def test_track_with_null_value(self): self.assertEqual( True, self.client.track("some_key", "traffic_type", "event_type", None)) self.logger_error.assert_not_called() self.logger_warning.assert_not_called() def test_track_with_string_value(self): self.assertEqual( False, self.client.track("some_key", "traffic_type", "event_type", "test")) self.logger_error \ .assert_called_once_with("track: value must be a number.") def test_track_with_bool_value(self): self.assertEqual( False, self.client.track("some_key", "traffic_type", "event_type", True)) self.logger_error \ .assert_called_once_with("track: value must be a number.") def test_track_with_array_value(self): self.assertEqual( False, self.client.track("some_key", "traffic_type", "event_type", [])) self.logger_error \ .assert_called_once_with("track: value must be a number.") def test_track_with_int_value(self): self.assertEqual( True, self.client.track("some_key", "traffic_type", "event_type", 1)) self.logger_error.assert_not_called() self.logger_warning.assert_not_called() def test_track_with_float_value(self): self.assertEqual( True, self.client.track("some_key", "traffic_type", "event_type", 1.3)) self.logger_error.assert_not_called() self.logger_warning.assert_not_called()