Ejemplo n.º 1
0
 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)
Ejemplo n.º 2
0
 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)
Ejemplo n.º 3
0
 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)
Ejemplo n.º 4
0
 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)
Ejemplo n.º 5
0
 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)
Ejemplo n.º 6
0
 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)
Ejemplo n.º 7
0
 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)
Ejemplo n.º 8
0
 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)
Ejemplo n.º 9
0
 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)
Ejemplo n.º 10
0
 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)
Ejemplo n.º 11
0
 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)
Ejemplo n.º 12
0
 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)
Ejemplo n.º 13
0
 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)
Ejemplo n.º 14
0
 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)
Ejemplo n.º 15
0
 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)
Ejemplo n.º 16
0
 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)
Ejemplo n.º 17
0
    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)
Ejemplo n.º 18
0
 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)
Ejemplo n.º 19
0
 def test_TODO(self):
     """ Test the values set at construction. """
     from supvisors.context import Context
     context = Context(self.supvisors)
     self.assertIsNotNone(context)
Ejemplo n.º 20
0
 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]))
Ejemplo n.º 21
0
 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)
Ejemplo n.º 22
0
 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)
Ejemplo n.º 23
0
 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)
Ejemplo n.º 24
0
 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)
Ejemplo n.º 25
0
 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)
Ejemplo n.º 26
0
 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]))
Ejemplo n.º 27
0
 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())
Ejemplo n.º 28
0
 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())