def test_handle_isolation(self): """ Test the isolation of addresses. """ from supvisors.context import Context from supvisors.ttypes import AddressStates context = Context(self.supvisors) with patch.object(self.supvisors.zmq.publisher, 'send_address_status') as mocked_send: # update address states context.addresses['127.0.0.1']._state = AddressStates.CHECKING context.addresses['10.0.0.1']._state = AddressStates.RUNNING context.addresses['10.0.0.2']._state = AddressStates.SILENT context.addresses['10.0.0.3']._state = AddressStates.ISOLATED context.addresses['10.0.0.4']._state = AddressStates.ISOLATING context.addresses['10.0.0.5']._state = AddressStates.ISOLATING # call method and check result result = context.handle_isolation() self.assertEqual(AddressStates.CHECKING, context.addresses['127.0.0.1'].state) self.assertEqual(AddressStates.RUNNING, context.addresses['10.0.0.1'].state) self.assertEqual(AddressStates.SILENT, context.addresses['10.0.0.2'].state) self.assertEqual(AddressStates.ISOLATED, context.addresses['10.0.0.3'].state) self.assertEqual(AddressStates.ISOLATED, context.addresses['10.0.0.4'].state) self.assertEqual(AddressStates.ISOLATED, context.addresses['10.0.0.5'].state) self.assertItemsEqual(['10.0.0.4', '10.0.0.5'], result) # check calls to publisher.send_address_status self.assertItemsEqual([call(context.addresses['10.0.0.4']), call(context.addresses['10.0.0.5'])], mocked_send.call_args_list)
def test_handle_isolation(self): """ Test the isolation of addresses. """ from supvisors.context import Context from supvisors.ttypes import AddressStates context = Context(self.supvisors) with patch.object(self.supvisors.zmq.publisher, 'send_address_status') as mocked_send: # update address states context.addresses['127.0.0.1']._state = AddressStates.CHECKING context.addresses['10.0.0.1']._state = AddressStates.RUNNING context.addresses['10.0.0.2']._state = AddressStates.SILENT context.addresses['10.0.0.3']._state = AddressStates.ISOLATED context.addresses['10.0.0.4']._state = AddressStates.ISOLATING context.addresses['10.0.0.5']._state = AddressStates.ISOLATING # call method and check result result = context.handle_isolation() self.assertEqual(AddressStates.CHECKING, context.addresses['127.0.0.1'].state) self.assertEqual(AddressStates.RUNNING, context.addresses['10.0.0.1'].state) self.assertEqual(AddressStates.SILENT, context.addresses['10.0.0.2'].state) self.assertEqual(AddressStates.ISOLATED, context.addresses['10.0.0.3'].state) self.assertEqual(AddressStates.ISOLATED, context.addresses['10.0.0.4'].state) self.assertEqual(AddressStates.ISOLATED, context.addresses['10.0.0.5'].state) self.assertItemsEqual(['10.0.0.4', '10.0.0.5'], result) # check calls to publisher.send_address_status self.assertItemsEqual([ call(context.addresses['10.0.0.4']), call(context.addresses['10.0.0.5']) ], mocked_send.call_args_list)
def test_setdefault_process(self): """ Test the access / creation of a process status. """ from supvisors.context import Context context = Context(self.supvisors) # check application list self.assertDictEqual({}, context.applications) self.assertDictEqual({}, context.processes) # get process dummy_info1 = {'group': 'dummy_application_1', 'name': 'dummy_process_1'} process1 = context.setdefault_process(dummy_info1) # check application and process list self.assertItemsEqual(['dummy_application_1'], context.applications.keys()) self.assertDictEqual({'dummy_application_1:dummy_process_1': process1}, context.processes) # get application dummy_info2 = {'group': 'dummy_application_2', 'name': 'dummy_process_2'} process2 = context.setdefault_process(dummy_info2) # check application and process list self.assertItemsEqual(['dummy_application_1', 'dummy_application_2'], context.applications.keys()) self.assertDictEqual({'dummy_application_1:dummy_process_1': process1, 'dummy_application_2:dummy_process_2': process2}, context.processes) # get application dummy_info3 = {'group': process1.application_name, 'name': process1.process_name} process3 = context.setdefault_process(dummy_info3) self.assertIs(process1, process3) # check application and process list self.assertItemsEqual(['dummy_application_1', 'dummy_application_2'], context.applications.keys()) self.assertDictEqual({'dummy_application_1:dummy_process_1': process1, 'dummy_application_2:dummy_process_2': process2}, context.processes)
def test_setdefault_application(self): """ Test the access / creation of an application status. """ from supvisors.context import Context context = Context(self.supvisors) # check application list self.assertDictEqual({}, context.applications) # get application application1 = context.setdefault_application('dummy_1') # check application list self.assertDictEqual({'dummy_1': application1}, context.applications) # get application application2 = context.setdefault_application('dummy_2') # check application list self.assertDictEqual({ 'dummy_1': application1, 'dummy_2': application2 }, context.applications) # get application application3 = context.setdefault_application('dummy_1') self.assertIs(application1, application3) # check application list self.assertDictEqual({ 'dummy_1': application1, 'dummy_2': application2 }, context.applications)
def test_end_synchro(self): """ Test the end of synchronization phase. """ from supvisors.context import Context from supvisors.ttypes import AddressStates context = Context(self.supvisors) # choose two addresses and change their state for address_status in context.addresses.values(): self.assertEqual(AddressStates.UNKNOWN, address_status.state) context.addresses['10.0.0.2']._state = AddressStates.RUNNING context.addresses['10.0.0.4']._state = AddressStates.ISOLATED # call end of synchro with auto_fence activated context.end_synchro() # check that UNKNOWN addresses became ISOLATING, but local address self.assertEqual(AddressStates.SILENT, context.addresses['127.0.0.1'].state) self.assertEqual(AddressStates.ISOLATING, context.addresses['10.0.0.1'].state) self.assertEqual(AddressStates.ISOLATING, context.addresses['10.0.0.3'].state) self.assertEqual(AddressStates.ISOLATING, context.addresses['10.0.0.5'].state) # reset states and set (local excepted) context.addresses['10.0.0.1']._state = AddressStates.UNKNOWN context.addresses['10.0.0.3']._state = AddressStates.UNKNOWN context.addresses['10.0.0.5']._state = AddressStates.UNKNOWN with patch.object(self.supvisors.options, 'auto_fence', False): # call end of synchro with auto_fencing deactivated context.end_synchro() # check that UNKNOWN addresses became SILENT self.assertEqual(AddressStates.SILENT, context.addresses['10.0.0.1'].state) self.assertEqual(AddressStates.SILENT, context.addresses['10.0.0.3'].state) self.assertEqual(AddressStates.SILENT, context.addresses['10.0.0.5'].state)
def test_master_address(self): """ Test the access to master address. """ from supvisors.context import Context context = Context(self.supvisors) self.assertEqual('', context.master_address) self.assertFalse(context.master) context.master_address = '10.0.0.1' self.assertEqual('10.0.0.1', context.master_address) self.assertEqual('10.0.0.1', context._master_address) self.assertFalse(context.master) context.master_address = '127.0.0.1' self.assertEqual('127.0.0.1', context.master_address) self.assertEqual('127.0.0.1', context._master_address) self.assertTrue(context.master)
def test_setdefault_process(self): """ Test the access / creation of a process status. """ from supvisors.context import Context context = Context(self.supvisors) # check application list self.assertDictEqual({}, context.applications) self.assertDictEqual({}, context.processes) # get process dummy_info1 = { 'group': 'dummy_application_1', 'name': 'dummy_process_1' } process1 = context.setdefault_process(dummy_info1) # check application and process list self.assertItemsEqual(['dummy_application_1'], context.applications.keys()) self.assertDictEqual({'dummy_application_1:dummy_process_1': process1}, context.processes) # get application dummy_info2 = { 'group': 'dummy_application_2', 'name': 'dummy_process_2' } process2 = context.setdefault_process(dummy_info2) # check application and process list self.assertItemsEqual(['dummy_application_1', 'dummy_application_2'], context.applications.keys()) self.assertDictEqual( { 'dummy_application_1:dummy_process_1': process1, 'dummy_application_2:dummy_process_2': process2 }, context.processes) # get application dummy_info3 = { 'group': process1.application_name, 'name': process1.process_name } process3 = context.setdefault_process(dummy_info3) self.assertIs(process1, process3) # check application and process list self.assertItemsEqual(['dummy_application_1', 'dummy_application_2'], context.applications.keys()) self.assertDictEqual( { 'dummy_application_1:dummy_process_1': process1, 'dummy_application_2:dummy_process_2': process2 }, context.processes)
def test_load_processes(self): """ Test the storage of processes handled by Supervisor on a given address. """ from supvisors.context import Context context = Context(self.supvisors) # check application list self.assertDictEqual({}, context.applications) self.assertDictEqual({}, context.processes) for address in context.addresses.values(): self.assertDictEqual({}, address.processes) # load ProcessInfoDatabase in unknown address with self.assertRaises(KeyError): context.load_processes('10.0.0.0', database_copy()) # load ProcessInfoDatabase in known address context.load_processes('10.0.0.1', database_copy()) # check context contents self.assertItemsEqual(['sample_test_1', 'sample_test_2', 'firefox', 'crash'], context.applications.keys()) self.assertItemsEqual(['sample_test_1:xclock', 'sample_test_1:xfontsel', 'sample_test_1:xlogo', 'sample_test_2:sleep', 'sample_test_2:yeux_00', 'sample_test_2:yeux_01', 'crash:late_segv', 'crash:segv', 'firefox'], context.processes.keys()) self.assertDictEqual(context.addresses['10.0.0.1'].processes, context.processes) # load ProcessInfoDatabase in other known address context.load_processes('10.0.0.2', database_copy()) # check context contents self.assertItemsEqual(['sample_test_1', 'sample_test_2', 'firefox', 'crash'], context.applications.keys()) self.assertItemsEqual(['sample_test_1:xclock', 'sample_test_1:xfontsel', 'sample_test_1:xlogo', 'sample_test_2:sleep', 'sample_test_2:yeux_00', 'sample_test_2:yeux_01', 'crash:late_segv', 'crash:segv', 'firefox'], context.processes.keys()) self.assertDictEqual(context.addresses['10.0.0.2'].processes, context.processes) # load different database in other known address info = any_process_info() info.update({'group': 'dummy_application', 'name': 'dummy_process'}) database = [info] context.load_processes('10.0.0.4', database) # check context contents self.assertItemsEqual(['sample_test_1', 'sample_test_2', 'firefox', 'crash', 'dummy_application'], context.applications.keys()) self.assertItemsEqual(['sample_test_1:xclock', 'sample_test_1:xfontsel', 'sample_test_1:xlogo', 'sample_test_2:sleep', 'sample_test_2:yeux_00', 'sample_test_2:yeux_01', 'crash:late_segv', 'crash:segv', 'firefox', 'dummy_application:dummy_process'], context.processes.keys()) self.assertListEqual(['dummy_application:dummy_process'], context.addresses['10.0.0.4'].processes.keys()) # equality lost between processes in addresses and processes in context self.assertNotIn(context.processes.keys(), context.addresses['10.0.0.1'].processes.keys()) self.assertNotIn(context.processes.keys(), context.addresses['10.0.0.2'].processes.keys()) self.assertNotIn(context.processes.keys(), context.addresses['10.0.0.4'].processes.keys()) self.assertDictContainsSubset(context.addresses['10.0.0.1'].processes, context.processes) self.assertDictContainsSubset(context.addresses['10.0.0.2'].processes, context.processes) self.assertDictContainsSubset(context.addresses['10.0.0.4'].processes, context.processes)
def test_timer_event(self): """ Test the handling of a timer event. """ from supvisors.context import Context from supvisors.ttypes import AddressStates context = Context(self.supvisors) with patch.object(self.supvisors.zmq.publisher, 'send_address_status') as mocked_send: # test address states excepting RUNNING: nothing happens for state in [x for x in AddressStates._values() if x != AddressStates.RUNNING]: context.on_timer_event() for address in context.addresses.values(): self.assertEqual(AddressStates.UNKNOWN, address.state) self.assertEqual(0, mocked_send.call_count) # test RUNNING address state with recent local_time test_addresses = ['10.0.0.1', '10.0.0.3', '10.0.0.5'] for address_name in test_addresses: address = context.addresses[address_name] address._state = AddressStates.RUNNING address.local_time = time.time() context.on_timer_event() for address_name in test_addresses: self.assertEqual(AddressStates.RUNNING, context.addresses[address_name].state) for address_name in [x for x in context.addresses.keys() if x not in test_addresses]: self.assertEqual(AddressStates.UNKNOWN, context.addresses[address_name].state) self.assertEqual(0, mocked_send.call_count) # test RUNNING address state with one recent local_time and with auto_fence activated address1 = context.addresses['10.0.0.3'] address1.local_time = time.time() - 100 context.on_timer_event() self.assertEqual(AddressStates.ISOLATING, address1.state) for address_name in [x for x in test_addresses if x != '10.0.0.3']: self.assertEqual(AddressStates.RUNNING, context.addresses[address_name].state) for address_name in [x for x in context.addresses.keys() if x not in test_addresses]: self.assertEqual(AddressStates.UNKNOWN, context.addresses[address_name].state) self.assertEqual(call(address1), mocked_send.call_args) # test with one other recent local_time and with auto_fence deactivated with patch.object(self.supvisors.options, 'auto_fence', False): mocked_send.reset_mock() address2 = context.addresses['10.0.0.5'] address2.local_time = time.time() - 100 address3 = context.addresses['10.0.0.1'] address3.local_time = time.time() - 100 context.on_timer_event() self.assertEqual(AddressStates.SILENT, address2.state) self.assertEqual(AddressStates.SILENT, address3.state) self.assertEqual(AddressStates.ISOLATING, address1.state) for address_name in [x for x in context.addresses.keys() if x not in test_addresses]: self.assertEqual(AddressStates.UNKNOWN, context.addresses[address_name].state) self.assertItemsEqual([call(address2), call(address3)], mocked_send.call_args_list)
def test_setdefault_application(self): """ Test the access / creation of an application status. """ from supvisors.context import Context context = Context(self.supvisors) # check application list self.assertDictEqual({}, context.applications) # get application application1 = context.setdefault_application('dummy_1') # check application list self.assertDictEqual({'dummy_1': application1}, context.applications) # get application application2 = context.setdefault_application('dummy_2') # check application list self.assertDictEqual({'dummy_1': application1, 'dummy_2': application2}, context.applications) # get application application3 = context.setdefault_application('dummy_1') self.assertIs(application1, application3) # check application list self.assertDictEqual({'dummy_1': application1, 'dummy_2': application2}, context.applications)
def test_tick_event(self): """ Test the handling of a timer event. """ from supvisors.context import Context from supvisors.ttypes import AddressStates context = Context(self.supvisors) with patch.object(self.supvisors.zmq.pusher, 'send_check_address') as mocked_check: with patch.object(self.supvisors.zmq.publisher, 'send_address_status') as mocked_send: # check no exception with unknown address context.on_tick_event('10.0.0.0', {}) self.assertEqual(0, mocked_check.call_count) self.assertEqual(0, mocked_send.call_count) # get address status used for tests address = context.addresses['10.0.0.1'] # check no change with known address in isolation for state in [AddressStates.ISOLATING, AddressStates.ISOLATED]: address._state = state context.on_tick_event('10.0.0.1', {}) self.assertEqual(state, address.state) self.assertEqual(0, mocked_check.call_count) self.assertEqual(0, mocked_send.call_count) # check that address is CHECKING and check_address is called # before address time is updated and address status is sent for state in [AddressStates.UNKNOWN, AddressStates.SILENT]: address._state = state context.on_tick_event('10.0.0.1', {'when': 1234}) self.assertEqual(AddressStates.CHECKING, address.state) self.assertEqual(call('10.0.0.1'), mocked_check.call_args) self.assertEqual(call(address), mocked_send.call_args) self.assertEqual(1234, address.remote_time) # check that address time is updated and address status is sent mocked_check.reset_mock() mocked_send.reset_mock() for state in [AddressStates.CHECKING, AddressStates.RUNNING]: address._state = state context.on_tick_event('10.0.0.1', {'when': 5678}) self.assertEqual(state, address.state) self.assertEqual(0, mocked_check.call_count) self.assertEqual(call(address), mocked_send.call_args) self.assertEqual(5678, address.remote_time)
def test_creation(self): """ Test the values set at construction. """ from supvisors.address import AddressStatus from supvisors.context import Context context = Context(self.supvisors) self.assertIs(self.supvisors, context.supvisors) self.assertIs(self.supvisors.address_mapper, context.address_mapper) self.assertIs(self.supvisors.logger, context.logger) self.assertItemsEqual(DummyAddressMapper().addresses, context.addresses.keys()) for address_name, address in context.addresses.items(): self.assertEqual(address_name, address.address_name) self.assertIsInstance(address, AddressStatus) self.assertDictEqual({}, context.applications) self.assertDictEqual({}, context.processes) self.assertEqual('', context._master_address) self.assertFalse(context.master)
def __init__(self, supervisord): """ Initialization of the attributes. """ # store this instance in supervisord to ensure persistence supervisord.supvisors = self # get options from config file server_options = SupvisorsServerOptions() server_options.realize() self.options = server_options.supvisors_options # create logger stdout = supervisord.options.nodaemon self.logger = getLogger(self.options.logfile, self.options.loglevel, Supvisors.LOGGER_FORMAT, True, self.options.logfile_maxbytes, self.options.logfile_backups, stdout) # configure supervisor info source self.info_source = SupervisordSource(supervisord) # set addresses and check local address self.address_mapper = AddressMapper(self.logger) self.address_mapper.addresses = self.options.address_list if not self.address_mapper.local_address: raise RPCError( Faults.SUPVISORS_CONF_ERROR, 'local host unexpected in address list: {}'.format( self.options.address_list)) # create context data self.context = Context(self) # create application starter and stopper self.starter = Starter(self) self.stopper = Stopper(self) # create statistics handler self.statistician = StatisticsCompiler(self) # create the failure handler of crashing processes self.failure_handler = RunningFailureHandler(self) # create state machine self.fsm = FiniteStateMachine(self) # check parsing try: self.parser = Parser(self) except: self.logger.warn('cannot parse rules file: {}'.format( self.options.rules_file)) self.parser = None # create event subscriber self.listener = SupervisorListener(self)
def test_invalid(self): """ Test the invalidation of an address. """ from supvisors.context import Context from supvisors.ttypes import AddressStates context = Context(self.supvisors) def check_address_status(address_name, new_state): # get address status address_status = context.addresses[address_name] # check initial state self.assertEqual(AddressStates.UNKNOWN, address_status.state) # invalidate address proc_1 = Mock(**{'invalidate_address.return_value': None}) proc_2 = Mock(**{'invalidate_address.return_value': None}) with patch.object(address_status, 'running_processes', return_value=[proc_1, proc_2]) as mocked_running: context.invalid(address_status) # check new state self.assertEqual(new_state, address_status.state) # test calls to process methods self.assertEqual([call()], mocked_running.call_args_list) self.assertEqual([call(address_name, False)], proc_1.invalidate_address.call_args_list) self.assertEqual([call(address_name, False)], proc_2.invalidate_address.call_args_list) # restore address state address_status._state = AddressStates.UNKNOWN # test address state with auto_fence and local_address check_address_status('127.0.0.1', AddressStates.SILENT) # test address state with auto_fence and other than local_address check_address_status('10.0.0.1', AddressStates.ISOLATING) # test address state without auto_fence with patch.object(self.supvisors.options, 'auto_fence', False): # test address state without auto_fence and local_address check_address_status('127.0.0.1', AddressStates.SILENT) # test address state without auto_fence and other than local_address check_address_status('10.0.0.2', AddressStates.SILENT)
def test_process_event(self): """ Test the handling of a process event. """ from supvisors.context import Context from supvisors.ttypes import AddressStates, ApplicationStates context = Context(self.supvisors) with patch.object(self.supvisors.zmq.publisher, 'send_application_status') as mocked_appli: with patch.object(self.supvisors.zmq.publisher, 'send_process_status') as mocked_proc: # check no exception with unknown address result = context.on_process_event('10.0.0.0', {}) self.assertIsNone(result) self.assertEqual(0, mocked_appli.call_count) self.assertEqual(0, mocked_proc.call_count) # get address status used for tests address = context.addresses['10.0.0.1'] # check no change with known address in isolation for state in [AddressStates.ISOLATING, AddressStates.ISOLATED]: address._state = state result = context.on_process_event('10.0.0.1', {}) self.assertIsNone(result) self.assertEqual(0, mocked_appli.call_count) self.assertEqual(0, mocked_proc.call_count) # check no exception with unknown process for state in [AddressStates.UNKNOWN, AddressStates.SILENT, AddressStates.CHECKING, AddressStates.RUNNING]: address._state = state result = context.on_process_event('10.0.0.1', {'groupname': 'dummy_application', 'processname': 'dummy_process'}) self.assertIsNone(result) self.assertEqual(0, mocked_appli.call_count) self.assertEqual(0, mocked_proc.call_count) # fill context with one process dummy_info = {'group': 'dummy_application', 'name': 'dummy_process', 'expected': True, 'now': 1234, 'state': 0} process = context.setdefault_process(dummy_info) process.add_info('10.0.0.1', dummy_info) application = context.applications['dummy_application'] self.assertEqual(ApplicationStates.STOPPED, application.state) # check normal behaviour with known process dummy_event = {'group': 'dummy_application', 'name': 'dummy_process', 'state': 10, 'now': 2345} for state in [AddressStates.UNKNOWN, AddressStates.SILENT, AddressStates.CHECKING, AddressStates.RUNNING]: address._state = state result = context.on_process_event('10.0.0.1', dummy_event) self.assertIs(process, result) self.assertEqual(10, process.state) self.assertEqual(ApplicationStates.STARTING, application.state) self.assertEqual(call(application), mocked_appli.call_args) self.assertEqual(call(process), mocked_proc.call_args)
def test_TODO(self): """ Test the values set at construction. """ from supvisors.context import Context context = Context(self.supvisors) self.assertIsNotNone(context)
def test_addresses_by_state(self): """ Test the access to addresses in unknown state. """ from supvisors.context import Context from supvisors.ttypes import AddressStates context = Context(self.supvisors) # test initial states self.assertItemsEqual(DummyAddressMapper().addresses, context.unknown_addresses()) self.assertItemsEqual([], context.running_addresses()) self.assertItemsEqual([], context.isolating_addresses()) self.assertItemsEqual([], context.isolation_addresses()) self.assertItemsEqual([], context.addresses_by_states([ AddressStates.RUNNING, AddressStates.ISOLATED ])) self.assertItemsEqual([], context.addresses_by_states( [AddressStates.SILENT])) self.assertItemsEqual( DummyAddressMapper().addresses, context.addresses_by_states([AddressStates.UNKNOWN])) # change states context.addresses['127.0.0.1']._state = AddressStates.RUNNING context.addresses['10.0.0.1']._state = AddressStates.SILENT context.addresses['10.0.0.2']._state = AddressStates.ISOLATING context.addresses['10.0.0.3']._state = AddressStates.ISOLATED context.addresses['10.0.0.4']._state = AddressStates.RUNNING # test new states self.assertItemsEqual(['10.0.0.5'], context.unknown_addresses()) self.assertItemsEqual(['127.0.0.1', '10.0.0.4'], context.running_addresses()) self.assertItemsEqual(['10.0.0.2'], context.isolating_addresses()) self.assertItemsEqual(['10.0.0.2', '10.0.0.3'], context.isolation_addresses()) self.assertItemsEqual(['127.0.0.1', '10.0.0.3', '10.0.0.4'], context.addresses_by_states([ AddressStates.RUNNING, AddressStates.ISOLATED ])) self.assertItemsEqual(['10.0.0.1'], context.addresses_by_states( [AddressStates.SILENT])) self.assertItemsEqual(['10.0.0.5'], context.addresses_by_states( [AddressStates.UNKNOWN]))
def test_authorization(self): """ Test the handling of an authorization event. """ from supvisors.context import Context from supvisors.ttypes import AddressStates, InvalidTransition context = Context(self.supvisors) # check no exception with unknown address context.on_authorization('10.0.0.0', True) # check no change with known address in isolation for state in [AddressStates.ISOLATING, AddressStates.ISOLATED]: for authorization in [True, False]: context.addresses['10.0.0.1']._state = state context.on_authorization('10.0.0.1', authorization) self.assertEqual(state, context.addresses['10.0.0.1'].state) # check exception if authorized and current state not CHECKING for state in [AddressStates.UNKNOWN, AddressStates.SILENT]: context.addresses['10.0.0.2']._state = state with self.assertRaises(InvalidTransition): context.on_authorization('10.0.0.2', True) self.assertEqual(state, context.addresses['10.0.0.2'].state) # check state becomes RUNNING if authorized and current state in CHECKING for state in [AddressStates.CHECKING, AddressStates.RUNNING]: context.addresses['10.0.0.2']._state = state context.on_authorization('10.0.0.2', True) self.assertEqual(AddressStates.RUNNING, context.addresses['10.0.0.2'].state) # check state becomes ISOLATING if not authorized and auto fencing activated for state in [AddressStates.UNKNOWN, AddressStates.CHECKING, AddressStates.RUNNING]: context.addresses['10.0.0.4']._state = state context.on_authorization('10.0.0.4', False) self.assertEqual(AddressStates.ISOLATING, context.addresses['10.0.0.4'].state) # check exception if not authorized and auto fencing activated and current is SILENT context.addresses['10.0.0.4']._state = AddressStates.SILENT with self.assertRaises(InvalidTransition): context.on_authorization('10.0.0.4', True) self.assertEqual(AddressStates.SILENT, context.addresses['10.0.0.4'].state) # check state becomes SILENT if not authorized and auto fencing deactivated with patch.object(self.supvisors.options, 'auto_fence', False): for state in [AddressStates.UNKNOWN, AddressStates.CHECKING, AddressStates.SILENT, AddressStates.RUNNING]: context.addresses['10.0.0.5']._state = state context.on_authorization('10.0.0.5', False) self.assertEqual(AddressStates.SILENT, context.addresses['10.0.0.5'].state)
def test_timer_event(self): """ Test the handling of a timer event. """ from supvisors.context import Context from supvisors.ttypes import AddressStates context = Context(self.supvisors) with patch.object(self.supvisors.zmq.publisher, 'send_address_status') as mocked_send: # test address states excepting RUNNING: nothing happens for state in [ x for x in AddressStates._values() if x != AddressStates.RUNNING ]: context.on_timer_event() for address in context.addresses.values(): self.assertEqual(AddressStates.UNKNOWN, address.state) self.assertEqual(0, mocked_send.call_count) # test RUNNING address state with recent local_time test_addresses = ['10.0.0.1', '10.0.0.3', '10.0.0.5'] for address_name in test_addresses: address = context.addresses[address_name] address._state = AddressStates.RUNNING address.local_time = time.time() context.on_timer_event() for address_name in test_addresses: self.assertEqual(AddressStates.RUNNING, context.addresses[address_name].state) for address_name in [ x for x in context.addresses.keys() if x not in test_addresses ]: self.assertEqual(AddressStates.UNKNOWN, context.addresses[address_name].state) self.assertEqual(0, mocked_send.call_count) # test RUNNING address state with one recent local_time and with auto_fence activated address1 = context.addresses['10.0.0.3'] address1.local_time = time.time() - 100 context.on_timer_event() self.assertEqual(AddressStates.ISOLATING, address1.state) for address_name in [x for x in test_addresses if x != '10.0.0.3']: self.assertEqual(AddressStates.RUNNING, context.addresses[address_name].state) for address_name in [ x for x in context.addresses.keys() if x not in test_addresses ]: self.assertEqual(AddressStates.UNKNOWN, context.addresses[address_name].state) self.assertEqual(call(address1), mocked_send.call_args) # test with one other recent local_time and with auto_fence deactivated with patch.object(self.supvisors.options, 'auto_fence', False): mocked_send.reset_mock() address2 = context.addresses['10.0.0.5'] address2.local_time = time.time() - 100 address3 = context.addresses['10.0.0.1'] address3.local_time = time.time() - 100 context.on_timer_event() self.assertEqual(AddressStates.SILENT, address2.state) self.assertEqual(AddressStates.SILENT, address3.state) self.assertEqual(AddressStates.ISOLATING, address1.state) for address_name in [ x for x in context.addresses.keys() if x not in test_addresses ]: self.assertEqual(AddressStates.UNKNOWN, context.addresses[address_name].state) self.assertItemsEqual( [call(address2), call(address3)], mocked_send.call_args_list)
def test_process_event(self): """ Test the handling of a process event. """ from supvisors.context import Context from supvisors.ttypes import AddressStates, ApplicationStates context = Context(self.supvisors) with patch.object(self.supvisors.zmq.publisher, 'send_application_status') as mocked_appli: with patch.object(self.supvisors.zmq.publisher, 'send_process_status') as mocked_proc: # check no exception with unknown address result = context.on_process_event('10.0.0.0', {}) self.assertIsNone(result) self.assertEqual(0, mocked_appli.call_count) self.assertEqual(0, mocked_proc.call_count) # get address status used for tests address = context.addresses['10.0.0.1'] # check no change with known address in isolation for state in [AddressStates.ISOLATING, AddressStates.ISOLATED]: address._state = state result = context.on_process_event('10.0.0.1', {}) self.assertIsNone(result) self.assertEqual(0, mocked_appli.call_count) self.assertEqual(0, mocked_proc.call_count) # check no exception with unknown process for state in [ AddressStates.UNKNOWN, AddressStates.SILENT, AddressStates.CHECKING, AddressStates.RUNNING ]: address._state = state result = context.on_process_event( '10.0.0.1', { 'groupname': 'dummy_application', 'processname': 'dummy_process' }) self.assertIsNone(result) self.assertEqual(0, mocked_appli.call_count) self.assertEqual(0, mocked_proc.call_count) # fill context with one process dummy_info = { 'group': 'dummy_application', 'name': 'dummy_process', 'spawnerr': '', 'now': 1234, 'state': 0 } process = context.setdefault_process(dummy_info) process.add_info('10.0.0.1', dummy_info) application = context.applications['dummy_application'] self.assertEqual(ApplicationStates.STOPPED, application.state) # check normal behaviour with known process dummy_event = { 'groupname': 'dummy_application', 'processname': 'dummy_process', 'state': 10, 'now': 2345 } for state in [ AddressStates.UNKNOWN, AddressStates.SILENT, AddressStates.CHECKING, AddressStates.RUNNING ]: address._state = state result = context.on_process_event('10.0.0.1', dummy_event) self.assertIs(process, result) self.assertEqual(10, process.state) self.assertEqual(2345, process.last_event_time) self.assertEqual(ApplicationStates.STARTING, application.state) self.assertEqual(call(application), mocked_appli.call_args) self.assertEqual(call(process), mocked_proc.call_args)
def test_authorization(self): """ Test the handling of an authorization event. """ from supvisors.context import Context from supvisors.ttypes import AddressStates, InvalidTransition context = Context(self.supvisors) # check no exception with unknown address context.on_authorization('10.0.0.0', True) # check no change with known address in isolation for state in [AddressStates.ISOLATING, AddressStates.ISOLATED]: for authorization in [True, False]: context.addresses['10.0.0.1']._state = state context.on_authorization('10.0.0.1', authorization) self.assertEqual(state, context.addresses['10.0.0.1'].state) # check exception if authorized and current state not CHECKING for state in [AddressStates.UNKNOWN, AddressStates.SILENT]: context.addresses['10.0.0.2']._state = state with self.assertRaises(InvalidTransition): context.on_authorization('10.0.0.2', True) self.assertEqual(state, context.addresses['10.0.0.2'].state) # check state becomes RUNNING if authorized and current state in CHECKING for state in [AddressStates.CHECKING, AddressStates.RUNNING]: context.addresses['10.0.0.2']._state = state context.on_authorization('10.0.0.2', True) self.assertEqual(AddressStates.RUNNING, context.addresses['10.0.0.2'].state) # check state becomes ISOLATING if not authorized and auto fencing activated for state in [ AddressStates.UNKNOWN, AddressStates.CHECKING, AddressStates.RUNNING ]: context.addresses['10.0.0.4']._state = state context.on_authorization('10.0.0.4', False) self.assertEqual(AddressStates.ISOLATING, context.addresses['10.0.0.4'].state) # check exception if not authorized and auto fencing activated and current is SILENT context.addresses['10.0.0.4']._state = AddressStates.SILENT with self.assertRaises(InvalidTransition): context.on_authorization('10.0.0.4', True) self.assertEqual(AddressStates.SILENT, context.addresses['10.0.0.4'].state) # check state becomes SILENT if not authorized and auto fencing deactivated with patch.object(self.supvisors.options, 'auto_fence', False): for state in [ AddressStates.UNKNOWN, AddressStates.CHECKING, AddressStates.SILENT, AddressStates.RUNNING ]: context.addresses['10.0.0.5']._state = state context.on_authorization('10.0.0.5', False) self.assertEqual(AddressStates.SILENT, context.addresses['10.0.0.5'].state)
def test_load_processes(self): """ Test the storage of processes handled by Supervisor on a given address. """ from supvisors.context import Context context = Context(self.supvisors) # check application list self.assertDictEqual({}, context.applications) self.assertDictEqual({}, context.processes) for address in context.addresses.values(): self.assertDictEqual({}, address.processes) # load ProcessInfoDatabase in unknown address with self.assertRaises(KeyError): context.load_processes('10.0.0.0', database_copy()) # load ProcessInfoDatabase in known address context.load_processes('10.0.0.1', database_copy()) # check context contents self.assertItemsEqual( ['sample_test_1', 'sample_test_2', 'firefox', 'crash'], context.applications.keys()) self.assertItemsEqual([ 'sample_test_1:xclock', 'sample_test_1:xfontsel', 'sample_test_1:xlogo', 'sample_test_2:sleep', 'sample_test_2:yeux_00', 'sample_test_2:yeux_01', 'crash:late_segv', 'crash:segv', 'firefox' ], context.processes.keys()) self.assertDictEqual(context.addresses['10.0.0.1'].processes, context.processes) # load ProcessInfoDatabase in other known address context.load_processes('10.0.0.2', database_copy()) # check context contents self.assertItemsEqual( ['sample_test_1', 'sample_test_2', 'firefox', 'crash'], context.applications.keys()) self.assertItemsEqual([ 'sample_test_1:xclock', 'sample_test_1:xfontsel', 'sample_test_1:xlogo', 'sample_test_2:sleep', 'sample_test_2:yeux_00', 'sample_test_2:yeux_01', 'crash:late_segv', 'crash:segv', 'firefox' ], context.processes.keys()) self.assertDictEqual(context.addresses['10.0.0.2'].processes, context.processes) # load different database in other known address info = any_process_info() info.update({'group': 'dummy_application', 'name': 'dummy_process'}) database = [info] context.load_processes('10.0.0.4', database) # check context contents self.assertItemsEqual([ 'sample_test_1', 'sample_test_2', 'firefox', 'crash', 'dummy_application' ], context.applications.keys()) self.assertItemsEqual([ 'sample_test_1:xclock', 'sample_test_1:xfontsel', 'sample_test_1:xlogo', 'sample_test_2:sleep', 'sample_test_2:yeux_00', 'sample_test_2:yeux_01', 'crash:late_segv', 'crash:segv', 'firefox', 'dummy_application:dummy_process' ], context.processes.keys()) self.assertListEqual(['dummy_application:dummy_process'], context.addresses['10.0.0.4'].processes.keys()) # equality lost between processes in addresses and processes in context self.assertNotIn(context.processes.keys(), context.addresses['10.0.0.1'].processes.keys()) self.assertNotIn(context.processes.keys(), context.addresses['10.0.0.2'].processes.keys()) self.assertNotIn(context.processes.keys(), context.addresses['10.0.0.4'].processes.keys()) self.assertDictContainsSubset(context.addresses['10.0.0.1'].processes, context.processes) self.assertDictContainsSubset(context.addresses['10.0.0.2'].processes, context.processes) self.assertDictContainsSubset(context.addresses['10.0.0.4'].processes, context.processes)
def test_addresses_by_state(self): """ Test the access to addresses in unknown state. """ from supvisors.context import Context from supvisors.ttypes import AddressStates context = Context(self.supvisors) # test initial states self.assertItemsEqual(DummyAddressMapper().addresses, context.unknown_addresses()) self.assertItemsEqual([], context.running_addresses()) self.assertItemsEqual([], context.isolating_addresses()) self.assertItemsEqual([], context.isolation_addresses()) self.assertItemsEqual([], context.addresses_by_states([AddressStates.RUNNING, AddressStates.ISOLATED])) self.assertItemsEqual([], context.addresses_by_states([AddressStates.SILENT])) self.assertItemsEqual(DummyAddressMapper().addresses, context.addresses_by_states([AddressStates.UNKNOWN])) # change states context.addresses['127.0.0.1']._state = AddressStates.RUNNING context.addresses['10.0.0.1']._state = AddressStates.SILENT context.addresses['10.0.0.2']._state = AddressStates.ISOLATING context.addresses['10.0.0.3']._state = AddressStates.ISOLATED context.addresses['10.0.0.4']._state = AddressStates.RUNNING # test new states self.assertItemsEqual(['10.0.0.5'], context.unknown_addresses()) self.assertItemsEqual(['127.0.0.1', '10.0.0.4'], context.running_addresses()) self.assertItemsEqual(['10.0.0.2'], context.isolating_addresses()) self.assertItemsEqual(['10.0.0.2', '10.0.0.3'], context.isolation_addresses()) self.assertItemsEqual(['127.0.0.1', '10.0.0.3', '10.0.0.4'], context.addresses_by_states([AddressStates.RUNNING, AddressStates.ISOLATED])) self.assertItemsEqual(['10.0.0.1'], context.addresses_by_states([AddressStates.SILENT])) self.assertItemsEqual(['10.0.0.5'], context.addresses_by_states([AddressStates.UNKNOWN]))
def test_conflicts(self): """ Test the detection of conflicting processes. """ from supvisors.context import Context context = Context(self.supvisors) # add processes to context self.random_fill_processes(context) # test no conflict self.assertFalse(context.conflicting()) self.assertListEqual([], context.conflicts()) # add addresses to one process process1 = next(process for process in context.processes.values() if process.running()) process1.addresses.update(context.addresses.keys()) # test conflict is detected self.assertTrue(context.conflicting()) self.assertListEqual([process1], context.conflicts()) # add addresses to one other process process2 = next(process for process in context.processes.values() if process.stopped()) process2.addresses.update(context.addresses.keys()) # test conflict is detected self.assertTrue(context.conflicting()) self.assertItemsEqual([process1, process2], context.conflicts()) # empty addresses of first process list process1.addresses.clear() # test conflict is still detected self.assertTrue(context.conflicting()) self.assertListEqual([process2], context.conflicts()) # empty addresses of second process list process2.addresses.clear() # test no conflict self.assertFalse(context.conflicting()) self.assertListEqual([], context.conflicts())