def test_recheck_limits_exception(self, mock_limits_hydrate, mock_exception, mock_ControlDaemon, mock_format_exc): limit_data = mock.Mock( **{ 'get_limits.side_effect': test_utils.TestException, }) mock_ControlDaemon.return_value = mock.Mock( **{ 'get_limits.return_value': limit_data, }) lc = compactor.LimitContainer(config.Config(), mock.Mock()) old_limits = [mock.Mock(uuid='old_uuid1'), mock.Mock(uuid='old_uuid2')] lc.limits = old_limits lc.limit_sum = 'old_sum' old_limit_map = dict(old_uuid1=old_limits[0], old_uuid2=old_limits[1]) lc.limit_map = old_limit_map lc.recheck_limits() mock_ControlDaemon.return_value.get_limits.assert_called_once_with() limit_data.get_limits.assert_called_once_with('old_sum') self.assertFalse(mock_limits_hydrate.called) self.assertEqual(lc.limits, old_limits) self.assertEqual(lc.limit_sum, 'old_sum') self.assertEqual(lc.limit_map, old_limit_map) mock_exception.assert_called_once_with("Could not load limits") mock_format_exc.assert_called_once_with() lc.db.assert_has_calls([ mock.call.sadd('errors', 'Failed to load limits: <traceback>'), mock.call.publish('errors', 'Failed to load limits: <traceback>'), ])
def test_reload_exception_altkeys(self, mock_format_exc, mock_exception): cd = control.ControlDaemon( 'middleware', config.Config( conf_dict={ 'control.errors_key': 'alt_err', 'control.errors_channel': 'alt_chan', })) cd.pending = mock.Mock(**{'acquire.return_value': True}) cd.limits = mock.Mock( **{ 'set_limits.side_effect': test_utils.TestException, }) cd._db = mock.Mock(**{'zrange.return_value': ['limit1', 'limit2']}) cd.reload() cd.pending.assert_has_calls([ mock.call.acquire(False), mock.call.release(), ]) self.assertEqual(len(cd.pending.method_calls), 2) cd.limits.set_limits.assert_called_once_with(['limit1', 'limit2']) cd._db.assert_has_calls([ mock.call.zrange('limits', 0, -1), mock.call.sadd('alt_err', 'Failed to load limits: <traceback>'), mock.call.publish('alt_chan', 'Failed to load limits: <traceback>'), ]) self.assertEqual(len(cd._db.method_calls), 3) mock_exception.assert_called_once_with('Could not load limits') mock_format_exc.assert_called_once_with()
def test_recheck_limits_basic(self, mock_limits_hydrate, mock_exception, mock_ControlDaemon, mock_format_exc): limit_data = mock.Mock(**{ 'get_limits.return_value': ('new_sum', ['limit1', 'limit2']), }) mock_ControlDaemon.return_value = mock.Mock( **{ 'get_limits.return_value': limit_data, }) lc = compactor.LimitContainer(config.Config(), mock.Mock()) lc.limits = [mock.Mock(uuid='old_uuid1'), mock.Mock(uuid='old_uuid2')] lc.limit_sum = 'old_sum' lc.limit_map = dict(old_uuid1=lc.limits[0], old_uuid2=lc.limits[1]) lc.recheck_limits() mock_ControlDaemon.return_value.get_limits.assert_called_once_with() limit_data.get_limits.assert_called_once_with('old_sum') mock_limits_hydrate.assert_called_once_with(lc.db, ['limit1', 'limit2']) self.assertEqual(lc.limits, mock_limits_hydrate.return_value) self.assertEqual(lc.limit_sum, 'new_sum') self.assertEqual( lc.limit_map, dict( uuid1=mock_limits_hydrate.return_value[0], uuid2=mock_limits_hydrate.return_value[1], )) self.assertFalse(mock_exception.called) self.assertFalse(mock_format_exc.called) self.assertEqual(len(lc.db.method_calls), 0)
def test_recheck_limits_unchanged(self, mock_limits_hydrate, mock_exception, mock_ControlDaemon, mock_format_exc): limit_data = mock.Mock( **{ 'get_limits.side_effect': control.NoChangeException, }) mock_ControlDaemon.return_value = mock.Mock( **{ 'get_limits.return_value': limit_data, }) lc = compactor.LimitContainer(config.Config(), mock.Mock()) old_limits = [mock.Mock(uuid='old_uuid1'), mock.Mock(uuid='old_uuid2')] lc.limits = old_limits lc.limit_sum = 'old_sum' old_limit_map = dict(old_uuid1=old_limits[0], old_uuid2=old_limits[1]) lc.limit_map = old_limit_map lc.recheck_limits() mock_ControlDaemon.return_value.get_limits.assert_called_once_with() limit_data.get_limits.assert_called_once_with('old_sum') self.assertFalse(mock_limits_hydrate.called) self.assertEqual(lc.limits, old_limits) self.assertEqual(lc.limit_sum, 'old_sum') self.assertEqual(lc.limit_map, old_limit_map) self.assertFalse(mock_exception.called) self.assertFalse(mock_format_exc.called) self.assertEqual(len(lc.db.method_calls), 0)
def test_ping_no_channel(self): conf = config.Config() db = mock.Mock() daemon = mock.Mock(config=conf, db=db) control.ping(daemon, '') self.assertFalse(db.publish.called)
def test_getitem(self, mock_recheck_limits, mock_ControlDaemon): lc = compactor.LimitContainer(config.Config(), 'db') lc.limit_map = dict(uuid1='limit1', uuid2='limit2') self.assertEqual(lc['uuid1'], 'limit1') self.assertEqual(lc['uuid2'], 'limit2') mock_recheck_limits.assert_has_calls([mock.call(), mock.call()])
def test_forced_spread(self, mock_random, mock_spawn_n, mock_spawn_after): daemon = mock.Mock(reload='reload', config=config.Config()) control.reload(daemon, 'spread', '20.4') mock_random.assert_called_once_with() mock_spawn_after.assert_called_once_with(10.2, 'reload') self.assertFalse(mock_spawn_n.called)
def test_ping_with_data_no_nodename(self): conf = config.Config() db = mock.Mock() daemon = mock.Mock(config=conf, db=db) control.ping(daemon, 'reply', 'data') db.publish.assert_called_once_with('reply', 'pong::data')
def test_basic(self, mock_random, mock_spawn_n, mock_spawn_after): daemon = mock.Mock(reload='reload', config=config.Config()) control.reload(daemon) self.assertFalse(mock_random.called) self.assertFalse(mock_spawn_after.called) mock_spawn_n.assert_called_once_with('reload')
def test_init_empty(self, mock_SafeConfigParser): cfg = config.Config() self.assertEqual(cfg._config, { None: { 'status': '413 Request Entity Too Large', }, }) self.assertFalse(mock_SafeConfigParser.called)
def test_ping_with_data_with_nodename(self): conf = config.Config(conf_dict={ 'control.node_name': 'node', }) db = mock.Mock() daemon = mock.Mock(config=conf, db=db) control.ping(daemon, 'reply', 'data') db.publish.assert_called_once_with('reply', 'pong:node:data')
def test_contains(self, mock_SafeConfigParser): local_conf = { 'preprocess': 'foo:bar', 'redis.host': '10.0.0.1', 'control.channel': 'control_channel', 'control.connection_pool.connection': 'FoobarConnection', } cfg = config.Config(conf_dict=local_conf) self.assertTrue('redis' in cfg) self.assertFalse('nosuch' in cfg)
def test_getitem(self, mock_SafeConfigParser): local_conf = { 'preprocess': 'foo:bar', 'redis.host': '10.0.0.1', 'control.channel': 'control_channel', 'control.connection_pool.connection': 'FoobarConnection', } cfg = config.Config(conf_dict=local_conf) self.assertEqual(cfg['redis'], dict(host='10.0.0.1')) self.assertEqual(cfg['nosuch'], {})
def test_get(self, mock_SafeConfigParser): local_conf = { 'preprocess': 'foo:bar', 'redis.host': '10.0.0.1', 'control.channel': 'control_channel', 'control.connection_pool.connection': 'FoobarConnection', } cfg = config.Config(conf_dict=local_conf) self.assertEqual(cfg.get('preprocess'), 'foo:bar') self.assertEqual(cfg.get('nosuch'), None) self.assertEqual(cfg.get('nosuch', 'other'), 'other')
def test_getattr(self, mock_SafeConfigParser): local_conf = { 'preprocess': 'foo:bar', 'redis.host': '10.0.0.1', 'control.channel': 'control_channel', 'control.connection_pool.connection': 'FoobarConnection', } cfg = config.Config(conf_dict=local_conf) self.assertEqual(cfg.preprocess, 'foo:bar') with self.assertRaises(AttributeError): dummy = cfg.nosuch
def test_bad_spread_fallback(self, mock_random, mock_spawn_n, mock_spawn_after): daemon = mock.Mock( reload='reload', config=config.Config(conf_dict={ 'control.reload_spread': '40.8', })) control.reload(daemon, 'spread', '20.4.3') mock_random.assert_called_once_with() mock_spawn_after.assert_called_once_with(20.4, 'reload') self.assertFalse(mock_spawn_n.called)
def test_configured_spread_override(self, mock_random, mock_spawn_n, mock_spawn_after): daemon = mock.Mock( reload='reload', config=config.Config(conf_dict={ 'control.reload_spread': '20.4', })) control.reload(daemon, 'immediate') self.assertFalse(mock_random.called) self.assertFalse(mock_spawn_after.called) mock_spawn_n.assert_called_once_with('reload')
def test_configured_spread(self, mock_random, mock_spawn_n, mock_spawn_after): daemon = mock.Mock( reload='reload', config=config.Config(conf_dict={ 'control.reload_spread': '20.4', })) control.reload(daemon) mock_random.assert_called_once_with() mock_spawn_after.assert_called_once_with(10.2, 'reload') self.assertFalse(mock_spawn_n.called)
def test_init_from_files(self, mock_SafeConfigParser): items = { 'turnstile': [ ('preprocess', 'foo:bar'), ], 'redis': [ ('password', 'spampass'), ], 'control': [ ('channel', 'control_channel'), ('connection_pool', 'FoobarConnectionPool'), ], } mock_SafeConfigParser.return_value.sections.return_value = \ ['turnstile', 'redis', 'control'] mock_SafeConfigParser.return_value.items.side_effect = \ lambda x: items[x] local_conf = { 'config': 'file_from_dict', 'status': '500 Internal Error', 'redis.host': '10.0.0.1', } cfg = config.Config(conf_dict=local_conf) self.assertEqual(cfg._config, { None: { 'status': '500 Internal Error', 'config': 'file_from_dict', 'preprocess': 'foo:bar', }, 'redis': { 'host': '10.0.0.1', 'password': '******', }, 'control': { 'channel': 'control_channel', 'connection_pool': 'FoobarConnectionPool', }, }) mock_SafeConfigParser.assert_called_once_with() mock_SafeConfigParser.return_value.assert_has_calls([ mock.call.read(['file_from_dict']), mock.call.sections(), mock.call.items('turnstile'), mock.call.items('redis'), mock.call.items('control'), ])
def test_init_files(self, mock_SafeConfigParser): local_conf = { 'config': 'file_from_dict', } cfg = config.Config(conf_dict=local_conf, conf_file='file_from_args') self.assertEqual(cfg._config, { None: { 'status': '413 Request Entity Too Large', 'config': 'file_from_dict', }, }) mock_SafeConfigParser.assert_called_once_with() mock_SafeConfigParser.return_value.read.assert_called_once_with( ['file_from_dict', 'file_from_args'])
def test_reload_noacquire(self, mock_format_exc, mock_exception): cd = control.ControlDaemon('middleware', config.Config()) cd.pending = mock.Mock(**{'acquire.return_value': False}) cd.limits = mock.Mock() cd._db = mock.Mock() cd.reload() cd.pending.assert_has_calls([ mock.call.acquire(False), ]) self.assertEqual(len(cd.pending.method_calls), 1) self.assertEqual(len(cd.limits.method_calls), 0) self.assertEqual(len(cd._db.method_calls), 0) self.assertFalse(mock_exception.called) self.assertFalse(mock_format_exc.called)
def test_init_local(self, mock_RemoteControlDaemon, mock_ControlDaemon): conf = config.Config(conf_dict={}) lc = compactor.LimitContainer(conf, 'db') self.assertEqual(lc.conf, conf) self.assertEqual(lc.db, 'db') self.assertEqual(lc.limits, []) self.assertEqual(lc.limit_map, {}) self.assertEqual(lc.limit_sum, None) self.assertEqual(lc.control_daemon, mock_ControlDaemon.return_value) self.assertFalse(mock_RemoteControlDaemon.called) mock_ControlDaemon.assert_has_calls([ mock.call(lc, conf), mock.call().start(), ])
def test_listen_shardhint(self, mock_get_database): pubsub = mock.Mock(**{'listen.return_value': []}) db = mock.Mock(**{'pubsub.return_value': pubsub}) mock_get_database.return_value = db cd = control.ControlDaemon( 'middleware', config.Config(conf_dict={ 'control.shard_hint': 'shard', })) cd.listen() mock_get_database.assert_called_once_with('control') db.pubsub.assert_called_once_with(shard_hint='shard') pubsub.assert_has_calls([ mock.call.subscribe('control'), mock.call.listen(), ])
def test_reload(self, mock_format_exc, mock_exception): cd = control.ControlDaemon('middleware', config.Config()) cd.pending = mock.Mock(**{'acquire.return_value': True}) cd.limits = mock.Mock() cd._db = mock.Mock(**{'zrange.return_value': ['limit1', 'limit2']}) cd.reload() cd.pending.assert_has_calls([ mock.call.acquire(False), mock.call.release(), ]) self.assertEqual(len(cd.pending.method_calls), 2) cd.limits.set_limits.assert_called_once_with(['limit1', 'limit2']) cd._db.assert_has_calls([ mock.call.zrange('limits', 0, -1), ]) self.assertEqual(len(cd._db.method_calls), 1) self.assertFalse(mock_exception.called) self.assertFalse(mock_format_exc.called)
def test_get_database_override(self, mock_initialize, mock_SafeConfigParser): local_conf = { 'redis.host': '10.0.0.1', 'redis.password': '******', 'redis.db': '3', 'control.host': '10.0.0.2', 'control.redis.host': '10.0.0.11', 'control.redis.port': '1234', 'control.redis.password': '******', 'control.redis.db': '', } cfg = config.Config(conf_dict=local_conf) result = cfg.get_database(override='control') self.assertEqual(result, 'db_handle') mock_initialize.assert_called_once_with({ 'host': '10.0.0.11', 'port': '1234', 'password': '******', }) self.assertEqual(cfg._config, { None: { 'status': '413 Request Entity Too Large', }, 'redis': { 'host': '10.0.0.1', 'password': '******', 'db': '3', }, 'control': { 'host': '10.0.0.2', 'redis.host': '10.0.0.11', 'redis.password': '******', 'redis.port': '1234', 'redis.db': '', }, })
def test_init_dict(self, mock_SafeConfigParser): local_conf = { 'preprocess': 'foo:bar', 'redis.host': '10.0.0.1', 'control.channel': 'control_channel', 'control.connection_pool.connection': 'FoobarConnection', } cfg = config.Config(conf_dict=local_conf) self.assertEqual(cfg._config, { None: { 'status': '413 Request Entity Too Large', 'preprocess': 'foo:bar', }, 'redis': { 'host': '10.0.0.1', }, 'control': { 'channel': 'control_channel', 'connection_pool.connection': 'FoobarConnection', }, }) self.assertFalse(mock_SafeConfigParser.called)
def test_listen_altchan(self, mock_exception, mock_error, mock_get_database, mock_find_entrypoint): pubsub = mock.Mock( **{ 'listen.return_value': [ { 'type': 'other', 'channel': 'control', 'data': 'ping', }, { 'type': 'pmessage', 'channel': 'other', 'data': 'ping', }, { 'type': 'message', 'channel': 'other', 'data': 'ping', }, { 'type': 'pmessage', 'channel': 'control', 'data': '', }, { 'type': 'message', 'channel': 'control', 'data': '', }, { 'type': 'pmessage', 'channel': 'control', 'data': '_ping', }, { 'type': 'message', 'channel': 'control', 'data': '_ping', }, { 'type': 'pmessage', 'channel': 'control', 'data': 'nosuch', }, { 'type': 'message', 'channel': 'control', 'data': 'nosuch', }, { 'type': 'pmessage', 'channel': 'control', 'data': 'fail', }, { 'type': 'message', 'channel': 'control', 'data': 'fail', }, { 'type': 'pmessage', 'channel': 'control', 'data': 'fail:arg1:arg2', }, { 'type': 'message', 'channel': 'control', 'data': 'fail:arg1:arg2', }, { 'type': 'pmessage', 'channel': 'control', 'data': 'ping', }, { 'type': 'message', 'channel': 'control', 'data': 'ping', }, { 'type': 'pmessage', 'channel': 'control', 'data': 'ping:arg1:arg2', }, { 'type': 'message', 'channel': 'control', 'data': 'ping:arg1:arg2', }, ] }) db = mock.Mock(**{'pubsub.return_value': pubsub}) mock_get_database.return_value = db cd = control.ControlDaemon( 'middleware', config.Config(conf_dict={ 'control.channel': 'other', })) cd.listen() mock_get_database.assert_called_once_with('control') db.pubsub.assert_called_once_with() pubsub.assert_has_calls([ mock.call.subscribe('other'), mock.call.listen(), ]) self.assertFalse(mock_error.called) self.assertFalse(mock_exception.called) control.ControlDaemon._commands['ping'].assert_has_calls([ mock.call(cd), mock.call(cd), ]) self.assertFalse(control.ControlDaemon._commands['_ping'].called) self.assertFalse(control.ControlDaemon._commands['fail'].called) self.assertFalse(mock_find_entrypoint.called)
def test_db_middleware(self): middleware = mock.Mock(db='midware_db') cd = control.ControlDaemon(middleware, config.Config()) self.assertEqual(cd.db, 'midware_db')
def test_db_present(self): middleware = mock.Mock(db='midware_db') cd = control.ControlDaemon(middleware, config.Config()) cd._db = 'cached_db' self.assertEqual(cd.db, 'cached_db')
def test_listen(self, mock_exception, mock_error, mock_get_database, mock_find_entrypoint): entrypoints = dict(discovered=mock.Mock()) mock_find_entrypoint.side_effect = ( lambda x, y, compat: entrypoints.get(y)) pubsub = mock.Mock( **{ 'listen.return_value': [ { 'type': 'other', 'channel': 'control', 'data': 'ping', }, { 'type': 'pmessage', 'channel': 'other', 'data': 'ping', }, { 'type': 'message', 'channel': 'other', 'data': 'ping', }, { 'type': 'pmessage', 'channel': 'control', 'data': '', }, { 'type': 'message', 'channel': 'control', 'data': '', }, { 'type': 'pmessage', 'channel': 'control', 'data': '_ping', }, { 'type': 'message', 'channel': 'control', 'data': '_ping', }, { 'type': 'pmessage', 'channel': 'control', 'data': 'nosuch', }, { 'type': 'message', 'channel': 'control', 'data': 'nosuch', }, { 'type': 'pmessage', 'channel': 'control', 'data': 'fail', }, { 'type': 'message', 'channel': 'control', 'data': 'fail', }, { 'type': 'pmessage', 'channel': 'control', 'data': 'fail:arg1:arg2', }, { 'type': 'message', 'channel': 'control', 'data': 'fail:arg1:arg2', }, { 'type': 'pmessage', 'channel': 'control', 'data': 'ping', }, { 'type': 'message', 'channel': 'control', 'data': 'ping', }, { 'type': 'pmessage', 'channel': 'control', 'data': 'ping:arg1:arg2', }, { 'type': 'message', 'channel': 'control', 'data': 'ping:arg1:arg2', }, { 'type': 'pmessage', 'channel': 'control', 'data': 'discovered', }, { 'type': 'message', 'channel': 'control', 'data': 'discovered', }, { 'type': 'pmessage', 'channel': 'control', 'data': 'discovered:arg1:arg2', }, { 'type': 'message', 'channel': 'control', 'data': 'discovered:arg1:arg2', }, ] }) db = mock.Mock(**{'pubsub.return_value': pubsub}) mock_get_database.return_value = db cd = control.ControlDaemon('middleware', config.Config()) cd.listen() mock_get_database.assert_called_once_with('control') db.pubsub.assert_called_once_with() pubsub.assert_has_calls([ mock.call.subscribe('control'), mock.call.listen(), ]) mock_error.assert_has_calls([ mock.call("Cannot call internal command '_ping'"), mock.call("Cannot call internal command '_ping'"), mock.call("No such command 'nosuch'"), mock.call("No such command 'nosuch'"), ]) mock_exception.assert_has_calls([ mock.call("Failed to execute command 'fail' arguments []"), mock.call("Failed to execute command 'fail' arguments []"), mock.call("Failed to execute command 'fail' arguments " "['arg1', 'arg2']"), mock.call("Failed to execute command 'fail' arguments " "['arg1', 'arg2']"), ]) control.ControlDaemon._commands['ping'].assert_has_calls([ mock.call(cd), mock.call(cd), mock.call(cd, 'arg1', 'arg2'), mock.call(cd, 'arg1', 'arg2'), ]) self.assertFalse(control.ControlDaemon._commands['_ping'].called) control.ControlDaemon._commands['fail'].assert_has_calls([ mock.call(cd), mock.call(cd), mock.call(cd, 'arg1', 'arg2'), mock.call(cd, 'arg1', 'arg2'), ]) entrypoints['discovered'].assert_has_calls([ mock.call(cd), mock.call(cd), mock.call(cd, 'arg1', 'arg2'), mock.call(cd, 'arg1', 'arg2'), ]) mock_find_entrypoint.assert_has_calls([ mock.call('turnstile.command', 'nosuch', compat=False), mock.call('turnstile.command', 'discovered', compat=False), ]) self.assertEqual(len(mock_find_entrypoint.mock_calls), 2) self.assertEqual(control.ControlDaemon._commands['discovered'], entrypoints['discovered']) self.assertEqual(control.ControlDaemon._commands['nosuch'], None)