|
@@ -244,7 +244,7 @@ class MockBob(BoB):
|
|
|
def stop_creator(self, kill=False):
|
|
|
self.creator = False
|
|
|
|
|
|
- def read_bind10_config(self):
|
|
|
+ def _read_bind10_config(self):
|
|
|
# Configuration options are set directly
|
|
|
pass
|
|
|
|
|
@@ -278,7 +278,6 @@ class MockBob(BoB):
|
|
|
|
|
|
def start_simple(self, name):
|
|
|
procmap = { 'b10-xfrout': self.start_xfrout,
|
|
|
- 'b10-xfrin': self.start_xfrin,
|
|
|
'b10-zonemgr': self.start_zonemgr,
|
|
|
'b10-stats': self.start_stats,
|
|
|
'b10-stats-httpd': self.start_stats_httpd,
|
|
@@ -324,13 +323,13 @@ class MockBob(BoB):
|
|
|
return procinfo
|
|
|
|
|
|
def start_dhcp6(self):
|
|
|
- self.stats = True
|
|
|
+ self.dhcp6 = True
|
|
|
procinfo = ProcessInfo('b10-dhcp6', ['/bin/false'])
|
|
|
procinfo.pid = 13
|
|
|
return procinfo
|
|
|
|
|
|
def start_dhcp4(self):
|
|
|
- self.stats = True
|
|
|
+ self.dhcp4 = True
|
|
|
procinfo = ProcessInfo('b10-dhcp4', ['/bin/false'])
|
|
|
procinfo.pid = 14
|
|
|
return procinfo
|
|
@@ -346,9 +345,7 @@ class MockBob(BoB):
|
|
|
'b10-cmdctl': self.stop_cmdctl }
|
|
|
procmap[process]()
|
|
|
|
|
|
- # We don't really use all of these stop_ methods. But it might turn out
|
|
|
- # someone would add some stop_ method to BoB and we want that one overriden
|
|
|
- # in case he forgets to update the tests.
|
|
|
+ # Some functions to pretend we stop processes, use by stop_process
|
|
|
def stop_msgq(self):
|
|
|
if self.msgq:
|
|
|
del self.components[2]
|
|
@@ -467,70 +464,61 @@ class TestStartStopProcessesBob(unittest.TestCase):
|
|
|
"""
|
|
|
Check if proper combinations of DHCPv4 and DHCpv6 can be started
|
|
|
"""
|
|
|
- v4found = 'b10-dhcp4' in bob.component_config
|
|
|
- v6found = 'b10-dhcp6' in bob.component_config
|
|
|
-
|
|
|
- # there should be exactly one DHCPv4 daemon (if v4==True)
|
|
|
- # there should be exactly one DHCPv6 daemon (if v6==True)
|
|
|
- self.assertEqual(v4==True, v4found==1)
|
|
|
- self.assertEqual(v6==True, v6found==1)
|
|
|
+ self.assertEqual(v4, bob.dhcp4)
|
|
|
+ self.assertEqual(v6, bob.dhcp6)
|
|
|
self.check_environment_unchanged()
|
|
|
|
|
|
- # Checks the components started when starting neither auth nor resolver
|
|
|
- # is specified.
|
|
|
- def test_start_none(self):
|
|
|
- # Create BoB and ensure correct initialization
|
|
|
- bob = MockBob()
|
|
|
- self.check_preconditions(bob)
|
|
|
-
|
|
|
- # Start components and check what was started
|
|
|
- bob.cfg_start_auth = False
|
|
|
- bob.cfg_start_resolver = False
|
|
|
-
|
|
|
- bob.start_all_components()
|
|
|
- self.check_started_none(bob)
|
|
|
-
|
|
|
- # Checks the components started when starting only the auth process
|
|
|
- def test_start_auth(self):
|
|
|
- # Create BoB and ensure correct initialization
|
|
|
+ def construct_config(self, start_auth, start_resolver):
|
|
|
+ # The things that are common, not turned on an off
|
|
|
+ config = {}
|
|
|
+ config['b10-stats'] = { 'kind': 'dispensable', 'address': 'Stats' }
|
|
|
+ config['b10-stats-httpd'] = { 'kind': 'dispensable',
|
|
|
+ 'address': 'StatsHttpd' }
|
|
|
+ config['b10-cmdctl'] = { 'kind': 'needed', 'special': 'cmdctl' }
|
|
|
+ if start_auth:
|
|
|
+ config['b10-auth'] = { 'kind': 'needed', 'special': 'auth' }
|
|
|
+ config['b10-xfrout'] = { 'kind': 'dispensable',
|
|
|
+ 'address': 'Xfrout' }
|
|
|
+ config['b10-xfrin'] = { 'kind': 'dispensable', 'special': 'xfrin' }
|
|
|
+ config['b10-zonemgr'] = { 'kind': 'dispensable',
|
|
|
+ 'address': 'Zonemgr' }
|
|
|
+ if start_resolver:
|
|
|
+ config['b10-resolver'] = { 'kind': 'needed',
|
|
|
+ 'special': 'resolver' }
|
|
|
+ return {'components': config}
|
|
|
+
|
|
|
+ def config_start_init(self, start_auth, start_resolver):
|
|
|
+ """
|
|
|
+ Test the configuration is loaded at the startup.
|
|
|
+ """
|
|
|
bob = MockBob()
|
|
|
- self.check_preconditions(bob)
|
|
|
-
|
|
|
- # Start components and check what was started
|
|
|
- bob.cfg_start_auth = True
|
|
|
- bob.cfg_start_resolver = False
|
|
|
-
|
|
|
+ config = self.construct_config(start_auth, start_resolver)
|
|
|
+ class CC:
|
|
|
+ def get_full_config(self):
|
|
|
+ return config
|
|
|
+ # Provide the fake CC with data
|
|
|
+ bob.ccs = CC()
|
|
|
+ # And make sure it's not overwritten
|
|
|
+ def start_ccsession():
|
|
|
+ bob.ccsession = True
|
|
|
+ bob.start_ccsession = lambda _: start_ccsession()
|
|
|
+ # We need to return the original _read_bind10_config
|
|
|
+ bob._read_bind10_config = lambda: BoB._read_bind10_config(bob)
|
|
|
bob.start_all_components()
|
|
|
+ self.check_started(bob, True, start_auth, start_resolver)
|
|
|
+ self.check_environment_unchanged()
|
|
|
|
|
|
- self.check_started_auth(bob)
|
|
|
+ def test_start_none(self):
|
|
|
+ self.config_start_init(False, False)
|
|
|
|
|
|
- # Checks the components started when starting only the resolver process
|
|
|
def test_start_resolver(self):
|
|
|
- # Create BoB and ensure correct initialization
|
|
|
- bob = MockBob()
|
|
|
- self.check_preconditions(bob)
|
|
|
-
|
|
|
- # Start components and check what was started
|
|
|
- bob.cfg_start_auth = False
|
|
|
- bob.cfg_start_resolver = True
|
|
|
-
|
|
|
- bob.start_all_components()
|
|
|
+ self.config_start_init(False, True)
|
|
|
|
|
|
- self.check_started_resolver(bob)
|
|
|
+ def test_start_auth(self):
|
|
|
+ self.config_start_init(True, False)
|
|
|
|
|
|
- # Checks the components started when starting both auth and resolver process
|
|
|
def test_start_both(self):
|
|
|
- # Create BoB and ensure correct initialization
|
|
|
- bob = MockBob()
|
|
|
- self.check_preconditions(bob)
|
|
|
-
|
|
|
- # Start components and check what was started
|
|
|
- bob.cfg_start_auth = True
|
|
|
- bob.cfg_start_resolver = True
|
|
|
-
|
|
|
- bob.start_all_components()
|
|
|
-
|
|
|
- self.check_started_both(bob)
|
|
|
+ self.config_start_init(True, True)
|
|
|
|
|
|
def test_config_start(self):
|
|
|
"""
|
|
@@ -542,17 +530,14 @@ class TestStartStopProcessesBob(unittest.TestCase):
|
|
|
bob = MockBob()
|
|
|
self.check_preconditions(bob)
|
|
|
|
|
|
- # Start components (nothing much should be started, as in
|
|
|
- # test_start_none)
|
|
|
- bob.cfg_start_auth = False
|
|
|
- bob.cfg_start_resolver = False
|
|
|
-
|
|
|
bob.start_all_components()
|
|
|
bob.runnable = True
|
|
|
+ bob._BoB_started = True
|
|
|
+ bob.config_handler(self.construct_config(False, False))
|
|
|
self.check_started_none(bob)
|
|
|
|
|
|
# Enable both at once
|
|
|
- bob.config_handler({'start_auth': True, 'start_resolver': True})
|
|
|
+ bob.config_handler(self.construct_config(True, True))
|
|
|
self.check_started_both(bob)
|
|
|
|
|
|
# Not touched by empty change
|
|
@@ -560,11 +545,11 @@ class TestStartStopProcessesBob(unittest.TestCase):
|
|
|
self.check_started_both(bob)
|
|
|
|
|
|
# Not touched by change to the same configuration
|
|
|
- bob.config_handler({'start_auth': True, 'start_resolver': True})
|
|
|
+ bob.config_handler(self.construct_config(True, True))
|
|
|
self.check_started_both(bob)
|
|
|
|
|
|
# Turn them both off again
|
|
|
- bob.config_handler({'start_auth': False, 'start_resolver': False})
|
|
|
+ bob.config_handler(self.construct_config(False, False))
|
|
|
self.check_started_none(bob)
|
|
|
|
|
|
# Not touched by empty change
|
|
@@ -572,47 +557,46 @@ class TestStartStopProcessesBob(unittest.TestCase):
|
|
|
self.check_started_none(bob)
|
|
|
|
|
|
# Not touched by change to the same configuration
|
|
|
- bob.config_handler({'start_auth': False, 'start_resolver': False})
|
|
|
+ bob.config_handler(self.construct_config(False, False))
|
|
|
self.check_started_none(bob)
|
|
|
|
|
|
# Start and stop auth separately
|
|
|
- bob.config_handler({'start_auth': True})
|
|
|
+ bob.config_handler(self.construct_config(True, False))
|
|
|
self.check_started_auth(bob)
|
|
|
|
|
|
- bob.config_handler({'start_auth': False})
|
|
|
+ bob.config_handler(self.construct_config(False, False))
|
|
|
self.check_started_none(bob)
|
|
|
|
|
|
# Start and stop resolver separately
|
|
|
- bob.config_handler({'start_resolver': True})
|
|
|
+ bob.config_handler(self.construct_config(False, True))
|
|
|
self.check_started_resolver(bob)
|
|
|
|
|
|
- bob.config_handler({'start_resolver': False})
|
|
|
+ bob.config_handler(self.construct_config(False, False))
|
|
|
self.check_started_none(bob)
|
|
|
|
|
|
# Alternate
|
|
|
- bob.config_handler({'start_auth': True})
|
|
|
+ bob.config_handler(self.construct_config(True, False))
|
|
|
self.check_started_auth(bob)
|
|
|
|
|
|
- bob.config_handler({'start_auth': False, 'start_resolver': True})
|
|
|
+ bob.config_handler(self.construct_config(False, True))
|
|
|
self.check_started_resolver(bob)
|
|
|
|
|
|
- bob.config_handler({'start_auth': True, 'start_resolver': False})
|
|
|
+ bob.config_handler(self.construct_config(True, False))
|
|
|
self.check_started_auth(bob)
|
|
|
|
|
|
def test_config_start_once(self):
|
|
|
"""
|
|
|
- Tests that a process is started only once.
|
|
|
+ Tests that a component is started only once.
|
|
|
"""
|
|
|
# Create BoB and ensure correct initialization
|
|
|
bob = MockBob()
|
|
|
self.check_preconditions(bob)
|
|
|
|
|
|
- # Start components (both)
|
|
|
- bob.cfg_start_auth = True
|
|
|
- bob.cfg_start_resolver = True
|
|
|
-
|
|
|
bob.start_all_components()
|
|
|
+
|
|
|
+ bob._BoB_started = True
|
|
|
bob.runnable = True
|
|
|
+ bob.config_handler(self.construct_config(True, True))
|
|
|
self.check_started_both(bob)
|
|
|
|
|
|
bob.start_auth = lambda: self.fail("Started auth again")
|
|
@@ -622,8 +606,7 @@ class TestStartStopProcessesBob(unittest.TestCase):
|
|
|
bob.start_resolver = lambda: self.fail("Started resolver again")
|
|
|
|
|
|
# Send again we want to start them. Should not do it, as they are.
|
|
|
- bob.config_handler({'start_auth': True})
|
|
|
- bob.config_handler({'start_resolver': True})
|
|
|
+ bob.config_handler(self.construct_config(True, True))
|
|
|
|
|
|
def test_config_not_started_early(self):
|
|
|
"""
|
|
@@ -648,29 +631,24 @@ class TestStartStopProcessesBob(unittest.TestCase):
|
|
|
bob = MockBob()
|
|
|
self.check_preconditions(bob)
|
|
|
|
|
|
- # don't care about DNS stuff
|
|
|
- bob.cfg_start_auth = False
|
|
|
- bob.cfg_start_resolver = False
|
|
|
-
|
|
|
- # v4 and v6 disabled
|
|
|
- bob.cfg_start_dhcp6 = False
|
|
|
- bob.cfg_start_dhcp4 = False
|
|
|
bob.start_all_components()
|
|
|
+ bob._BoB_started = True
|
|
|
+ bob.runnable = True
|
|
|
+ bob.config_handler(self.construct_config(False, False))
|
|
|
self.check_started_dhcp(bob, False, False)
|
|
|
|
|
|
def test_start_dhcp_v6only(self):
|
|
|
# Create BoB and ensure correct initialization
|
|
|
bob = MockBob()
|
|
|
self.check_preconditions(bob)
|
|
|
-
|
|
|
- # don't care about DNS stuff
|
|
|
- bob.cfg_start_auth = False
|
|
|
- bob.cfg_start_resolver = False
|
|
|
-
|
|
|
# v6 only enabled
|
|
|
- bob.cfg_start_dhcp6 = True
|
|
|
- bob.cfg_start_dhcp4 = False
|
|
|
bob.start_all_components()
|
|
|
+ bob.runnable = True
|
|
|
+ bob._BoB_started = True
|
|
|
+ config = self.construct_config(False, False)
|
|
|
+ config['components']['b10-dhcp6'] = { 'kind': 'needed',
|
|
|
+ 'address': 'Dhcp6' }
|
|
|
+ bob.config_handler(config)
|
|
|
self.check_started_dhcp(bob, False, True)
|
|
|
|
|
|
# uncomment when dhcpv4 becomes implemented
|
|
@@ -857,6 +835,159 @@ class TestBrittle(unittest.TestCase):
|
|
|
sys.stdout = old_stdout
|
|
|
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_components()
|
|
|
+ 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 components 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.components = {}
|
|
|
+ def pid(self):
|
|
|
+ return 1
|
|
|
+ def name(self):
|
|
|
+ return "Immortal"
|
|
|
+ bob.components = {}
|
|
|
+ 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_components()
|
|
|
+ self.__check_extended(self.__param)
|
|
|
+
|
|
|
if __name__ == '__main__':
|
|
|
# store os.environ for test_unchanged_environment
|
|
|
original_os_environ = copy.deepcopy(os.environ)
|