예제 #1
0
class TestRedisMonitor(TestCase):
    def setUp(self):
        self.redis_monitor = RedisMonitor("settings.py", True)
        self.redis_monitor.settings = self.redis_monitor.wrapper.load("settings.py")
        self.redis_monitor.logger = MagicMock()

    def test_load_plugins(self):
        # test loading default plugins
        assert_keys = [100, 200, 300, 400]
        self.redis_monitor._load_plugins()
        self.assertEqual(self.redis_monitor.plugins_dict.keys(), assert_keys)

        # test removing a plugin from settings
        assert_keys = [100, 300, 400]
        self.redis_monitor.settings["PLUGINS"]["plugins.stop_monitor.StopMonitor"] = None
        self.redis_monitor._load_plugins()
        self.assertEqual(self.redis_monitor.plugins_dict.keys(), assert_keys)
        self.redis_monitor.settings["PLUGINS"]["plugins.stop_monitor.StopMonitor"] = 200

        # fail if the class is not found
        self.redis_monitor.settings["PLUGINS"]["plugins.crazy_class.CrazyHandler"] = (400,)

        self.assertRaises(ImportError, self.redis_monitor._load_plugins)
        del self.redis_monitor.settings["PLUGINS"]["plugins.crazy_class.CrazyHandler"]
        self.redis_monitor.settings["PLUGINS"] = {}

    def test_active_plugins(self):
        # test that exceptions are caught within each plugin
        # assuming now all plugins are loaded
        self.redis_monitor._load_plugins()
        self.redis_monitor.stats_dict = {}

        # BaseExceptions are never raised normally
        self.redis_monitor.plugins_dict.items()[0][1]["instance"].handle = MagicMock(side_effect=BaseException("info"))
        self.redis_monitor.plugins_dict.items()[1][1]["instance"].handle = MagicMock(side_effect=BaseException("stop"))
        self.redis_monitor.plugins_dict.items()[2][1]["instance"].handle = MagicMock(
            side_effect=BaseException("expire")
        )
        self.redis_monitor.redis_conn = MagicMock()
        self.redis_monitor.redis_conn.scan_iter = MagicMock()
        # lets just assume the regex worked
        self.redis_monitor.redis_conn.scan_iter.return_value = ["somekey1"]

        # info
        try:
            plugin = self.redis_monitor.plugins_dict.items()[0][1]
            self.redis_monitor._process_plugin(plugin)
            self.fail("Info not called")
        except BaseException as e:
            self.assertEquals("info", e.message)

        # action
        try:
            plugin = self.redis_monitor.plugins_dict.items()[1][1]
            self.redis_monitor._process_plugin(plugin)
            self.fail("Stop not called")
        except BaseException as e:
            self.assertEquals("stop", e.message)

        # expire
        try:
            plugin = self.redis_monitor.plugins_dict.items()[2][1]
            self.redis_monitor._process_plugin(plugin)
            self.fail("Expire not called")
        except BaseException as e:
            self.assertEquals("expire", e.message)

        # test that an exception within a handle method is caught
        try:
            self.redis_monitor.plugins_dict.items()[0][1]["instance"].handle = MagicMock(
                side_effect=Exception("normal")
            )
            plugin = self.redis_monitor.plugins_dict.items()[0][1]
            self.redis_monitor._process_plugin(plugin)
        except Exception as e:
            self.fail("Normal Exception not handled")

    def test_load_stats_plugins(self):
        # lets assume we are loading the default plugins
        self.redis_monitor._load_plugins()
        self.redis_monitor.redis_conn = MagicMock()

        # test no rolling stats
        self.redis_monitor.stats_dict = {}
        self.redis_monitor.settings["STATS_TIMES"] = []
        self.redis_monitor._setup_stats_plugins()
        defaults = ["ExpireMonitor", "StopMonitor", "InfoMonitor", "StatsMonitor"]

        self.assertEquals(sorted(self.redis_monitor.stats_dict["plugins"].keys()), sorted(defaults))

        for key in self.redis_monitor.plugins_dict:
            plugin_name = self.redis_monitor.plugins_dict[key]["instance"].__class__.__name__
            self.assertEquals(self.redis_monitor.stats_dict["plugins"][plugin_name].keys(), ["lifetime"])

        # test good/bad rolling stats
        self.redis_monitor.stats_dict = {}
        self.redis_monitor.settings["STATS_TIMES"] = ["SECONDS_15_MINUTE", "SECONDS_1_HOUR", "SECONDS_DUMB"]
        good = ["lifetime", 900, 3600]  # for totals, not DUMB

        self.redis_monitor._setup_stats_plugins()

        self.assertEquals(sorted(self.redis_monitor.stats_dict["plugins"].keys()), sorted(defaults))

        for key in self.redis_monitor.plugins_dict:
            plugin_name = self.redis_monitor.plugins_dict[key]["instance"].__class__.__name__
            self.assertEquals(sorted(self.redis_monitor.stats_dict["plugins"][plugin_name].keys()), sorted(good))

        for plugin_key in self.redis_monitor.stats_dict["plugins"]:
            k1 = "stats:redis-monitor:{p}".format(p=plugin_key)
            for time_key in self.redis_monitor.stats_dict["plugins"][plugin_key]:
                if time_key == 0:
                    self.assertEquals(
                        self.redis_monitor.stats_dict["plugins"][plugin_key][0].key, "{k}:lifetime".format(k=k1)
                    )
                else:
                    self.assertEquals(
                        self.redis_monitor.stats_dict["plugins"][plugin_key][time_key].key,
                        "{k}:{t}".format(k=k1, t=time_key),
                    )

    def test_main_loop(self):
        self.redis_monitor._load_plugins()
        self.redis_monitor._process_plugin = MagicMock(side_effect=Exception("normal"))

        try:
            self.redis_monitor._main_loop()
            self.fail("_process_plugin not called")
        except BaseException as e:
            self.assertEquals("normal", e.message)

    def test_precondition(self):
        self.redis_monitor.stats_dict = {}
        instance = MagicMock()
        instance.check_precondition = MagicMock(return_value=False)
        instance.handle = MagicMock(side_effect=Exception("handler"))
        key = "stuff"
        value = "blah"

        # this should not raise an exception
        self.redis_monitor._process_key_val(instance, key, value)

        # this should
        instance.check_precondition = MagicMock(return_value=True)
        try:
            self.redis_monitor._process_key_val(instance, key, value)
            self.fail("handler not called")
        except BaseException as e:
            self.assertEquals("handler", e.message)
