Skip to content

Commit 4fa760c

Browse files
committed
issue #613: add tests for all the weird shutdown methods
1 parent 57012e0 commit 4fa760c

File tree

3 files changed

+112
-1
lines changed

3 files changed

+112
-1
lines changed

docs/internals.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,11 @@ These signals are used internally by Mitogen.
321321
- ``disconnect``
322322
- Fired on the Broker thread during shutdown (???)
323323

324+
* - :py:class:`mitogen.parent.Process`
325+
- ``exit``
326+
- Fired when :class:`mitogen.parent.Reaper` detects subprocess has fully
327+
exitted.
328+
324329
* - :py:class:`mitogen.core.Broker`
325330
- ``shutdown``
326331
- Fired after Broker.shutdown() is called.

mitogen/parent.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2331,7 +2331,7 @@ def disconnect(self, context):
23312331
directly connected.
23322332
"""
23332333
stream = self.stream_by_id(context)
2334-
if stream.protocol.remote_id != context.context_id:
2334+
if stream is None or stream.protocol.remote_id != context.context_id:
23352335
return
23362336

23372337
l = mitogen.core.Latch()
@@ -2589,6 +2589,7 @@ def reap(self):
25892589
status = self.proc.poll()
25902590
if status is not None:
25912591
LOG.debug('%r: %s', self.proc, returncode_to_str(status))
2592+
mitogen.core.fire(self.proc, 'exit')
25922593
self._remove_timer()
25932594
return
25942595

tests/router_test.py

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import errno
2+
import os
13
import sys
24
import time
35
import zlib
@@ -425,5 +427,108 @@ def test_egress_ids_populated(self):
425427
]))
426428

427429

430+
class ShutdownTest(testlib.RouterMixin, testlib.TestCase):
431+
# 613: tests for all the weird shutdown() variants we ended up with.
432+
433+
def test_shutdown_wait_false(self):
434+
l1 = self.router.local()
435+
pid = l1.call(os.getpid)
436+
437+
conn = self.router.stream_by_id(l1.context_id).conn
438+
exitted = mitogen.core.Latch()
439+
mitogen.core.listen(conn.proc, 'exit', exitted.put)
440+
441+
l1.shutdown(wait=False)
442+
exitted.get()
443+
444+
e = self.assertRaises(OSError,
445+
lambda: os.waitpid(pid, 0))
446+
self.assertEquals(e.args[0], errno.ECHILD)
447+
448+
e = self.assertRaises(mitogen.core.ChannelError,
449+
lambda: l1.call(os.getpid))
450+
self.assertEquals(e.args[0], mitogen.core.Router.no_route_msg % (
451+
l1.context_id,
452+
mitogen.context_id,
453+
))
454+
455+
def test_shutdown_wait_true(self):
456+
l1 = self.router.local()
457+
pid = l1.call(os.getpid)
458+
459+
conn = self.router.stream_by_id(l1.context_id).conn
460+
exitted = mitogen.core.Latch()
461+
mitogen.core.listen(conn.proc, 'exit', exitted.put)
462+
463+
l1.shutdown(wait=True)
464+
exitted.get()
465+
466+
e = self.assertRaises(OSError,
467+
lambda: os.waitpid(pid, 0))
468+
self.assertEquals(e.args[0], errno.ECHILD)
469+
470+
e = self.assertRaises(mitogen.core.ChannelError,
471+
lambda: l1.call(os.getpid))
472+
self.assertEquals(e.args[0], mitogen.core.Router.no_route_msg % (
473+
l1.context_id,
474+
mitogen.context_id,
475+
))
476+
477+
def test_disconnect_invalid_context(self):
478+
self.router.disconnect(
479+
mitogen.core.Context(self.router, 1234)
480+
)
481+
482+
def test_disconnect_valid_context(self):
483+
l1 = self.router.local()
484+
pid = l1.call(os.getpid)
485+
486+
strm = self.router.stream_by_id(l1.context_id)
487+
488+
exitted = mitogen.core.Latch()
489+
mitogen.core.listen(strm.conn.proc, 'exit', exitted.put)
490+
self.router.disconnect_stream(strm)
491+
exitted.get()
492+
493+
e = self.assertRaises(OSError,
494+
lambda: os.waitpid(pid, 0))
495+
self.assertEquals(e.args[0], errno.ECHILD)
496+
497+
e = self.assertRaises(mitogen.core.ChannelError,
498+
lambda: l1.call(os.getpid))
499+
self.assertEquals(e.args[0], mitogen.core.Router.no_route_msg % (
500+
l1.context_id,
501+
mitogen.context_id,
502+
))
503+
504+
def test_disconnet_all(self):
505+
l1 = self.router.local()
506+
l2 = self.router.local()
507+
508+
pids = [l1.call(os.getpid), l2.call(os.getpid)]
509+
510+
exitted = mitogen.core.Latch()
511+
for ctx in l1, l2:
512+
strm = self.router.stream_by_id(ctx.context_id)
513+
mitogen.core.listen(strm.conn.proc, 'exit', exitted.put)
514+
515+
self.router.disconnect_all()
516+
exitted.get()
517+
exitted.get()
518+
519+
for pid in pids:
520+
e = self.assertRaises(OSError,
521+
lambda: os.waitpid(pid, 0))
522+
self.assertEquals(e.args[0], errno.ECHILD)
523+
524+
for ctx in l1, l2:
525+
e = self.assertRaises(mitogen.core.ChannelError,
526+
lambda: ctx.call(os.getpid))
527+
self.assertEquals(e.args[0], mitogen.core.Router.no_route_msg % (
528+
ctx.context_id,
529+
mitogen.context_id,
530+
))
531+
532+
428533
if __name__ == '__main__':
429534
unittest2.main()

0 commit comments

Comments
 (0)