|
@@ -801,6 +801,159 @@ class TestBrittle(unittest.TestCase):
|
|
sys.stdout = old_stdout
|
|
sys.stdout = old_stdout
|
|
self.assertFalse(bob.runnable)
|
|
self.assertFalse(bob.runnable)
|
|
|
|
|
|
|
|
+class TestBossComponents(unittest.TestCase):
|
|
|
|
+ """
|
|
|
|
+ Test the boss propagates component configuration properly to the
|
|
|
|
+ component configurator and acts sane.
|
|
|
|
+ """
|
|
|
|
+ def setUp(self):
|
|
|
|
+ self.__param = None
|
|
|
|
+ self.__called = False
|
|
|
|
+ self.__compconfig = {
|
|
|
|
+ 'comp': {
|
|
|
|
+ 'kind': 'needed',
|
|
|
|
+ 'process': 'cat'
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ def __unary_hook(self, param):
|
|
|
|
+ """
|
|
|
|
+ A hook function that stores the parameter for later examination.
|
|
|
|
+ """
|
|
|
|
+ self.__param = param
|
|
|
|
+
|
|
|
|
+ def __nullary_hook(self):
|
|
|
|
+ """
|
|
|
|
+ A hook function that notes down it was called.
|
|
|
|
+ """
|
|
|
|
+ self.__called = True
|
|
|
|
+
|
|
|
|
+ def __check_core(self, config):
|
|
|
|
+ """
|
|
|
|
+ A function checking that the config contains parts for the valid
|
|
|
|
+ core component configuration.
|
|
|
|
+ """
|
|
|
|
+ self.assertIsNotNone(config)
|
|
|
|
+ for component in ['sockcreator', 'msgq', 'cfgmgr']:
|
|
|
|
+ self.assertTrue(component in config)
|
|
|
|
+ self.assertEqual(component, config[component]['special'])
|
|
|
|
+ self.assertEqual('core', config[component]['kind'])
|
|
|
|
+
|
|
|
|
+ def __check_extended(self, config):
|
|
|
|
+ """
|
|
|
|
+ This checks that the config contains the core and one more component.
|
|
|
|
+ """
|
|
|
|
+ self.__check_core(config)
|
|
|
|
+ self.assertTrue('comp' in config)
|
|
|
|
+ self.assertEqual('cat', config['comp']['process'])
|
|
|
|
+ self.assertEqual('needed', config['comp']['kind'])
|
|
|
|
+ self.assertEqual(4, len(config))
|
|
|
|
+
|
|
|
|
+ def test_correct_run(self):
|
|
|
|
+ """
|
|
|
|
+ Test the situation when we run in usual scenario, nothing fails,
|
|
|
|
+ we just start, reconfigure and then stop peacefully.
|
|
|
|
+ """
|
|
|
|
+ bob = MockBob()
|
|
|
|
+ # Start it
|
|
|
|
+ orig = bob._component_configurator.startup
|
|
|
|
+ bob._component_configurator.startup = self.__unary_hook
|
|
|
|
+ bob.start_all_processes()
|
|
|
|
+ bob._component_configurator.startup = orig
|
|
|
|
+ self.__check_core(self.__param)
|
|
|
|
+ self.assertEqual(3, len(self.__param))
|
|
|
|
+
|
|
|
|
+ # Reconfigure it
|
|
|
|
+ self.__param = None
|
|
|
|
+ orig = bob._component_configurator.reconfigure
|
|
|
|
+ bob._component_configurator.reconfigure = self.__unary_hook
|
|
|
|
+ # Otherwise it does not work
|
|
|
|
+ bob.runnable = True
|
|
|
|
+ bob.config_handler({'components': self.__compconfig})
|
|
|
|
+ self.__check_extended(self.__param)
|
|
|
|
+ currconfig = self.__param
|
|
|
|
+ # If we reconfigure it, but it does not contain the components part,
|
|
|
|
+ # nothing is called
|
|
|
|
+ bob.config_handler({})
|
|
|
|
+ self.assertEqual(self.__param, currconfig)
|
|
|
|
+ self.__param = None
|
|
|
|
+ bob._component_configurator.reconfigure = orig
|
|
|
|
+ # Check a configuration that messes up the core components is rejected.
|
|
|
|
+ compconf = dict(self.__compconfig)
|
|
|
|
+ compconf['msgq'] = { 'process': 'echo' }
|
|
|
|
+ result = bob.config_handler({'components': compconf})
|
|
|
|
+ # Check it rejected it
|
|
|
|
+ self.assertEqual(1, result['result'][0])
|
|
|
|
+
|
|
|
|
+ # We can't call shutdown, that one relies on the stuff in main
|
|
|
|
+ # We check somewhere else that the shutdown is actually called
|
|
|
|
+ # from there (the test_kills).
|
|
|
|
+
|
|
|
|
+ def test_kills(self):
|
|
|
|
+ """
|
|
|
|
+ Test that the boss kills processes which don't want to stop.
|
|
|
|
+ """
|
|
|
|
+ bob = MockBob()
|
|
|
|
+ killed = []
|
|
|
|
+ class ImmortalComponent:
|
|
|
|
+ """
|
|
|
|
+ An immortal component. It does not stop when it is told so
|
|
|
|
+ (anyway it is not told so). It does not die if it is killed
|
|
|
|
+ the first time. It dies only when killed forcefully.
|
|
|
|
+ """
|
|
|
|
+ def kill(self, forcefull=False):
|
|
|
|
+ killed.append(forcefull)
|
|
|
|
+ if forcefull:
|
|
|
|
+ bob.processes = {}
|
|
|
|
+ def pid(self):
|
|
|
|
+ return 1
|
|
|
|
+ def name(self):
|
|
|
|
+ return "Immortal"
|
|
|
|
+ bob.processes = {}
|
|
|
|
+ bob.register_process(1, ImmortalComponent())
|
|
|
|
+
|
|
|
|
+ # While at it, we check the configurator shutdown is actually called
|
|
|
|
+ orig = bob._component_configurator.shutdown
|
|
|
|
+ bob._component_configurator.shutdown = self.__nullary_hook
|
|
|
|
+ self.__called = False
|
|
|
|
+
|
|
|
|
+ bob.shutdown()
|
|
|
|
+
|
|
|
|
+ self.assertEqual([False, True], killed)
|
|
|
|
+ self.assertTrue(self.__called)
|
|
|
|
+
|
|
|
|
+ bob._component_configurator.shutdown = orig
|
|
|
|
+
|
|
|
|
+ def test_component_shutdown(self):
|
|
|
|
+ """
|
|
|
|
+ Test the component_shutdown sets all variables accordingly.
|
|
|
|
+ """
|
|
|
|
+ bob = MockBob()
|
|
|
|
+ self.assertRaises(Exception, bob.component_shutdown, 1)
|
|
|
|
+ self.assertEqual(1, bob.exitcode)
|
|
|
|
+ bob._BoB__started = True
|
|
|
|
+ bob.runnable = True
|
|
|
|
+ bob.component_shutdown(2)
|
|
|
|
+ self.assertEqual(2, bob.exitcode)
|
|
|
|
+ self.assertFalse(bob.runnable)
|
|
|
|
+
|
|
|
|
+ def test_init_config(self):
|
|
|
|
+ """
|
|
|
|
+ Test initial configuration is loaded.
|
|
|
|
+ """
|
|
|
|
+ bob = MockBob()
|
|
|
|
+ # Start it
|
|
|
|
+ bob._component_configurator.reconfigure = self.__unary_hook
|
|
|
|
+ # We need to return the original read_bind10_config
|
|
|
|
+ bob.read_bind10_config = lambda: BoB.read_bind10_config(bob)
|
|
|
|
+ # And provide a session to read the data from
|
|
|
|
+ class CC:
|
|
|
|
+ pass
|
|
|
|
+ bob.ccs = CC()
|
|
|
|
+ bob.ccs.get_full_config = lambda: {'components': self.__compconfig}
|
|
|
|
+ bob.start_all_processes()
|
|
|
|
+ self.__check_extended(self.__param)
|
|
|
|
+
|
|
if __name__ == '__main__':
|
|
if __name__ == '__main__':
|
|
# store os.environ for test_unchanged_environment
|
|
# store os.environ for test_unchanged_environment
|
|
original_os_environ = copy.deepcopy(os.environ)
|
|
original_os_environ = copy.deepcopy(os.environ)
|