예제 #2
0
class TestRedisMonitor(TestCase):

    def setUp(self):
        self.redis_monitor = RedisMonitor("settings.py", True)
        self.redis_monitor.settings = self.redis_monitor.wrapper.load("settings.py")
        self.redis_monitor.logger = MagicMock()

    def test_load_plugins(self):
        # test loading default plugins
        assert_keys = [100, 200, 300, 400, 500]
        self.redis_monitor._load_plugins()
        self.assertEqual(list(self.redis_monitor.plugins_dict.keys()), assert_keys)

        # test removing a plugin from settings
        assert_keys = [100, 300, 400, 500]
        self.redis_monitor.settings['PLUGINS'] \
            ['plugins.stop_monitor.StopMonitor'] = None
        self.redis_monitor._load_plugins()
        self.assertEqual(list(self.redis_monitor.plugins_dict.keys()), assert_keys)
        self.redis_monitor.settings['PLUGINS'] \
            ['plugins.stop_monitor.StopMonitor'] = 200

        # fail if the class is not found
        self.redis_monitor.settings['PLUGINS'] \
            ['plugins.crazy_class.CrazyHandler'] = 400,

        self.assertRaises(ImportError, self.redis_monitor._load_plugins)
        del self.redis_monitor.settings['PLUGINS'] \
            ['plugins.crazy_class.CrazyHandler']
        self.redis_monitor.settings['PLUGINS'] = {}

    def test_active_plugins(self):
        # test that exceptions are caught within each plugin
        # assuming now all plugins are loaded
        self.redis_monitor._load_plugins()
        self.redis_monitor.stats_dict = {}

        # BaseExceptions are never raised normally
        list(self.redis_monitor.plugins_dict.items())[0][1]['instance'].handle = MagicMock(side_effect=BaseException("info"))
        list(self.redis_monitor.plugins_dict.items())[1][1]['instance'].handle = MagicMock(side_effect=BaseException("stop"))
        list(self.redis_monitor.plugins_dict.items())[2][1]['instance'].handle = MagicMock(side_effect=BaseException("expire"))
        self.redis_monitor.redis_conn = MagicMock()
        self.redis_monitor.redis_conn.scan_iter = MagicMock()
        self.redis_monitor._create_lock_object = MagicMock()

        # lets just assume the regex worked
        self.redis_monitor.redis_conn.scan_iter.return_value = ['somekey1']

        # info
        try:
            plugin = list(self.redis_monitor.plugins_dict.items())[0][1]
            self.redis_monitor._process_plugin(plugin)
            self.fail("Info not called")
        except BaseException as e:
            self.assertEquals("info", str(e))

        # action
        try:
            plugin = list(self.redis_monitor.plugins_dict.items())[1][1]
            self.redis_monitor._process_plugin(plugin)
            self.fail("Stop not called")
        except BaseException as e:
            self.assertEquals("stop", str(e))

        # expire
        try:
            plugin = list(self.redis_monitor.plugins_dict.items())[2][1]
            self.redis_monitor._process_plugin(plugin)
            self.fail("Expire not called")
        except BaseException as e:
            self.assertEquals("expire", str(e))

        # test that an exception within a handle method is caught
        self.redis_monitor._process_failures = MagicMock()
        self.redis_monitor._increment_fail_stat = MagicMock()
        try:
            list(self.redis_monitor.plugins_dict.items())[0][1]['instance'].handle = MagicMock(side_effect=Exception("normal"))
            plugin = list(self.redis_monitor.plugins_dict.items())[0][1]
            self.redis_monitor._process_plugin(plugin)

        except Exception as e:
            self.fail("Normal Exception not handled")

        self.assertTrue(self.redis_monitor._increment_fail_stat.called)
        self.assertTrue(self.redis_monitor._process_failures.called)

    def test_locking_actions(self):
        # tests for _process_plugins with locking
        self.redis_monitor._load_plugins()
        self.redis_monitor.redis_conn = MagicMock()
        self.redis_monitor.redis_conn = MagicMock()
        self.redis_monitor.redis_conn.scan_iter = MagicMock()
        self.redis_monitor.redis_conn.get = MagicMock(return_value=5)

        lock = MagicMock()
        lock.acquire
        lock.acquire = MagicMock(return_value=False)
        lock.release = MagicMock()
        lock._held = False
        self.redis_monitor._create_lock_object = MagicMock(return_value=lock)

        self.redis_monitor._increment_fail_stat = MagicMock()
        self.redis_monitor._process_failures = MagicMock()
        self.redis_monitor._process_key_val = MagicMock()
        # lets just assume the regex worked
        self.redis_monitor.redis_conn.scan_iter.return_value = ['somekey1']

        plugin = {'instance': 'test',
                  'regex': 'abc123'}

        # test didnt acquire lock
        self.redis_monitor._process_key_val.assert_not_called()
        self.redis_monitor._process_plugin(plugin)
        self.redis_monitor._process_key_val.assert_not_called()
        lock.release.assert_not_called()

        # test got lock
        lock.acquire = MagicMock(return_value=True)
        lock._held = True
        self.redis_monitor._process_plugin(plugin)
        self.redis_monitor._process_key_val.assert_called_once_with('test', 'somekey1', 5)
        # test lock released
        lock.release.assert_called_once_with()

        # test lock not held not released
        lock._held = False
        lock.release.reset_mock()
        self.redis_monitor._process_plugin(plugin)
        lock.release.assert_not_called()


    def test_load_stats_plugins(self):
        # lets assume we are loading the default plugins
        self.redis_monitor._load_plugins()
        self.redis_monitor.redis_conn = MagicMock()

        # test no rolling stats
        self.redis_monitor.stats_dict = {}
        self.redis_monitor.settings['STATS_TIMES'] = []
        self.redis_monitor._setup_stats_plugins()
        defaults = [
            'ExpireMonitor',
            'StopMonitor',
            'InfoMonitor',
            'StatsMonitor',
            'ZookeeperMonitor'
        ]

        self.assertEquals(
            sorted(self.redis_monitor.stats_dict['plugins'].keys()),
            sorted(defaults))

        for key in self.redis_monitor.plugins_dict:
            plugin_name = self.redis_monitor.plugins_dict[key]['instance'].__class__.__name__
            self.assertEquals(
                list(self.redis_monitor.stats_dict['plugins'][plugin_name].keys()),
                ['lifetime'])

        # test good/bad rolling stats
        self.redis_monitor.stats_dict = {}
        self.redis_monitor.settings['STATS_TIMES'] = [
            'SECONDS_15_MINUTE',
            'SECONDS_1_HOUR',
            'SECONDS_DUMB',
        ]
        good = [
            'lifetime', # for totals, not DUMB
            '900',
            '3600',
        ]

        self.redis_monitor._setup_stats_plugins()

        self.assertEquals(
            sorted(self.redis_monitor.stats_dict['plugins'].keys()),
            sorted(defaults))

        for key in self.redis_monitor.plugins_dict:
            plugin_name = self.redis_monitor.plugins_dict[key]['instance'].__class__.__name__
            self.assertEquals(
                sorted([str(x) for x in self.redis_monitor.stats_dict['plugins'][plugin_name].keys()]),
                sorted(good))

        for plugin_key in self.redis_monitor.stats_dict['plugins']:
            k1 = 'stats:redis-monitor:{p}'.format(p=plugin_key)
            for time_key in self.redis_monitor.stats_dict['plugins'][plugin_key]:
                if time_key == 0:
                    self.assertEquals(
                        self.redis_monitor.stats_dict['plugins'][plugin_key][0].key,
                        '{k}:lifetime'.format(k=k1)
                        )
                else:
                    self.assertEquals(
                        self.redis_monitor.stats_dict['plugins'][plugin_key][time_key].key,
                        '{k}:{t}'.format(k=k1, t=time_key)
                        )

    def test_main_loop(self):
        self.redis_monitor._load_plugins()
        self.redis_monitor._process_plugin = MagicMock(side_effect=Exception(
                                                       "normal"))

        try:
            self.redis_monitor._main_loop()
            self.fail("_process_plugin not called")
        except BaseException as e:
            self.assertEquals("normal", str(e))

    def test_precondition(self):
        self.redis_monitor.stats_dict = {}
        instance = MagicMock()
        instance.check_precondition = MagicMock(return_value=False)
        instance.handle = MagicMock(side_effect=Exception("handler"))
        key = 'stuff'
        value = 'blah'

        # this should not raise an exception
        self.redis_monitor._process_key_val(instance, key, value)

        # this should
        instance.check_precondition = MagicMock(return_value=True)
        try:
            self.redis_monitor._process_key_val(instance, key, value)
            self.fail('handler not called')
        except BaseException as e:
            self.assertEquals('handler', str(e))

    def test_get_fail_key(self):
        key = 'test'
        result = 'lock:test:failures'
        self.assertEquals(self.redis_monitor._get_fail_key(key), result)

    def test_process_failures(self):
        self.redis_monitor.settings = {'RETRY_FAILURES':True,
                                       'RETRY_FAILURES_MAX': 3}
        self.redis_monitor._get_fail_key = MagicMock(return_value='the_key')
        self.redis_monitor.redis_conn = MagicMock()
        self.redis_monitor.redis_conn.set = MagicMock()

        # test not set
        self.redis_monitor.redis_conn.get = MagicMock(return_value=None)
        self.redis_monitor._process_failures('key1')
        self.redis_monitor.redis_conn.set.assert_called_once_with('the_key', 1)

        # test set
        self.redis_monitor.redis_conn.set.reset_mock()
        self.redis_monitor.redis_conn.get = MagicMock(return_value=2)
        self.redis_monitor._process_failures('key1')
        self.redis_monitor.redis_conn.set.assert_called_once_with('the_key', 3)

        # test exceeded
        self.redis_monitor.redis_conn.delete = MagicMock()
        self.redis_monitor.redis_conn.set.reset_mock()
        self.redis_monitor.redis_conn.get = MagicMock(return_value=3)
        self.redis_monitor._process_failures('key1')
        calls = [call('the_key'), call('key1')]
        self.redis_monitor.redis_conn.delete.assert_has_calls(calls)

    @mock.patch('socket.gethostname', return_value='host')
    @mock.patch('time.time', return_value=5)
    def test_report_self(self, h, t):
        self.redis_monitor.my_uuid = '1234'
        self.redis_monitor.redis_conn = MagicMock()
        self.redis_monitor.redis_conn.set = MagicMock()
        self.redis_monitor.redis_conn.expire = MagicMock()

        self.redis_monitor._report_self()
        self.redis_monitor.redis_conn.set.assert_called_once_with('stats:redis-monitor:self:host:1234', 5)
        self.redis_monitor.redis_conn.expire.assert_called_once_with('stats:redis-monitor:self:host:1234', 120)
