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