class test_MultiTool(AppCase): def setup(self): self.fh = WhateverIO() self.env = {} self.t = MultiTool(env=self.env, fh=self.fh) def test_note(self): self.t.note('hello world') self.assertEqual(self.fh.getvalue(), 'hello world\n') def test_note_quiet(self): self.t.quiet = True self.t.note('hello world') self.assertFalse(self.fh.getvalue()) def test_info(self): self.t.verbose = True self.t.info('hello info') self.assertEqual(self.fh.getvalue(), 'hello info\n') def test_info_not_verbose(self): self.t.verbose = False self.t.info('hello info') self.assertFalse(self.fh.getvalue()) def test_error(self): self.t.carp = Mock() self.t.usage = Mock() self.assertEqual(self.t.error('foo'), 1) self.t.carp.assert_called_with('foo') self.t.usage.assert_called_with() self.t.carp = Mock() self.assertEqual(self.t.error(), 1) self.assertFalse(self.t.carp.called) self.assertEqual(self.t.retcode, 1) @patch('celery.bin.multi.Popen') def test_waitexec(self, Popen): self.t.note = Mock() pipe = Popen.return_value = Mock() pipe.wait.return_value = -10 self.assertEqual(self.t.waitexec(['-m', 'foo'], 'path'), 10) Popen.assert_called_with(['path', '-m', 'foo'], env=self.t.env) self.t.note.assert_called_with('* Child was terminated by signal 10') pipe.wait.return_value = 2 self.assertEqual(self.t.waitexec(['-m', 'foo'], 'path'), 2) self.t.note.assert_called_with( '* Child terminated with errorcode 2', ) pipe.wait.return_value = 0 self.assertFalse(self.t.waitexec(['-m', 'foo', 'path'])) def test_nosplash(self): self.t.nosplash = True self.t.splash() self.assertFalse(self.fh.getvalue()) def test_splash(self): self.t.nosplash = False self.t.splash() self.assertIn('celery multi', self.fh.getvalue()) def test_usage(self): self.t.usage() self.assertTrue(self.fh.getvalue()) def test_help(self): self.t.help([]) self.assertIn(doc, self.fh.getvalue()) def test_expand(self): self.t.expand(['foo%n', 'ask', 'klask', 'dask']) self.assertEqual( self.fh.getvalue(), 'fooask\nfooklask\nfoodask\n', ) def test_restart(self): stop = self.t._stop_nodes = Mock() self.t.restart(['jerry', 'george'], 'celery worker') waitexec = self.t.waitexec = Mock() self.assertTrue(stop.called) callback = stop.call_args[1]['callback'] self.assertTrue(callback) waitexec.return_value = 0 callback('jerry', ['arg'], 13) waitexec.assert_called_with(['arg']) self.assertIn('OK', self.fh.getvalue()) self.fh.seek(0) self.fh.truncate() waitexec.return_value = 1 callback('jerry', ['arg'], 13) self.assertIn('FAILED', self.fh.getvalue()) def test_stop(self): self.t.getpids = Mock() self.t.getpids.return_value = [2, 3, 4] self.t.shutdown_nodes = Mock() self.t.stop(['a', 'b', '-INT'], 'celery worker') self.t.shutdown_nodes.assert_called_with( [2, 3, 4], sig=signal.SIGINT, retry=None, callback=None, ) def test_kill(self): if not hasattr(signal, 'SIGKILL'): raise SkipTest('SIGKILL not supported by this platform') self.t.getpids = Mock() self.t.getpids.return_value = [ ('a', None, 10), ('b', None, 11), ('c', None, 12) ] sig = self.t.signal_node = Mock() self.t.kill(['a', 'b', 'c'], 'celery worker') sigs = sig.call_args_list self.assertEqual(len(sigs), 3) self.assertEqual(sigs[0][0], ('a', 10, signal.SIGKILL)) self.assertEqual(sigs[1][0], ('b', 11, signal.SIGKILL)) self.assertEqual(sigs[2][0], ('c', 12, signal.SIGKILL)) def prepare_pidfile_for_getpids(self, Pidfile): class pids(object): def __init__(self, path): self.path = path def read_pid(self): try: return {'foo.pid': 10, 'bar.pid': 11}[self.path] except KeyError: raise ValueError() Pidfile.side_effect = pids @patch('celery.bin.multi.Pidfile') @patch('socket.gethostname') def test_getpids(self, gethostname, Pidfile): gethostname.return_value = 'e.com' self.prepare_pidfile_for_getpids(Pidfile) callback = Mock() p = NamespacedOptionParser(['foo', 'bar', 'baz']) nodes = self.t.getpids(p, 'celery worker', callback=callback) node_0, node_1 = nodes self.assertEqual(node_0[0], '*****@*****.**') self.assertEqual( sorted(node_0[1]), sorted(('celery worker', '--pidfile=foo.pid', '-n [email protected]', '')), ) self.assertEqual(node_0[2], 10) self.assertEqual(node_1[0], '*****@*****.**') self.assertEqual( sorted(node_1[1]), sorted(('celery worker', '--pidfile=bar.pid', '-n [email protected]', '')), ) self.assertEqual(node_1[2], 11) self.assertTrue(callback.called) cargs, _ = callback.call_args self.assertEqual(cargs[0], '*****@*****.**') self.assertItemsEqual( cargs[1], ['celery worker', '--pidfile=baz.pid', '-n [email protected]', ''], ) self.assertIsNone(cargs[2]) self.assertIn('DOWN', self.fh.getvalue()) # without callback, should work nodes = self.t.getpids(p, 'celery worker', callback=None) @patch('celery.bin.multi.Pidfile') @patch('socket.gethostname') @patch('celery.bin.multi.sleep') def test_shutdown_nodes(self, slepp, gethostname, Pidfile): gethostname.return_value = 'e.com' self.prepare_pidfile_for_getpids(Pidfile) self.assertIsNone(self.t.shutdown_nodes([])) self.t.signal_node = Mock() node_alive = self.t.node_alive = Mock() self.t.node_alive.return_value = False callback = Mock() self.t.stop(['foo', 'bar', 'baz'], 'celery worker', callback=callback) sigs = sorted(self.t.signal_node.call_args_list) self.assertEqual(len(sigs), 2) self.assertIn( ('*****@*****.**', 10, signal.SIGTERM), [tup[0] for tup in sigs], ) self.assertIn( ('*****@*****.**', 11, signal.SIGTERM), [tup[0] for tup in sigs], ) self.t.signal_node.return_value = False self.assertTrue(callback.called) self.t.stop(['foo', 'bar', 'baz'], 'celery worker', callback=None) def on_node_alive(pid): if node_alive.call_count > 4: return True return False self.t.signal_node.return_value = True self.t.node_alive.side_effect = on_node_alive self.t.stop(['foo', 'bar', 'baz'], 'celery worker', retry=True) @patch('os.kill') def test_node_alive(self, kill): kill.return_value = True self.assertTrue(self.t.node_alive(13)) esrch = OSError() esrch.errno = errno.ESRCH kill.side_effect = esrch self.assertFalse(self.t.node_alive(13)) kill.assert_called_with(13, 0) enoent = OSError() enoent.errno = errno.ENOENT kill.side_effect = enoent with self.assertRaises(OSError): self.t.node_alive(13) @patch('os.kill') def test_signal_node(self, kill): kill.return_value = True self.assertTrue(self.t.signal_node('foo', 13, 9)) esrch = OSError() esrch.errno = errno.ESRCH kill.side_effect = esrch self.assertFalse(self.t.signal_node('foo', 13, 9)) kill.assert_called_with(13, 9) self.assertIn('Could not signal foo', self.fh.getvalue()) enoent = OSError() enoent.errno = errno.ENOENT kill.side_effect = enoent with self.assertRaises(OSError): self.t.signal_node('foo', 13, 9) def test_start(self): self.t.waitexec = Mock() self.t.waitexec.return_value = 0 self.assertFalse(self.t.start(['foo', 'bar', 'baz'], 'celery worker')) self.t.waitexec.return_value = 1 self.assertFalse(self.t.start(['foo', 'bar', 'baz'], 'celery worker')) def test_show(self): self.t.show(['foo', 'bar', 'baz'], 'celery worker') self.assertTrue(self.fh.getvalue()) @patch('socket.gethostname') def test_get(self, gethostname): gethostname.return_value = 'e.com' self.t.get(['*****@*****.**', 'foo', 'bar', 'baz'], 'celery worker') self.assertFalse(self.fh.getvalue()) self.t.get(['*****@*****.**', 'foo', 'bar', 'baz'], 'celery worker') self.assertTrue(self.fh.getvalue()) @patch('socket.gethostname') def test_names(self, gethostname): gethostname.return_value = 'e.com' self.t.names(['foo', 'bar', 'baz'], 'celery worker') self.assertIn('[email protected]\[email protected]\[email protected]', self.fh.getvalue()) def test_execute_from_commandline(self): start = self.t.commands['start'] = Mock() self.t.error = Mock() self.t.execute_from_commandline(['multi', 'start', 'foo', 'bar']) self.assertFalse(self.t.error.called) start.assert_called_with(['foo', 'bar'], 'celery worker') self.t.error = Mock() self.t.execute_from_commandline(['multi', 'frob', 'foo', 'bar']) self.t.error.assert_called_with('Invalid command: frob') self.t.error = Mock() self.t.execute_from_commandline(['multi']) self.t.error.assert_called_with() self.t.error = Mock() self.t.execute_from_commandline(['multi', '-foo']) self.t.error.assert_called_with() self.t.execute_from_commandline( ['multi', 'start', 'foo', '--nosplash', '--quiet', '-q', '--verbose', '--no-color'], ) self.assertTrue(self.t.nosplash) self.assertTrue(self.t.quiet) self.assertTrue(self.t.verbose) self.assertTrue(self.t.no_color) def test_stopwait(self): self.t._stop_nodes = Mock() self.t.stopwait(['foo', 'bar', 'baz'], 'celery worker') self.assertEqual(self.t._stop_nodes.call_args[1]['retry'], 2) @patch('celery.bin.multi.MultiTool') def test_main(self, MultiTool): m = MultiTool.return_value = Mock() with self.assertRaises(SystemExit): main() m.execute_from_commandline.assert_called_with(sys.argv)
class test_MultiTool(AppCase): def setup(self): self.fh = WhateverIO() self.env = {} self.t = MultiTool(env=self.env, fh=self.fh) self.t.Cluster = Mock(name='Cluster') self.t.carp = Mock(name='.carp') self.t.usage = Mock(name='.usage') self.t.splash = Mock(name='.splash') self.t.say = Mock(name='.say') self.t.ok = Mock(name='.ok') self.cluster = self.t.Cluster.return_value def test_execute_from_commandline(self): self.t.call_command = Mock(name='call_command') self.t.execute_from_commandline( 'multi start --verbose 10 --foo'.split(), cmd='X', ) self.assertEqual(self.t.cmd, 'X') self.assertEqual(self.t.prog_name, 'multi') self.t.call_command.assert_called_with('start', ['10', '--foo']) def test_execute_from_commandline__arguments(self): self.assertTrue(self.t.execute_from_commandline('multi'.split())) self.assertTrue(self.t.execute_from_commandline('multi -bar'.split())) def test_call_command(self): cmd = self.t.commands['foo'] = Mock(name='foo') self.t.retcode = 303 self.assertIs( self.t.call_command('foo', ['1', '2', '--foo=3']), cmd.return_value, ) cmd.assert_called_with('1', '2', '--foo=3') def test_call_command__error(self): self.assertEqual( self.t.call_command('asdqwewqe', ['1', '2']), 1, ) self.t.carp.assert_called() def test_handle_reserved_options(self): self.assertListEqual( self.t._handle_reserved_options( ['a', '-q', 'b', '--no-color', 'c']), ['a', 'b', 'c'], ) def test_start(self): self.cluster.start.return_value = [0, 0, 1, 0] self.assertTrue(self.t.start('10', '-A', 'proj')) self.t.splash.assert_called_with() self.t.Cluster.assert_called_with(('10', '-A', 'proj')) self.cluster.start.assert_called_with() def test_start__exitcodes(self): self.cluster.start.return_value = [0, 0, 0] self.assertFalse(self.t.start('foo', 'bar', 'baz')) self.cluster.start.assert_called_with() self.cluster.start.return_value = [0, 1, 0] self.assertTrue(self.t.start('foo', 'bar', 'baz')) def test_stop(self): self.t.stop('10', '-A', 'proj', retry=3) self.t.splash.assert_called_with() self.t.Cluster.assert_called_with(('10', '-A', 'proj')) self.cluster.stop.assert_called_with(retry=3) def test_stopwait(self): self.t.stopwait('10', '-A', 'proj', retry=3) self.t.splash.assert_called_with() self.t.Cluster.assert_called_with(('10', '-A', 'proj')) self.cluster.stopwait.assert_called_with(retry=3) def test_restart(self): self.cluster.restart.return_value = [0, 0, 1, 0] self.t.restart('10', '-A', 'proj') self.t.splash.assert_called_with() self.t.Cluster.assert_called_with(('10', '-A', 'proj')) self.cluster.restart.assert_called_with() def test_names(self): self.t.Cluster.return_value = [Mock(), Mock()] self.t.Cluster.return_value[0].name = 'x' self.t.Cluster.return_value[1].name = 'y' self.t.names('10', '-A', 'proj') self.t.say.assert_called() def test_get(self): node = self.cluster.find.return_value = Mock(name='node') node.argv = ['A', 'B', 'C'] self.assertIs( self.t.get('wanted', '10', '-A', 'proj'), self.t.ok.return_value, ) self.cluster.find.assert_called_with('wanted') self.t.Cluster.assert_called_with(('10', '-A', 'proj')) self.t.ok.assert_called_with(' '.join(node.argv)) def test_get__KeyError(self): self.cluster.find.side_effect = KeyError() self.assertTrue(self.t.get('wanted', '10', '-A', 'proj')) def test_show(self): nodes = self.t.Cluster.return_value = [ Mock(name='n1'), Mock(name='n2'), ] nodes[0].argv_with_executable = ['python', 'foo', 'bar'] nodes[1].argv_with_executable = ['python', 'xuzzy', 'baz'] self.assertIs( self.t.show('10', '-A', 'proj'), self.t.ok.return_value, ) self.t.ok.assert_called_with('\n'.join( ' '.join(node.argv_with_executable) for node in nodes)) def test_kill(self): self.t.kill('10', '-A', 'proj') self.t.splash.assert_called_with() self.t.Cluster.assert_called_with(('10', '-A', 'proj')) self.cluster.kill.assert_called_with() def test_expand(self): node1 = Mock(name='n1') node2 = Mock(name='n2') node1.expander.return_value = 'A' node2.expander.return_value = 'B' nodes = self.t.Cluster.return_value = [node1, node2] self.assertIs(self.t.expand('%p', '10'), self.t.ok.return_value) self.t.Cluster.assert_called_with(('10', )) for node in nodes: node.expander.assert_called_with('%p') self.t.ok.assert_called_with('A\nB') def test_note(self): self.t.quiet = True self.t.note('foo') self.t.say.assert_not_called() self.t.quiet = False self.t.note('foo') self.t.say.assert_called_with('foo', newline=True) def test_splash(self): x = MultiTool() x.note = Mock() x.nosplash = True x.splash() x.note.assert_not_called() x.nosplash = False x.splash() x.note.assert_called() def test_Cluster(self): m = MultiTool() c = m.Cluster(['A', 'B', 'C']) self.assertListEqual(c.argv, ['A', 'B', 'C']) self.assertIs(c.env, m.env) self.assertEqual(c.cmd, 'celery worker') self.assertEqual(c.on_stopping_preamble, m.on_stopping_preamble) self.assertEqual(c.on_send_signal, m.on_send_signal) self.assertEqual(c.on_still_waiting_for, m.on_still_waiting_for) self.assertEqual( c.on_still_waiting_progress, m.on_still_waiting_progress, ) self.assertEqual(c.on_still_waiting_end, m.on_still_waiting_end) self.assertEqual(c.on_node_start, m.on_node_start) self.assertEqual(c.on_node_restart, m.on_node_restart) self.assertEqual(c.on_node_shutdown_ok, m.on_node_shutdown_ok) self.assertEqual(c.on_node_status, m.on_node_status) self.assertEqual(c.on_node_signal_dead, m.on_node_signal_dead) self.assertEqual(c.on_node_signal, m.on_node_signal) self.assertEqual(c.on_node_down, m.on_node_down) self.assertEqual(c.on_child_spawn, m.on_child_spawn) self.assertEqual(c.on_child_signalled, m.on_child_signalled) self.assertEqual(c.on_child_failure, m.on_child_failure) def test_on_stopping_preamble(self): self.t.on_stopping_preamble([]) def test_on_send_signal(self): self.t.on_send_signal(Mock(), Mock()) def test_on_still_waiting_for(self): self.t.on_still_waiting_for([Mock(), Mock()]) def test_on_still_waiting_for__empty(self): self.t.on_still_waiting_for([]) def test_on_still_waiting_progress(self): self.t.on_still_waiting_progress([]) def test_on_still_waiting_end(self): self.t.on_still_waiting_end() def test_on_node_signal_dead(self): self.t.on_node_signal_dead(Mock()) def test_on_node_start(self): self.t.on_node_start(Mock()) def test_on_node_restart(self): self.t.on_node_restart(Mock()) def test_on_node_down(self): self.t.on_node_down(Mock()) def test_on_node_shutdown_ok(self): self.t.on_node_shutdown_ok(Mock()) def test_on_node_status__FAIL(self): self.t.on_node_status(Mock(), 1) self.t.say.assert_called_with(self.t.FAILED, newline=True) def test_on_node_status__OK(self): self.t.on_node_status(Mock(), 0) self.t.say.assert_called_with(self.t.OK, newline=True) def test_on_node_signal(self): self.t.on_node_signal(Mock(), Mock()) def test_on_child_spawn(self): self.t.on_child_spawn(Mock(), Mock(), Mock()) def test_on_child_signalled(self): self.t.on_child_signalled(Mock(), Mock()) def test_on_child_failure(self): self.t.on_child_failure(Mock(), Mock()) def test_constant_strings(self): self.assertTrue(self.t.OK) self.assertTrue(self.t.DOWN) self.assertTrue(self.t.FAILED)
class test_MultiTool(AppCase): def setup(self): self.fh = WhateverIO() self.env = {} self.t = MultiTool(env=self.env, fh=self.fh) self.t.cluster_from_argv = Mock(name='cluster_from_argv') self.t._cluster_from_argv = Mock(name='cluster_from_argv') self.t.Cluster = Mock(name='Cluster') self.t.carp = Mock(name='.carp') self.t.usage = Mock(name='.usage') self.t.splash = Mock(name='.splash') self.t.say = Mock(name='.say') self.t.ok = Mock(name='.ok') self.cluster = self.t.Cluster.return_value def _cluster_from_argv(argv): p = self.t.OptionParser(argv) p.parse() return p, self.cluster self.t.cluster_from_argv.return_value = self.cluster self.t._cluster_from_argv.side_effect = _cluster_from_argv def test_findsig(self): self.assert_sig_argument(['a', 'b', 'c', '-1'], 1) self.assert_sig_argument(['--foo=1', '-9'], 9) self.assert_sig_argument(['-INT'], signal.SIGINT) self.assert_sig_argument([], signal.SIGTERM) self.assert_sig_argument(['-s'], signal.SIGTERM) self.assert_sig_argument(['-log'], signal.SIGTERM) def assert_sig_argument(self, args, expected): p = self.t.OptionParser(args) p.parse() self.assertEqual(self.t._find_sig_argument(p), expected) def test_execute_from_commandline(self): self.t.call_command = Mock(name='call_command') self.t.execute_from_commandline( 'multi start --verbose 10 --foo'.split(), cmd='X', ) self.assertEqual(self.t.cmd, 'X') self.assertEqual(self.t.prog_name, 'multi') self.t.call_command.assert_called_with('start', ['10', '--foo']) def test_execute_from_commandline__arguments(self): self.assertTrue(self.t.execute_from_commandline('multi'.split())) self.assertTrue(self.t.execute_from_commandline('multi -bar'.split())) def test_call_command(self): cmd = self.t.commands['foo'] = Mock(name='foo') self.t.retcode = 303 self.assertIs( self.t.call_command('foo', ['1', '2', '--foo=3']), cmd.return_value, ) cmd.assert_called_with('1', '2', '--foo=3') def test_call_command__error(self): self.assertEqual( self.t.call_command('asdqwewqe', ['1', '2']), 1, ) self.t.carp.assert_called() def test_handle_reserved_options(self): self.assertListEqual( self.t._handle_reserved_options( ['a', '-q', 'b', '--no-color', 'c']), ['a', 'b', 'c'], ) def test_start(self): self.cluster.start.return_value = [0, 0, 1, 0] self.assertTrue(self.t.start('10', '-A', 'proj')) self.t.splash.assert_called_with() self.t.cluster_from_argv.assert_called_with(('10', '-A', 'proj')) self.cluster.start.assert_called_with() def test_start__exitcodes(self): self.cluster.start.return_value = [0, 0, 0] self.assertFalse(self.t.start('foo', 'bar', 'baz')) self.cluster.start.assert_called_with() self.cluster.start.return_value = [0, 1, 0] self.assertTrue(self.t.start('foo', 'bar', 'baz')) def test_stop(self): self.t.stop('10', '-A', 'proj', retry=3) self.t.splash.assert_called_with() self.t._cluster_from_argv.assert_called_with(('10', '-A', 'proj')) self.cluster.stop.assert_called_with(retry=3, sig=signal.SIGTERM) def test_stopwait(self): self.t.stopwait('10', '-A', 'proj', retry=3) self.t.splash.assert_called_with() self.t._cluster_from_argv.assert_called_with(('10', '-A', 'proj')) self.cluster.stopwait.assert_called_with(retry=3, sig=signal.SIGTERM) def test_restart(self): self.cluster.restart.return_value = [0, 0, 1, 0] self.t.restart('10', '-A', 'proj') self.t.splash.assert_called_with() self.t._cluster_from_argv.assert_called_with(('10', '-A', 'proj')) self.cluster.restart.assert_called_with(sig=signal.SIGTERM) def test_names(self): self.t.cluster_from_argv.return_value = [Mock(), Mock()] self.t.cluster_from_argv.return_value[0].name = 'x' self.t.cluster_from_argv.return_value[1].name = 'y' self.t.names('10', '-A', 'proj') self.t.say.assert_called() def test_get(self): node = self.cluster.find.return_value = Mock(name='node') node.argv = ['A', 'B', 'C'] self.assertIs( self.t.get('wanted', '10', '-A', 'proj'), self.t.ok.return_value, ) self.cluster.find.assert_called_with('wanted') self.t.cluster_from_argv.assert_called_with(('10', '-A', 'proj')) self.t.ok.assert_called_with(' '.join(node.argv)) def test_get__KeyError(self): self.cluster.find.side_effect = KeyError() self.assertTrue(self.t.get('wanted', '10', '-A', 'proj')) def test_show(self): nodes = self.t.cluster_from_argv.return_value = [ Mock(name='n1'), Mock(name='n2'), ] nodes[0].argv_with_executable = ['python', 'foo', 'bar'] nodes[1].argv_with_executable = ['python', 'xuzzy', 'baz'] self.assertIs( self.t.show('10', '-A', 'proj'), self.t.ok.return_value, ) self.t.ok.assert_called_with( '\n'.join(' '.join(node.argv_with_executable) for node in nodes)) def test_kill(self): self.t.kill('10', '-A', 'proj') self.t.splash.assert_called_with() self.t.cluster_from_argv.assert_called_with(('10', '-A', 'proj')) self.cluster.kill.assert_called_with() def test_expand(self): node1 = Mock(name='n1') node2 = Mock(name='n2') node1.expander.return_value = 'A' node2.expander.return_value = 'B' nodes = self.t.cluster_from_argv.return_value = [node1, node2] self.assertIs(self.t.expand('%p', '10'), self.t.ok.return_value) self.t.cluster_from_argv.assert_called_with(('10',)) for node in nodes: node.expander.assert_called_with('%p') self.t.ok.assert_called_with('A\nB') def test_note(self): self.t.quiet = True self.t.note('foo') self.t.say.assert_not_called() self.t.quiet = False self.t.note('foo') self.t.say.assert_called_with('foo', newline=True) def test_splash(self): x = MultiTool() x.note = Mock() x.nosplash = True x.splash() x.note.assert_not_called() x.nosplash = False x.splash() x.note.assert_called() def test_Cluster(self): m = MultiTool() c = m.cluster_from_argv(['A', 'B', 'C']) self.assertIs(c.env, m.env) self.assertEqual(c.cmd, 'celery worker') self.assertEqual(c.on_stopping_preamble, m.on_stopping_preamble) self.assertEqual(c.on_send_signal, m.on_send_signal) self.assertEqual(c.on_still_waiting_for, m.on_still_waiting_for) self.assertEqual( c.on_still_waiting_progress, m.on_still_waiting_progress, ) self.assertEqual(c.on_still_waiting_end, m.on_still_waiting_end) self.assertEqual(c.on_node_start, m.on_node_start) self.assertEqual(c.on_node_restart, m.on_node_restart) self.assertEqual(c.on_node_shutdown_ok, m.on_node_shutdown_ok) self.assertEqual(c.on_node_status, m.on_node_status) self.assertEqual(c.on_node_signal_dead, m.on_node_signal_dead) self.assertEqual(c.on_node_signal, m.on_node_signal) self.assertEqual(c.on_node_down, m.on_node_down) self.assertEqual(c.on_child_spawn, m.on_child_spawn) self.assertEqual(c.on_child_signalled, m.on_child_signalled) self.assertEqual(c.on_child_failure, m.on_child_failure) def test_on_stopping_preamble(self): self.t.on_stopping_preamble([]) def test_on_send_signal(self): self.t.on_send_signal(Mock(), Mock()) def test_on_still_waiting_for(self): self.t.on_still_waiting_for([Mock(), Mock()]) def test_on_still_waiting_for__empty(self): self.t.on_still_waiting_for([]) def test_on_still_waiting_progress(self): self.t.on_still_waiting_progress([]) def test_on_still_waiting_end(self): self.t.on_still_waiting_end() def test_on_node_signal_dead(self): self.t.on_node_signal_dead(Mock()) def test_on_node_start(self): self.t.on_node_start(Mock()) def test_on_node_restart(self): self.t.on_node_restart(Mock()) def test_on_node_down(self): self.t.on_node_down(Mock()) def test_on_node_shutdown_ok(self): self.t.on_node_shutdown_ok(Mock()) def test_on_node_status__FAIL(self): self.t.on_node_status(Mock(), 1) self.t.say.assert_called_with(self.t.FAILED, newline=True) def test_on_node_status__OK(self): self.t.on_node_status(Mock(), 0) self.t.say.assert_called_with(self.t.OK, newline=True) def test_on_node_signal(self): self.t.on_node_signal(Mock(), Mock()) def test_on_child_spawn(self): self.t.on_child_spawn(Mock(), Mock(), Mock()) def test_on_child_signalled(self): self.t.on_child_signalled(Mock(), Mock()) def test_on_child_failure(self): self.t.on_child_failure(Mock(), Mock()) def test_constant_strings(self): self.assertTrue(self.t.OK) self.assertTrue(self.t.DOWN) self.assertTrue(self.t.FAILED)
class test_MultiTool(AppCase): def setup(self): self.fh = WhateverIO() self.env = {} self.t = MultiTool(env=self.env, fh=self.fh) def test_note(self): self.t.note('hello world') self.assertEqual(self.fh.getvalue(), 'hello world\n') def test_note_quiet(self): self.t.quiet = True self.t.note('hello world') self.assertFalse(self.fh.getvalue()) def test_carp(self): self.t.say = Mock() self.t.carp('foo') self.t.say.assert_called_with('foo', True, self.t.stderr) def test_info(self): self.t.verbose = True self.t.info('hello info') self.assertEqual(self.fh.getvalue(), 'hello info\n') def test_info_not_verbose(self): self.t.verbose = False self.t.info('hello info') self.assertFalse(self.fh.getvalue()) def test_error(self): self.t.carp = Mock() self.t.usage = Mock() self.assertEqual(self.t.error('foo'), 1) self.t.carp.assert_called_with('foo') self.t.usage.assert_called_with() self.t.carp = Mock() self.assertEqual(self.t.error(), 1) self.assertFalse(self.t.carp.called) self.assertEqual(self.t.retcode, 1) @patch('celery.bin.multi.Popen') def test_waitexec(self, Popen): self.t.note = Mock() pipe = Popen.return_value = Mock() pipe.wait.return_value = -10 self.assertEqual(self.t.waitexec(['-m', 'foo'], 'path'), 10) Popen.assert_called_with(['path', '-m', 'foo'], env=self.t.env) self.t.note.assert_called_with('* Child was terminated by signal 10') pipe.wait.return_value = 2 self.assertEqual(self.t.waitexec(['-m', 'foo'], 'path'), 2) self.t.note.assert_called_with( '* Child terminated with errorcode 2', ) pipe.wait.return_value = 0 self.assertFalse(self.t.waitexec(['-m', 'foo', 'path'])) def test_nosplash(self): self.t.nosplash = True self.t.splash() self.assertFalse(self.fh.getvalue()) def test_splash(self): self.t.nosplash = False self.t.splash() self.assertIn('celery multi', self.fh.getvalue()) def test_usage(self): self.t.usage() self.assertTrue(self.fh.getvalue()) def test_help(self): self.t.help([]) self.assertIn(doc, self.fh.getvalue()) def test_expand(self): self.t.expand(['foo%n', 'ask', 'klask', 'dask']) self.assertEqual( self.fh.getvalue(), 'fooask\nfooklask\nfoodask\n', ) def test_restart(self): stop = self.t._stop_nodes = Mock() self.t.restart(['jerry', 'george'], 'celery worker') waitexec = self.t.waitexec = Mock() self.assertTrue(stop.called) callback = stop.call_args[1]['callback'] self.assertTrue(callback) waitexec.return_value = 0 callback('jerry', ['arg'], 13) waitexec.assert_called_with(['arg'], path=sys.executable) self.assertIn('OK', self.fh.getvalue()) self.fh.seek(0) self.fh.truncate() waitexec.return_value = 1 callback('jerry', ['arg'], 13) self.assertIn('FAILED', self.fh.getvalue()) def test_stop(self): self.t.getpids = Mock() self.t.getpids.return_value = [2, 3, 4] self.t.shutdown_nodes = Mock() self.t.stop(['a', 'b', '-INT'], 'celery worker') self.t.shutdown_nodes.assert_called_with( [2, 3, 4], sig=signal.SIGINT, retry=None, callback=None, ) def test_kill(self): if not hasattr(signal, 'SIGKILL'): raise SkipTest('SIGKILL not supported by this platform') self.t.getpids = Mock() self.t.getpids.return_value = [ ('a', None, 10), ('b', None, 11), ('c', None, 12) ] sig = self.t.signal_node = Mock() self.t.kill(['a', 'b', 'c'], 'celery worker') sigs = sig.call_args_list self.assertEqual(len(sigs), 3) self.assertEqual(sigs[0][0], ('a', 10, signal.SIGKILL)) self.assertEqual(sigs[1][0], ('b', 11, signal.SIGKILL)) self.assertEqual(sigs[2][0], ('c', 12, signal.SIGKILL)) def prepare_pidfile_for_getpids(self, Pidfile): class pids(object): def __init__(self, path): self.path = path def read_pid(self): try: return {'foo.pid': 10, 'bar.pid': 11}[self.path] except KeyError: raise ValueError() Pidfile.side_effect = pids @patch('celery.bin.multi.Pidfile') @patch('socket.gethostname') def test_getpids(self, gethostname, Pidfile): gethostname.return_value = 'e.com' self.prepare_pidfile_for_getpids(Pidfile) callback = Mock() p = NamespacedOptionParser(['foo', 'bar', 'baz']) nodes = self.t.getpids(p, 'celery worker', callback=callback) node_0, node_1 = nodes self.assertEqual(node_0[0], '*****@*****.**') self.assertEqual( sorted(node_0[1]), sorted(('celery worker', '--pidfile=foo.pid', '-n [email protected]', '')), ) self.assertEqual(node_0[2], 10) self.assertEqual(node_1[0], '*****@*****.**') self.assertEqual( sorted(node_1[1]), sorted(('celery worker', '--pidfile=bar.pid', '-n [email protected]', '')), ) self.assertEqual(node_1[2], 11) self.assertTrue(callback.called) cargs, _ = callback.call_args self.assertEqual(cargs[0], '*****@*****.**') self.assertItemsEqual( cargs[1], ['celery worker', '--pidfile=baz.pid', '-n [email protected]', ''], ) self.assertIsNone(cargs[2]) self.assertIn('DOWN', self.fh.getvalue()) # without callback, should work nodes = self.t.getpids(p, 'celery worker', callback=None) @patch('celery.bin.multi.Pidfile') @patch('socket.gethostname') @patch('celery.bin.multi.sleep') def test_shutdown_nodes(self, slepp, gethostname, Pidfile): gethostname.return_value = 'e.com' self.prepare_pidfile_for_getpids(Pidfile) self.assertIsNone(self.t.shutdown_nodes([])) self.t.signal_node = Mock() node_alive = self.t.node_alive = Mock() self.t.node_alive.return_value = False callback = Mock() self.t.stop(['foo', 'bar', 'baz'], 'celery worker', callback=callback) sigs = sorted(self.t.signal_node.call_args_list) self.assertEqual(len(sigs), 2) self.assertIn( ('*****@*****.**', 10, signal.SIGTERM), [tup[0] for tup in sigs], ) self.assertIn( ('*****@*****.**', 11, signal.SIGTERM), [tup[0] for tup in sigs], ) self.t.signal_node.return_value = False self.assertTrue(callback.called) self.t.stop(['foo', 'bar', 'baz'], 'celery worker', callback=None) def on_node_alive(pid): if node_alive.call_count > 4: return True return False self.t.signal_node.return_value = True self.t.node_alive.side_effect = on_node_alive self.t.stop(['foo', 'bar', 'baz'], 'celery worker', retry=True) @patch('os.kill') def test_node_alive(self, kill): kill.return_value = True self.assertTrue(self.t.node_alive(13)) esrch = OSError() esrch.errno = errno.ESRCH kill.side_effect = esrch self.assertFalse(self.t.node_alive(13)) kill.assert_called_with(13, 0) enoent = OSError() enoent.errno = errno.ENOENT kill.side_effect = enoent with self.assertRaises(OSError): self.t.node_alive(13) @patch('os.kill') def test_signal_node(self, kill): kill.return_value = True self.assertTrue(self.t.signal_node('foo', 13, 9)) esrch = OSError() esrch.errno = errno.ESRCH kill.side_effect = esrch self.assertFalse(self.t.signal_node('foo', 13, 9)) kill.assert_called_with(13, 9) self.assertIn('Could not signal foo', self.fh.getvalue()) enoent = OSError() enoent.errno = errno.ENOENT kill.side_effect = enoent with self.assertRaises(OSError): self.t.signal_node('foo', 13, 9) def test_start(self): self.t.waitexec = Mock() self.t.waitexec.return_value = 0 self.assertFalse(self.t.start(['foo', 'bar', 'baz'], 'celery worker')) self.t.waitexec.return_value = 1 self.assertFalse(self.t.start(['foo', 'bar', 'baz'], 'celery worker')) def test_show(self): self.t.show(['foo', 'bar', 'baz'], 'celery worker') self.assertTrue(self.fh.getvalue()) @patch('socket.gethostname') def test_get(self, gethostname): gethostname.return_value = 'e.com' self.t.get(['*****@*****.**', 'foo', 'bar', 'baz'], 'celery worker') self.assertFalse(self.fh.getvalue()) self.t.get(['*****@*****.**', 'foo', 'bar', 'baz'], 'celery worker') self.assertTrue(self.fh.getvalue()) @patch('socket.gethostname') def test_names(self, gethostname): gethostname.return_value = 'e.com' self.t.names(['foo', 'bar', 'baz'], 'celery worker') self.assertIn('[email protected]\[email protected]\[email protected]', self.fh.getvalue()) def test_execute_from_commandline(self): start = self.t.commands['start'] = Mock() self.t.error = Mock() self.t.execute_from_commandline(['multi', 'start', 'foo', 'bar']) self.assertFalse(self.t.error.called) start.assert_called_with(['foo', 'bar'], 'celery worker') self.t.error = Mock() self.t.execute_from_commandline(['multi', 'frob', 'foo', 'bar']) self.t.error.assert_called_with('Invalid command: frob') self.t.error = Mock() self.t.execute_from_commandline(['multi']) self.t.error.assert_called_with() self.t.error = Mock() self.t.execute_from_commandline(['multi', '-foo']) self.t.error.assert_called_with() self.t.execute_from_commandline( ['multi', 'start', 'foo', '--nosplash', '--quiet', '-q', '--verbose', '--no-color'], ) self.assertTrue(self.t.nosplash) self.assertTrue(self.t.quiet) self.assertTrue(self.t.verbose) self.assertTrue(self.t.no_color) def test_stopwait(self): self.t._stop_nodes = Mock() self.t.stopwait(['foo', 'bar', 'baz'], 'celery worker') self.assertEqual(self.t._stop_nodes.call_args[1]['retry'], 2) @patch('celery.bin.multi.MultiTool') def test_main(self, MultiTool): m = MultiTool.return_value = Mock() with self.assertRaises(SystemExit): main() m.execute_from_commandline.assert_called_with(sys.argv)
class test_MultiTool: def setup(self): self.fh = WhateverIO() self.env = {} self.t = MultiTool(env=self.env, fh=self.fh) self.t.cluster_from_argv = Mock(name='cluster_from_argv') self.t._cluster_from_argv = Mock(name='cluster_from_argv') self.t.Cluster = Mock(name='Cluster') self.t.carp = Mock(name='.carp') self.t.usage = Mock(name='.usage') self.t.splash = Mock(name='.splash') self.t.say = Mock(name='.say') self.t.ok = Mock(name='.ok') self.cluster = self.t.Cluster.return_value def _cluster_from_argv(argv): p = self.t.OptionParser(argv) p.parse() return p, self.cluster self.t.cluster_from_argv.return_value = self.cluster self.t._cluster_from_argv.side_effect = _cluster_from_argv def test_findsig(self): self.assert_sig_argument(['a', 'b', 'c', '-1'], 1) self.assert_sig_argument(['--foo=1', '-9'], 9) self.assert_sig_argument(['-INT'], signal.SIGINT) self.assert_sig_argument([], signal.SIGTERM) self.assert_sig_argument(['-s'], signal.SIGTERM) self.assert_sig_argument(['-log'], signal.SIGTERM) def assert_sig_argument(self, args, expected): p = self.t.OptionParser(args) p.parse() assert self.t._find_sig_argument(p) == expected def test_execute_from_commandline(self): self.t.call_command = Mock(name='call_command') self.t.execute_from_commandline( 'multi start --verbose 10 --foo'.split(), cmd='X', ) assert self.t.cmd == 'X' assert self.t.prog_name == 'multi' self.t.call_command.assert_called_with('start', ['10', '--foo']) def test_execute_from_commandline__arguments(self): assert self.t.execute_from_commandline('multi'.split()) assert self.t.execute_from_commandline('multi -bar'.split()) def test_call_command(self): cmd = self.t.commands['foo'] = Mock(name='foo') self.t.retcode = 303 assert (self.t.call_command('foo', ['1', '2', '--foo=3']) is cmd.return_value) cmd.assert_called_with('1', '2', '--foo=3') def test_call_command__error(self): assert self.t.call_command('asdqwewqe', ['1', '2']) == 1 self.t.carp.assert_called() def test_handle_reserved_options(self): assert self.t._handle_reserved_options( ['a', '-q', 'b', '--no-color', 'c']) == ['a', 'b', 'c'] def test_start(self): self.cluster.start.return_value = [0, 0, 1, 0] assert self.t.start('10', '-A', 'proj') self.t.splash.assert_called_with() self.t.cluster_from_argv.assert_called_with(('10', '-A', 'proj')) self.cluster.start.assert_called_with() def test_start__exitcodes(self): self.cluster.start.return_value = [0, 0, 0] assert not self.t.start('foo', 'bar', 'baz') self.cluster.start.assert_called_with() self.cluster.start.return_value = [0, 1, 0] assert self.t.start('foo', 'bar', 'baz') def test_stop(self): self.t.stop('10', '-A', 'proj', retry=3) self.t.splash.assert_called_with() self.t._cluster_from_argv.assert_called_with(('10', '-A', 'proj')) self.cluster.stop.assert_called_with(retry=3, sig=signal.SIGTERM) def test_stopwait(self): self.t.stopwait('10', '-A', 'proj', retry=3) self.t.splash.assert_called_with() self.t._cluster_from_argv.assert_called_with(('10', '-A', 'proj')) self.cluster.stopwait.assert_called_with(retry=3, sig=signal.SIGTERM) def test_restart(self): self.cluster.restart.return_value = [0, 0, 1, 0] self.t.restart('10', '-A', 'proj') self.t.splash.assert_called_with() self.t._cluster_from_argv.assert_called_with(('10', '-A', 'proj')) self.cluster.restart.assert_called_with(sig=signal.SIGTERM) def test_names(self): self.t.cluster_from_argv.return_value = [Mock(), Mock()] self.t.cluster_from_argv.return_value[0].name = 'x' self.t.cluster_from_argv.return_value[1].name = 'y' self.t.names('10', '-A', 'proj') self.t.say.assert_called() def test_get(self): node = self.cluster.find.return_value = Mock(name='node') node.argv = ['A', 'B', 'C'] assert (self.t.get('wanted', '10', '-A', 'proj') is self.t.ok.return_value) self.cluster.find.assert_called_with('wanted') self.t.cluster_from_argv.assert_called_with(('10', '-A', 'proj')) self.t.ok.assert_called_with(' '.join(node.argv)) def test_get__KeyError(self): self.cluster.find.side_effect = KeyError() assert self.t.get('wanted', '10', '-A', 'proj') def test_show(self): nodes = self.t.cluster_from_argv.return_value = [ Mock(name='n1'), Mock(name='n2'), ] nodes[0].argv_with_executable = ['python', 'foo', 'bar'] nodes[1].argv_with_executable = ['python', 'xuzzy', 'baz'] assert self.t.show('10', '-A', 'proj') is self.t.ok.return_value self.t.ok.assert_called_with('\n'.join( ' '.join(node.argv_with_executable) for node in nodes)) def test_kill(self): self.t.kill('10', '-A', 'proj') self.t.splash.assert_called_with() self.t.cluster_from_argv.assert_called_with(('10', '-A', 'proj')) self.cluster.kill.assert_called_with() def test_expand(self): node1 = Mock(name='n1') node2 = Mock(name='n2') node1.expander.return_value = 'A' node2.expander.return_value = 'B' nodes = self.t.cluster_from_argv.return_value = [node1, node2] assert self.t.expand('%p', '10') is self.t.ok.return_value self.t.cluster_from_argv.assert_called_with(('10', )) for node in nodes: node.expander.assert_called_with('%p') self.t.ok.assert_called_with('A\nB') def test_note(self): self.t.quiet = True self.t.note('foo') self.t.say.assert_not_called() self.t.quiet = False self.t.note('foo') self.t.say.assert_called_with('foo', newline=True) def test_splash(self): x = MultiTool() x.note = Mock() x.nosplash = True x.splash() x.note.assert_not_called() x.nosplash = False x.splash() x.note.assert_called() def test_Cluster(self): m = MultiTool() c = m.cluster_from_argv(['A', 'B', 'C']) assert c.env is m.env assert c.cmd == 'celery worker' assert c.on_stopping_preamble == m.on_stopping_preamble assert c.on_send_signal == m.on_send_signal assert c.on_still_waiting_for == m.on_still_waiting_for assert c.on_still_waiting_progress == m.on_still_waiting_progress assert c.on_still_waiting_end == m.on_still_waiting_end assert c.on_node_start == m.on_node_start assert c.on_node_restart == m.on_node_restart assert c.on_node_shutdown_ok == m.on_node_shutdown_ok assert c.on_node_status == m.on_node_status assert c.on_node_signal_dead == m.on_node_signal_dead assert c.on_node_signal == m.on_node_signal assert c.on_node_down == m.on_node_down assert c.on_child_spawn == m.on_child_spawn assert c.on_child_signalled == m.on_child_signalled assert c.on_child_failure == m.on_child_failure def test_on_stopping_preamble(self): self.t.on_stopping_preamble([]) def test_on_send_signal(self): self.t.on_send_signal(Mock(), Mock()) def test_on_still_waiting_for(self): self.t.on_still_waiting_for([Mock(), Mock()]) def test_on_still_waiting_for__empty(self): self.t.on_still_waiting_for([]) def test_on_still_waiting_progress(self): self.t.on_still_waiting_progress([]) def test_on_still_waiting_end(self): self.t.on_still_waiting_end() def test_on_node_signal_dead(self): self.t.on_node_signal_dead(Mock()) def test_on_node_start(self): self.t.on_node_start(Mock()) def test_on_node_restart(self): self.t.on_node_restart(Mock()) def test_on_node_down(self): self.t.on_node_down(Mock()) def test_on_node_shutdown_ok(self): self.t.on_node_shutdown_ok(Mock()) def test_on_node_status__FAIL(self): self.t.on_node_status(Mock(), 1) self.t.say.assert_called_with(self.t.FAILED, newline=True) def test_on_node_status__OK(self): self.t.on_node_status(Mock(), 0) self.t.say.assert_called_with(self.t.OK, newline=True) def test_on_node_signal(self): self.t.on_node_signal(Mock(), Mock()) def test_on_child_spawn(self): self.t.on_child_spawn(Mock(), Mock(), Mock()) def test_on_child_signalled(self): self.t.on_child_signalled(Mock(), Mock()) def test_on_child_failure(self): self.t.on_child_failure(Mock(), Mock()) def test_constant_strings(self): assert self.t.OK assert self.t.DOWN assert self.t.FAILED