class TestRedisMonitor(TestCase):
    def setUp(self):
        self.redis_monitor = RedisMonitor("settings.py", True)
        self.redis_monitor.settings = self.redis_monitor.wrapper.load(
            "settings.py")
        self.redis_monitor.logger = MagicMock()

    def test_load_plugins(self):
        # test loading default plugins
        assert_keys = [100, 200, 300, 400, 500]
        self.redis_monitor._load_plugins()
        self.assertEqual(list(self.redis_monitor.plugins_dict.keys()),
                         assert_keys)

        # test removing a plugin from settings
        assert_keys = [100, 300, 400, 500]
        self.redis_monitor.settings['PLUGINS'] \
            ['plugins.stop_monitor.StopMonitor'] = None
        self.redis_monitor._load_plugins()
        self.assertEqual(list(self.redis_monitor.plugins_dict.keys()),
                         assert_keys)
        self.redis_monitor.settings['PLUGINS'] \
            ['plugins.stop_monitor.StopMonitor'] = 200

        # fail if the class is not found
        self.redis_monitor.settings['PLUGINS'] \
            ['plugins.crazy_class.CrazyHandler'] = 400,

        self.assertRaises(ImportError, self.redis_monitor._load_plugins)
        del self.redis_monitor.settings['PLUGINS'] \
            ['plugins.crazy_class.CrazyHandler']
        self.redis_monitor.settings['PLUGINS'] = {}

    def test_active_plugins(self):
        # test that exceptions are caught within each plugin
        # assuming now all plugins are loaded
        self.redis_monitor._load_plugins()
        self.redis_monitor.stats_dict = {}

        # BaseExceptions are never raised normally
        list(self.redis_monitor.plugins_dict.items()
             )[0][1]['instance'].handle = MagicMock(
                 side_effect=BaseException("info"))
        list(self.redis_monitor.plugins_dict.items()
             )[1][1]['instance'].handle = MagicMock(
                 side_effect=BaseException("stop"))
        list(self.redis_monitor.plugins_dict.items()
             )[2][1]['instance'].handle = MagicMock(
                 side_effect=BaseException("expire"))
        self.redis_monitor.redis_conn = MagicMock()
        self.redis_monitor.redis_conn.scan_iter = MagicMock()
        self.redis_monitor._create_lock_object = MagicMock()

        # lets just assume the regex worked
        self.redis_monitor.redis_conn.scan_iter.return_value = ['somekey1']

        # info
        try:
            plugin = list(self.redis_monitor.plugins_dict.items())[0][1]
            self.redis_monitor._process_plugin(plugin)
            self.fail("Info not called")
        except BaseException as e:
            self.assertEqual("info", str(e))

        # action
        try:
            plugin = list(self.redis_monitor.plugins_dict.items())[1][1]
            self.redis_monitor._process_plugin(plugin)
            self.fail("Stop not called")
        except BaseException as e:
            self.assertEqual("stop", str(e))

        # expire
        try:
            plugin = list(self.redis_monitor.plugins_dict.items())[2][1]
            self.redis_monitor._process_plugin(plugin)
            self.fail("Expire not called")
        except BaseException as e:
            self.assertEqual("expire", str(e))

        # test that an exception within a handle method is caught
        self.redis_monitor._process_failures = MagicMock()
        self.redis_monitor._increment_fail_stat = MagicMock()
        try:
            list(self.redis_monitor.plugins_dict.items()
                 )[0][1]['instance'].handle = MagicMock(
                     side_effect=Exception("normal"))
            plugin = list(self.redis_monitor.plugins_dict.items())[0][1]
            self.redis_monitor._process_plugin(plugin)

        except Exception as e:
            self.fail("Normal Exception not handled")

        self.assertTrue(self.redis_monitor._increment_fail_stat.called)
        self.assertTrue(self.redis_monitor._process_failures.called)

    def test_locking_actions(self):
        # tests for _process_plugins with locking
        self.redis_monitor._load_plugins()
        self.redis_monitor.redis_conn = MagicMock()
        self.redis_monitor.redis_conn = MagicMock()
        self.redis_monitor.redis_conn.scan_iter = MagicMock()
        self.redis_monitor.redis_conn.get = MagicMock(return_value=5)

        lock = MagicMock()
        lock.acquire
        lock.acquire = MagicMock(return_value=False)
        lock.release = MagicMock()
        lock._held = False
        self.redis_monitor._create_lock_object = MagicMock(return_value=lock)

        self.redis_monitor._increment_fail_stat = MagicMock()
        self.redis_monitor._process_failures = MagicMock()
        self.redis_monitor._process_key_val = MagicMock()
        # lets just assume the regex worked
        self.redis_monitor.redis_conn.scan_iter.return_value = ['somekey1']

        plugin = {'instance': 'test', 'regex': 'abc123'}

        # test didnt acquire lock
        self.redis_monitor._process_key_val.assert_not_called()
        self.redis_monitor._process_plugin(plugin)
        self.redis_monitor._process_key_val.assert_not_called()
        lock.release.assert_not_called()

        # test got lock
        lock.acquire = MagicMock(return_value=True)
        lock._held = True
        self.redis_monitor._process_plugin(plugin)
        self.redis_monitor._process_key_val.assert_called_once_with(
            'test', 'somekey1', 5)
        # test lock released
        lock.release.assert_called_once_with()

        # test lock not held not released
        lock._held = False
        lock.release.reset_mock()
        self.redis_monitor._process_plugin(plugin)
        lock.release.assert_not_called()

    def test_load_stats_plugins(self):
        # lets assume we are loading the default plugins
        self.redis_monitor._load_plugins()
        self.redis_monitor.redis_conn = MagicMock()

        # test no rolling stats
        self.redis_monitor.stats_dict = {}
        self.redis_monitor.settings['STATS_TIMES'] = []
        self.redis_monitor._setup_stats_plugins()
        defaults = [
            'ExpireMonitor', 'StopMonitor', 'InfoMonitor', 'StatsMonitor',
            'ZookeeperMonitor'
        ]

        self.assertEqual(
            sorted(self.redis_monitor.stats_dict['plugins'].keys()),
            sorted(defaults))

        for key in self.redis_monitor.plugins_dict:
            plugin_name = self.redis_monitor.plugins_dict[key][
                'instance'].__class__.__name__
            self.assertEqual(
                list(self.redis_monitor.stats_dict['plugins']
                     [plugin_name].keys()), ['lifetime'])

        # test good/bad rolling stats
        self.redis_monitor.stats_dict = {}
        self.redis_monitor.settings['STATS_TIMES'] = [
            'SECONDS_15_MINUTE',
            'SECONDS_1_HOUR',
            'SECONDS_DUMB',
        ]
        good = [
            'lifetime',  # for totals, not DUMB
            '900',
            '3600',
        ]

        self.redis_monitor._setup_stats_plugins()

        self.assertEqual(
            sorted(self.redis_monitor.stats_dict['plugins'].keys()),
            sorted(defaults))

        for key in self.redis_monitor.plugins_dict:
            plugin_name = self.redis_monitor.plugins_dict[key][
                'instance'].__class__.__name__
            self.assertEqual(
                sorted([
                    str(x) for x in self.redis_monitor.stats_dict['plugins']
                    [plugin_name].keys()
                ]), sorted(good))

        for plugin_key in self.redis_monitor.stats_dict['plugins']:
            k1 = 'stats:redis-monitor:{p}'.format(p=plugin_key)
            for time_key in self.redis_monitor.stats_dict['plugins'][
                    plugin_key]:
                if time_key == 0:
                    self.assertEqual(
                        self.redis_monitor.stats_dict['plugins'][plugin_key]
                        [0].key, '{k}:lifetime'.format(k=k1))
                else:
                    self.assertEqual(
                        self.redis_monitor.stats_dict['plugins'][plugin_key]
                        [time_key].key, '{k}:{t}'.format(k=k1, t=time_key))

    def test_main_loop(self):
        self.redis_monitor._load_plugins()
        self.redis_monitor._process_plugin = MagicMock(
            side_effect=Exception("normal"))

        try:
            self.redis_monitor._main_loop()
            self.fail("_process_plugin not called")
        except BaseException as e:
            self.assertEqual("normal", str(e))

    def test_precondition(self):
        self.redis_monitor.stats_dict = {}
        instance = MagicMock()
        instance.check_precondition = MagicMock(return_value=False)
        instance.handle = MagicMock(side_effect=Exception("handler"))
        key = 'stuff'
        value = 'blah'

        # this should not raise an exception
        self.redis_monitor._process_key_val(instance, key, value)

        # this should
        instance.check_precondition = MagicMock(return_value=True)
        try:
            self.redis_monitor._process_key_val(instance, key, value)
            self.fail('handler not called')
        except BaseException as e:
            self.assertEqual('handler', str(e))

    def test_get_fail_key(self):
        key = 'test'
        result = 'lock:test:failures'
        self.assertEqual(self.redis_monitor._get_fail_key(key), result)

    def test_process_failures(self):
        self.redis_monitor.settings = {
            'RETRY_FAILURES': True,
            'RETRY_FAILURES_MAX': 3
        }
        self.redis_monitor._get_fail_key = MagicMock(return_value='the_key')
        self.redis_monitor.redis_conn = MagicMock()
        self.redis_monitor.redis_conn.set = MagicMock()

        # test not set
        self.redis_monitor.redis_conn.get = MagicMock(return_value=None)
        self.redis_monitor._process_failures('key1')
        self.redis_monitor.redis_conn.set.assert_called_once_with('the_key', 1)

        # test set
        self.redis_monitor.redis_conn.set.reset_mock()
        self.redis_monitor.redis_conn.get = MagicMock(return_value=2)
        self.redis_monitor._process_failures('key1')
        self.redis_monitor.redis_conn.set.assert_called_once_with('the_key', 3)

        # test exceeded
        self.redis_monitor.redis_conn.delete = MagicMock()
        self.redis_monitor.redis_conn.set.reset_mock()
        self.redis_monitor.redis_conn.get = MagicMock(return_value=3)
        self.redis_monitor._process_failures('key1')
        calls = [call('the_key'), call('key1')]
        self.redis_monitor.redis_conn.delete.assert_has_calls(calls)

    @mock.patch('socket.gethostname', return_value='host')
    @mock.patch('time.time', return_value=5)
    def test_report_self(self, h, t):
        self.redis_monitor.my_uuid = '1234'
        self.redis_monitor.redis_conn = MagicMock()
        self.redis_monitor.redis_conn.set = MagicMock()
        self.redis_monitor.redis_conn.expire = MagicMock()

        self.redis_monitor._report_self()
        self.redis_monitor.redis_conn.set.assert_called_once_with(
            'stats:redis-monitor:self:host:1234', 5)
        self.redis_monitor.redis_conn.expire.assert_called_once_with(
            'stats:redis-monitor:self:host:1234', 120)
