(self)
| 49 | super().tearDown() |
| 50 | |
| 51 | def test_multi_process(self): |
| 52 | # This test doesn't work on twisted because we use the global |
| 53 | # reactor and don't restore it to a sane state after the fork |
| 54 | # (asyncio has the same issue, but we have a special case in |
| 55 | # place for it). |
| 56 | with ExpectLog( |
| 57 | gen_log, "(Starting .* processes|child .* exited|uncaught exception)" |
| 58 | ): |
| 59 | sock, port = bind_unused_port() |
| 60 | |
| 61 | def get_url(path): |
| 62 | return "http://127.0.0.1:%d%s" % (port, path) |
| 63 | |
| 64 | # ensure that none of these processes live too long |
| 65 | signal.alarm(5) # master process |
| 66 | try: |
| 67 | id = fork_processes(3, max_restarts=3) |
| 68 | self.assertIsNotNone(id) |
| 69 | signal.alarm(5) # child processes |
| 70 | except SystemExit as e: |
| 71 | # if we exit cleanly from fork_processes, all the child processes |
| 72 | # finished with status 0 |
| 73 | self.assertEqual(e.code, 0) |
| 74 | self.assertIsNone(task_id()) |
| 75 | sock.close() |
| 76 | return |
| 77 | try: |
| 78 | if id in (0, 1): |
| 79 | self.assertEqual(id, task_id()) |
| 80 | |
| 81 | async def f(): |
| 82 | server = HTTPServer(self.get_app()) |
| 83 | server.add_sockets([sock]) |
| 84 | await asyncio.Event().wait() |
| 85 | |
| 86 | asyncio.run(f()) |
| 87 | elif id == 2: |
| 88 | self.assertEqual(id, task_id()) |
| 89 | sock.close() |
| 90 | # Always use SimpleAsyncHTTPClient here; the curl |
| 91 | # version appears to get confused sometimes if the |
| 92 | # connection gets closed before it's had a chance to |
| 93 | # switch from writing mode to reading mode. |
| 94 | client = HTTPClient(SimpleAsyncHTTPClient) |
| 95 | |
| 96 | def fetch(url, fail_ok=False): |
| 97 | try: |
| 98 | return client.fetch(get_url(url)) |
| 99 | except HTTPError as e: |
| 100 | if not (fail_ok and e.code == 599): |
| 101 | raise |
| 102 | |
| 103 | # Make two processes exit abnormally |
| 104 | fetch("/?exit=2", fail_ok=True) |
| 105 | fetch("/?exit=3", fail_ok=True) |
| 106 | |
| 107 | # They've been restarted, so a new fetch will work |
| 108 | int(fetch("/").body) |
nothing calls this directly
no test coverage detected