def test_syslog_logfile_deprecated(self): import warnings options = DummyOptions() config = DummyPConfig(options, 'process1', '/bin/process1') config.stdout_logfile = 'syslog' process = DummyProcess(config) with warnings.catch_warnings(record=True) as w: warnings.simplefilter('always') self._makeOne(process) self.assertEqual(len(w), 1)
def test_handle_request_stdout_logfile_none(self): options = DummyOptions() pconfig = DummyPConfig(options, 'process1', '/bin/process1', priority=1, stdout_logfile='/tmp/process1.log') supervisord = PopulatedDummySupervisor(options, 'process1', pconfig) handler = self._makeOne(supervisord) request = DummyRequest('/logtail/process1', None, None, None) handler.handle_request(request) self.assertEqual(request._error, 410)
def _test_one_ProcessStateEvent(self, klass): from supervisor.states import ProcessStates from supervisor.events import ProcessStateEvent self.assertTrue(issubclass(klass, ProcessStateEvent)) options = DummyOptions() pconfig1 = DummyPConfig(options, 'process1', 'process1', '/bin/process1') process = DummyProcess(pconfig1) inst = klass(process, ProcessStates.STARTING) self.assertEqual(inst.process, process) self.assertEqual(inst.from_state, ProcessStates.STARTING) self.assertEqual(inst.expected, True)
def test_handle_listener_state_change_from_unknown(self): options = DummyOptions() config = DummyPConfig(options, 'process1', '/bin/process1') process = DummyProcess(config) from supervisor.dispatchers import EventListenerStates dispatcher = self._makeOne(process) process.listener_state = EventListenerStates.UNKNOWN dispatcher.state_buffer = 'whatever' self.assertEqual(dispatcher.handle_listener_state_change(), None) self.assertEqual(dispatcher.state_buffer, '') self.assertEqual(options.logger.data, []) self.assertEqual(process.listener_state, EventListenerStates.UNKNOWN)
def test_handle_sigusr2(self): options = DummyOptions() options._signal = signal.SIGUSR2 pconfig1 = DummyPConfig(options, 'process1', 'process1', '/bin/process1') from supervisor.process import ProcessStates process1 = DummyProcess(pconfig1, state=ProcessStates.STOPPING) process1.delay = time.time() - 1 supervisord = self._makeOne(options) pconfigs = [DummyPConfig(options, 'foo', 'foo', '/bin/foo')] options.process_group_configs = DummyPGroupConfig(options, 'foo', pconfigs=pconfigs) dummypgroup = DummyProcessGroup(options) supervisord.process_groups = {None: dummypgroup} supervisord.handle_signal() self.assertEqual(supervisord.options.mood, 1) self.assertEqual(options.logs_reopened, True) self.assertEqual(options.logger.data[0], 'received SIGUSR2 indicating log reopen request') self.assertEqual(dummypgroup.logs_reopened, True)
def test_handle_listener_state_change_ready_to_unknown(self): options = DummyOptions() config = DummyPConfig(options, 'process1', '/bin/process1') process = DummyProcess(config) from supervisor.dispatchers import EventListenerStates dispatcher = self._makeOne(process) process.listener_state = EventListenerStates.READY dispatcher.state_buffer = 'bogus data yo' self.assertEqual(dispatcher.handle_listener_state_change(), None) self.assertEqual(dispatcher.state_buffer, '') self.assertEqual(options.logger.data[0], 'process1: READY -> UNKNOWN') self.assertEqual(process.listener_state, EventListenerStates.UNKNOWN)
def test_ctor_logfile_only(self): options = DummyOptions() config = DummyPConfig(options, 'process1', '/bin/process1', stdout_logfile='/tmp/foo') process = DummyProcess(config) dispatcher = self._makeOne(process) self.assertEqual(dispatcher.process, process) self.assertEqual(dispatcher.channel, 'stdout') self.assertEqual(dispatcher.fd, 0) self.assertEqual(dispatcher.capturelog, None) self.assertEqual(dispatcher.mainlog.__class__, DummyLogger) self.assertEqual(dispatcher.childlog, dispatcher.mainlog)
def test_removeProcessFromGroup_raises_bad_name_when_group_doesnt_exist( self): pconfig = DummyPConfig(None, 'foo', '/bin/foo') gconfig = DummyPGroupConfig(None, pconfigs=[pconfig]) pgroup = DummyProcessGroup(gconfig) supervisord = DummySupervisor(process_groups={'group_name': pgroup}) interface = self.makeOne(supervisord) self.assertRPCError(SupervisorFaults.BAD_NAME, interface.removeProcessFromGroup, 'nonexistant_group_name', 'process_name')
def test_handle_error(self): options = DummyOptions() config = DummyPConfig(options, 'test', '/test') process = DummyProcess(config) dispatcher = self._makeOne(process) try: raise ValueError('foo') except: dispatcher.handle_error() result = options.logger.data[0] self.assertTrue(result.startswith( 'uncaptured python exception, closing channel'), result)
def test_removeProcessFromGroup_deletes_the_process(self): pconfig = DummyPConfig(None, "foo", "/bin/foo") process = DummyProcess(pconfig, ProcessStates.STOPPED) gconfig = DummyPGroupConfig(None, pconfigs=[pconfig]) pgroup = DummyProcessGroup(gconfig) pgroup.processes = {"process_name": process} supervisord = DummySupervisor(process_groups={"group_name": pgroup}) interface = self.makeOne(supervisord) result = interface.removeProcessFromGroup("group_name", "process_name") self.assertTrue(result) self.assertTrue(pgroup.processes.get("process_name") is None) self.assertEqual("removeProcessFromGroup", interface.update_text)
def test_handle_write_event_epipe_raised(self): options = DummyOptions() config = DummyPConfig(options, 'test', '/test') process = DummyProcess(config) dispatcher = self._makeOne(process) dispatcher.input_buffer = 'halloooo' import errno options.write_error = errno.EPIPE dispatcher.handle_write_event() self.assertEqual(dispatcher.input_buffer, '') self.assertTrue(options.logger.data[0].startswith( 'fd 0 closed, stopped monitoring')) self.assertTrue(options.logger.data[0].endswith('(stdin)>'))
def test_runforever_select_dispatcher_handle_error_via_write(self): options = DummyOptions() options.poller.result = [], [6] supervisord = self._makeOne(options) pconfig = DummyPConfig(options, 'foo', '/bin/foo',) gconfig = DummyPGroupConfig(options, pconfigs=[pconfig]) pgroup = DummyProcessGroup(gconfig) notimpl = DummyDispatcher(readable=True, error=NotImplementedError) pgroup.dispatchers = {6:notimpl} supervisord.process_groups = {'foo': pgroup} options.test = True supervisord.runforever() self.assertEqual(notimpl.error_handled, True)
def test_handle_listener_state_change_acknowledged_to_insufficient(self): options = DummyOptions() config = DummyPConfig(options, 'process1', '/bin/process1') process = DummyProcess(config) from supervisor.dispatchers import EventListenerStates dispatcher = self._makeOne(process) process.listener_state = EventListenerStates.ACKNOWLEDGED dispatcher.state_buffer = 'RE' self.assertEqual(dispatcher.handle_listener_state_change(), None) self.assertEqual(dispatcher.state_buffer, 'RE') self.assertEqual(options.logger.data, []) self.assertEqual(process.listener_state, EventListenerStates.ACKNOWLEDGED)
def test_handle_read_event_logging_childlog(self): options = DummyOptions() options.readfd_result = 'supercalifragilisticexpialidocious' config = DummyPConfig(options, 'process1', '/bin/process1', stdout_logfile='/tmp/foo') process = DummyProcess(config) dispatcher = self._makeOne(process) self.assertEqual(dispatcher.handle_read_event(), None) self.assertEqual(len(dispatcher.childlog.data), 1) self.assertEqual(dispatcher.childlog.data[0], 'supercalifragilisticexpialidocious')
def test_handle_read_event_no_data_closes(self): options = DummyOptions() options.readfd_result = '' config = DummyPConfig(options, 'process1', '/bin/process1', stdout_capture_maxbytes=100) process = DummyProcess(config) dispatcher = self._makeOne(process) self.assertFalse(dispatcher.closed) self.assertEqual(dispatcher.handle_read_event(), None) self.assertEqual(dispatcher.output_buffer, '') self.assertTrue(dispatcher.closed)
def test_removelogs(self): options = DummyOptions() config = DummyPConfig(options, 'process1', '/bin/process1', stdout_logfile='/tmp/foo') process = DummyProcess(config) dispatcher = self._makeOne(process) dispatcher.removelogs() self.assertEqual(dispatcher.mainlog.handlers[0].reopened, True) self.assertEqual(dispatcher.mainlog.handlers[0].removed, True) self.assertEqual(dispatcher.childlog.handlers[0].reopened, True) self.assertEqual(dispatcher.childlog.handlers[0].removed, True)
def test_runforever_select_dispatcher_exitnow_via_write(self): options = DummyOptions() options.poller.result = [], [6] supervisord = self._makeOne(options) pconfig = DummyPConfig(options, 'foo', '/bin/foo',) gconfig = DummyPGroupConfig(options, pconfigs=[pconfig]) pgroup = DummyProcessGroup(gconfig) from supervisor.medusa import asyncore_25 as asyncore exitnow = DummyDispatcher(readable=True, error=asyncore.ExitNow) pgroup.dispatchers = {6:exitnow} supervisord.process_groups = {'foo': pgroup} options.test = True self.assertRaises(asyncore.ExitNow, supervisord.runforever)
def test_diff_to_active_finds_groups_added(self): options = DummyOptions() supervisord = self._makeOne(options) pconfig = DummyPConfig(options, 'process1', '/bin/foo', '/tmp') group1 = DummyPGroupConfig(options, 'group1', pconfigs=[pconfig]) # the active configuration has no groups # diffing should find that group1 has been added supervisord.options.process_group_configs = [group1] added, changed, removed = supervisord.diff_to_active() self.assertEqual(added, [group1]) self.assertEqual(changed, []) self.assertEqual(removed, [])
def test_write_encodes_unicode_as_utf8(self): options = DummyOptions() config = DummyPConfig(options, 'cat', 'bin/cat') process = DummyProcess(config) process.pid = 42 process.killing = False event = DummyEvent() event.process = process response = _u(_b('STDIN:foobar')) supervisor_twiddler.resulthandler.stdin_write_handler(event, response) self.assertEqual(process.stdin_buffer, 'foobar')
def test_handle_listener_state_change_acknowledged_gobbles(self): options = DummyOptions() config = DummyPConfig(options, 'process1', '/bin/process1') process = DummyProcess(config) from supervisor.dispatchers import EventListenerStates dispatcher = self._makeOne(process) process.listener_state = EventListenerStates.ACKNOWLEDGED dispatcher.state_buffer = 'READY\ngarbage\n' self.assertEqual(dispatcher.handle_listener_state_change(), None) self.assertEqual(dispatcher.state_buffer, '') self.assertEqual(options.logger.data[0], 'process1: ACKNOWLEDGED -> READY') self.assertEqual(options.logger.data[1], 'process1: READY -> UNKNOWN') self.assertEqual(process.listener_state, EventListenerStates.UNKNOWN)
def test_write_fails_silently_if_process_is_killing(self): options = DummyOptions() config = DummyPConfig(options, 'cat', 'bin/cat') process = DummyProcess(config) process.pid = 42 process.killing = True event = DummyEvent() event.process = process response = 'STDIN:foobar' supervisor_twiddler.resulthandler.stdin_write_handler(event, response) self.assertEqual(process.stdin_buffer, '')
def test_handler_writes_chars_when_response_is_STDIN(self): options = DummyOptions() config = DummyPConfig(options, 'cat', 'bin/cat') process = DummyProcess(config) process.pid = 42 process.killing = False event = DummyEvent() event.process = process response = 'STDIN:foobar' supervisor_twiddler.resulthandler.stdin_write_handler(event, response) self.assertEqual(process.stdin_buffer, 'foobar')
def test_getGroupNames_returns_group_names(self): pconfig = DummyPConfig(None, 'foo', '/bin/foo') gconfig = DummyPGroupConfig(None, pconfigs=[pconfig]) pgroup = DummyProcessGroup(gconfig) pgroups = {'foo': pgroup, 'bar': pgroup} supervisord = DummySupervisor(process_groups=pgroups) interface = self.makeOne(supervisord) names = interface.getGroupNames() self.assertTrue(isinstance(names, list)) self.assertEqual(2, len(names)) names.index('foo') names.index('bar')
def test_addProgramToGroup_raises_bad_name_when_process_already_exists( self): pconfig = DummyPConfig(None, 'process_that_exists', '/bin/foo') gconfig = DummyPGroupConfig(None, pconfigs=[pconfig]) pgroup = DummyProcessGroup(gconfig) supervisord = DummySupervisor(process_groups={'group_name': pgroup}) supervisord.options = supervisor.options.ServerOptions() interface = self.makeOne(supervisord) poptions = {'command': '/usr/bin/find /'} self.assertRPCError(SupervisorFaults.BAD_NAME, interface.addProgramToGroup, 'group_name', 'process_that_exists', poptions)
def test_addProgramToGroup_raises_incorrect_params_when_poptions_is_not_dict( self): pconfig = DummyPConfig(None, 'foo', '/bin/foo') gconfig = DummyPGroupConfig(None, pconfigs=[pconfig]) pgroup = DummyProcessGroup(gconfig) supervisord = DummySupervisor(process_groups={'group_name': pgroup}) supervisord.options = supervisor.options.ServerOptions() interface = self.makeOne(supervisord) bad_poptions = 42 self.assertRPCError(SupervisorFaults.INCORRECT_PARAMETERS, interface.addProgramToGroup, 'group_name', 'new_process', bad_poptions)
def test_removeProcessFromGroup_transitions_process_group(self): pconfig = DummyPConfig(None, 'foo', '/bin/foo') process = DummyProcess(pconfig, ProcessStates.EXITED) gconfig = DummyPGroupConfig(None, pconfigs=[pconfig]) pgroup = DummyProcessGroup(gconfig) pgroup.processes = {'process_name': process} supervisord = DummySupervisor(process_groups={'group_name': pgroup}) interface = self.makeOne(supervisord) result = interface.removeProcessFromGroup('group_name', 'process_name') self.assertTrue(result) self.assertTrue(pgroup.transitioned)
def test_pcomm_stderr_event(self): options = DummyOptions() pconfig1 = DummyPConfig(options, 'process1', 'process1','/bin/process1') process1 = DummyProcess(pconfig1) class DummyGroup: config = pconfig1 process1.group = DummyGroup from supervisor.events import ProcessCommunicationStderrEvent event = ProcessCommunicationStderrEvent(process1, 1, 'yo') headers, payload = self._deserialize(str(event)) self.assertEqual(headers['processname'], 'process1', headers) self.assertEqual(headers['groupname'], 'process1', headers) self.assertEqual(headers['pid'], '1', headers) self.assertEqual(payload, 'yo')
def test_record_output_capturemode_string_not_longer_than_token(self): # stdout/stderr goes to the process log and the main log, # in capturemode, the length of the data needs to be longer # than the capture token to make it out. options = DummyOptions() config = DummyPConfig(options, 'process1', '/bin/process1', stdout_logfile='/tmp/foo', stdout_capture_maxbytes=100) process = DummyProcess(config) dispatcher = self._makeOne(process) dispatcher.output_buffer = 'a' dispatcher.record_output() self.assertEqual(dispatcher.childlog.data, []) self.assertEqual(dispatcher.output_buffer, 'a')
def test_reap_more_than_once(self): options = DummyOptions() options.waitpid_return = 1, 1 pconfig = DummyPConfig(options, 'process', 'process', '/bin/process1') process = DummyProcess(pconfig) process.drained = False process.killing = True process.laststop = None process.waitstatus = None, None options.pidhistory = {1: process} supervisord = self._makeOne(options) supervisord.reap(recursionguard=99) self.assertEqual(process.finished, (1, 1))
def test_exit(self): options = DummyOptions() supervisord = self._makeOne(options) pconfig = DummyPConfig(options, 'foo', '/bin/foo',) gconfig = DummyPGroupConfig(options, pconfigs=[pconfig]) pgroup = DummyProcessGroup(gconfig) L = [] def callback(): L.append(1) supervisord.process_groups = {'foo': pgroup} supervisord.options.mood = SupervisorStates.RESTARTING supervisord.options.test = True from supervisor.medusa import asyncore_25 as asyncore self.assertRaises(asyncore.ExitNow, supervisord.runforever) self.assertEqual(pgroup.all_stopped, True)
def test_reap_unknown_pid(self): options = DummyOptions() options.waitpid_return = 2, 0 # pid, status pconfig = DummyPConfig(options, 'process', 'process', '/bin/process1') process = DummyProcess(pconfig) process.drained = False process.killing = True process.laststop = None process.waitstatus = None, None options.pidhistory = {1: process} supervisord = self._makeOne(options) supervisord.reap(once=True) self.assertEqual(process.finished, None) self.assertEqual(options.logger.data[0], 'reaped unknown pid 2')