예제 #4
0
class TestRedisMonitor(TestCase):

    def setUp(self):
        self.redis_monitor = RedisMonitor("settings.py", True)
        self.redis_monitor.settings = self.redis_monitor.wrapper.load("settings.py")
        self.redis_monitor.logger = MagicMock()

    def test_load_plugins(self):
        # test loading default plugins
        assert_keys = [100, 200, 300, 400]
        self.redis_monitor._load_plugins()
        self.assertEqual(self.redis_monitor.plugins_dict.keys(), assert_keys)

        # test removing a plugin from settings
        assert_keys = [100, 300, 400]
        self.redis_monitor.settings['PLUGINS'] \
            ['plugins.stop_monitor.StopMonitor'] = None
        self.redis_monitor._load_plugins()
        self.assertEqual(self.redis_monitor.plugins_dict.keys(), assert_keys)
        self.redis_monitor.settings['PLUGINS'] \
            ['plugins.stop_monitor.StopMonitor'] = 200

        # fail if the class is not found
        self.redis_monitor.settings['PLUGINS'] \
            ['plugins.crazy_class.CrazyHandler'] = 400,

        self.assertRaises(ImportError, self.redis_monitor._load_plugins)
        del self.redis_monitor.settings['PLUGINS'] \
            ['plugins.crazy_class.CrazyHandler']
        self.redis_monitor.settings['PLUGINS'] = {}

    def test_active_plugins(self):
        # test that exceptions are caught within each plugin
        # assuming now all plugins are loaded
        self.redis_monitor._load_plugins()
        self.redis_monitor.stats_dict = {}

        # BaseExceptions are never raised normally
        self.redis_monitor.plugins_dict.items()[0][1]['instance'].handle = MagicMock(side_effect=BaseException("info"))
        self.redis_monitor.plugins_dict.items()[1][1]['instance'].handle = MagicMock(side_effect=BaseException("stop"))
        self.redis_monitor.plugins_dict.items()[2][1]['instance'].handle = MagicMock(side_effect=BaseException("expire"))
        self.redis_monitor.redis_conn = MagicMock()
        self.redis_monitor.redis_conn.scan_iter = MagicMock()
        # lets just assume the regex worked
        self.redis_monitor.redis_conn.scan_iter.return_value = ['somekey1']

        # info
        try:
            plugin = self.redis_monitor.plugins_dict.items()[0][1]
            self.redis_monitor._process_plugin(plugin)
            self.fail("Info not called")
        except BaseException as e:
            self.assertEquals("info", e.message)

        # action
        try:
            plugin = self.redis_monitor.plugins_dict.items()[1][1]
            self.redis_monitor._process_plugin(plugin)
            self.fail("Stop not called")
        except BaseException as e:
            self.assertEquals("stop", e.message)

        # expire
        try:
            plugin = self.redis_monitor.plugins_dict.items()[2][1]
            self.redis_monitor._process_plugin(plugin)
            self.fail("Expire not called")
        except BaseException as e:
            self.assertEquals("expire", e.message)

        # test that an exception within a handle method is caught
        try:
            self.redis_monitor.plugins_dict.items()[0][1]['instance'].handle = MagicMock(side_effect=Exception("normal"))
            plugin = self.redis_monitor.plugins_dict.items()[0][1]
            self.redis_monitor._process_plugin(plugin)
        except Exception as e:
            self.fail("Normal Exception not handled")

    def test_load_stats_plugins(self):
        # lets assume we are loading the default plugins
        self.redis_monitor._load_plugins()
        self.redis_monitor.redis_conn = MagicMock()

        # test no rolling stats
        self.redis_monitor.stats_dict = {}
        self.redis_monitor.settings['STATS_TIMES'] = []
        self.redis_monitor._setup_stats_plugins()
        defaults = [
            'ExpireMonitor',
            'StopMonitor',
            'InfoMonitor',
            'StatsMonitor'
        ]

        self.assertEquals(
            sorted(self.redis_monitor.stats_dict['plugins'].keys()),
            sorted(defaults))

        for key in self.redis_monitor.plugins_dict:
            plugin_name = self.redis_monitor.plugins_dict[key]['instance'].__class__.__name__
            self.assertEquals(
                self.redis_monitor.stats_dict['plugins'][plugin_name].keys(),
                ['lifetime'])

        # test good/bad rolling stats
        self.redis_monitor.stats_dict = {}
        self.redis_monitor.settings['STATS_TIMES'] = [
            'SECONDS_15_MINUTE',
            'SECONDS_1_HOUR',
            'SECONDS_DUMB',
        ]
        good = [
            'lifetime', # for totals, not DUMB
            900,
            3600,
        ]

        self.redis_monitor._setup_stats_plugins()

        self.assertEquals(
            sorted(self.redis_monitor.stats_dict['plugins'].keys()),
            sorted(defaults))

        for key in self.redis_monitor.plugins_dict:
            plugin_name = self.redis_monitor.plugins_dict[key]['instance'].__class__.__name__
            self.assertEquals(
                sorted(self.redis_monitor.stats_dict['plugins'][plugin_name].keys()),
                sorted(good))

        for plugin_key in self.redis_monitor.stats_dict['plugins']:
            k1 = 'stats:redis-monitor:{p}'.format(p=plugin_key)
            for time_key in self.redis_monitor.stats_dict['plugins'][plugin_key]:
                if time_key == 0:
                    self.assertEquals(
                        self.redis_monitor.stats_dict['plugins'][plugin_key][0].key,
                        '{k}:lifetime'.format(k=k1)
                        )
                else:
                    self.assertEquals(
                        self.redis_monitor.stats_dict['plugins'][plugin_key][time_key].key,
                        '{k}:{t}'.format(k=k1, t=time_key)
                        )

    def test_main_loop(self):
        self.redis_monitor._load_plugins()
        self.redis_monitor._process_plugin = MagicMock(side_effect=Exception(
                                                       "normal"))

        try:
            self.redis_monitor._main_loop()
            self.fail("_process_plugin not called")
        except BaseException as e:
            self.assertEquals("normal", e.message)

    def test_precondition(self):
        self.redis_monitor.stats_dict = {}
        instance = MagicMock()
        instance.check_precondition = MagicMock(return_value=False)
        instance.handle = MagicMock(side_effect=Exception("handler"))
        key = 'stuff'
        value = 'blah'

        # this should not raise an exception
        self.redis_monitor._process_key_val(instance, key, value)

        # this should
        instance.check_precondition = MagicMock(return_value=True)
        try:
            self.redis_monitor._process_key_val(instance, key, value)
            self.fail('handler not called')
        except BaseException as e:
            self.assertEquals('handler', e.message)