17db96d56Sopenharmony_ci""" 27db96d56Sopenharmony_ciTest suite for socketserver. 37db96d56Sopenharmony_ci""" 47db96d56Sopenharmony_ci 57db96d56Sopenharmony_ciimport contextlib 67db96d56Sopenharmony_ciimport io 77db96d56Sopenharmony_ciimport os 87db96d56Sopenharmony_ciimport select 97db96d56Sopenharmony_ciimport signal 107db96d56Sopenharmony_ciimport socket 117db96d56Sopenharmony_ciimport tempfile 127db96d56Sopenharmony_ciimport threading 137db96d56Sopenharmony_ciimport unittest 147db96d56Sopenharmony_ciimport socketserver 157db96d56Sopenharmony_ci 167db96d56Sopenharmony_ciimport test.support 177db96d56Sopenharmony_cifrom test.support import reap_children, verbose 187db96d56Sopenharmony_cifrom test.support import os_helper 197db96d56Sopenharmony_cifrom test.support import socket_helper 207db96d56Sopenharmony_cifrom test.support import threading_helper 217db96d56Sopenharmony_ci 227db96d56Sopenharmony_ci 237db96d56Sopenharmony_citest.support.requires("network") 247db96d56Sopenharmony_citest.support.requires_working_socket(module=True) 257db96d56Sopenharmony_ci 267db96d56Sopenharmony_ci 277db96d56Sopenharmony_ciTEST_STR = b"hello world\n" 287db96d56Sopenharmony_ciHOST = socket_helper.HOST 297db96d56Sopenharmony_ci 307db96d56Sopenharmony_ciHAVE_UNIX_SOCKETS = hasattr(socket, "AF_UNIX") 317db96d56Sopenharmony_cirequires_unix_sockets = unittest.skipUnless(HAVE_UNIX_SOCKETS, 327db96d56Sopenharmony_ci 'requires Unix sockets') 337db96d56Sopenharmony_ciHAVE_FORKING = test.support.has_fork_support 347db96d56Sopenharmony_cirequires_forking = unittest.skipUnless(HAVE_FORKING, 'requires forking') 357db96d56Sopenharmony_ci 367db96d56Sopenharmony_cidef signal_alarm(n): 377db96d56Sopenharmony_ci """Call signal.alarm when it exists (i.e. not on Windows).""" 387db96d56Sopenharmony_ci if hasattr(signal, 'alarm'): 397db96d56Sopenharmony_ci signal.alarm(n) 407db96d56Sopenharmony_ci 417db96d56Sopenharmony_ci# Remember real select() to avoid interferences with mocking 427db96d56Sopenharmony_ci_real_select = select.select 437db96d56Sopenharmony_ci 447db96d56Sopenharmony_cidef receive(sock, n, timeout=test.support.SHORT_TIMEOUT): 457db96d56Sopenharmony_ci r, w, x = _real_select([sock], [], [], timeout) 467db96d56Sopenharmony_ci if sock in r: 477db96d56Sopenharmony_ci return sock.recv(n) 487db96d56Sopenharmony_ci else: 497db96d56Sopenharmony_ci raise RuntimeError("timed out on %r" % (sock,)) 507db96d56Sopenharmony_ci 517db96d56Sopenharmony_ciif HAVE_UNIX_SOCKETS and HAVE_FORKING: 527db96d56Sopenharmony_ci class ForkingUnixStreamServer(socketserver.ForkingMixIn, 537db96d56Sopenharmony_ci socketserver.UnixStreamServer): 547db96d56Sopenharmony_ci pass 557db96d56Sopenharmony_ci 567db96d56Sopenharmony_ci class ForkingUnixDatagramServer(socketserver.ForkingMixIn, 577db96d56Sopenharmony_ci socketserver.UnixDatagramServer): 587db96d56Sopenharmony_ci pass 597db96d56Sopenharmony_ci 607db96d56Sopenharmony_ci 617db96d56Sopenharmony_ci@contextlib.contextmanager 627db96d56Sopenharmony_cidef simple_subprocess(testcase): 637db96d56Sopenharmony_ci """Tests that a custom child process is not waited on (Issue 1540386)""" 647db96d56Sopenharmony_ci pid = os.fork() 657db96d56Sopenharmony_ci if pid == 0: 667db96d56Sopenharmony_ci # Don't raise an exception; it would be caught by the test harness. 677db96d56Sopenharmony_ci os._exit(72) 687db96d56Sopenharmony_ci try: 697db96d56Sopenharmony_ci yield None 707db96d56Sopenharmony_ci except: 717db96d56Sopenharmony_ci raise 727db96d56Sopenharmony_ci finally: 737db96d56Sopenharmony_ci test.support.wait_process(pid, exitcode=72) 747db96d56Sopenharmony_ci 757db96d56Sopenharmony_ci 767db96d56Sopenharmony_ciclass SocketServerTest(unittest.TestCase): 777db96d56Sopenharmony_ci """Test all socket servers.""" 787db96d56Sopenharmony_ci 797db96d56Sopenharmony_ci def setUp(self): 807db96d56Sopenharmony_ci signal_alarm(60) # Kill deadlocks after 60 seconds. 817db96d56Sopenharmony_ci self.port_seed = 0 827db96d56Sopenharmony_ci self.test_files = [] 837db96d56Sopenharmony_ci 847db96d56Sopenharmony_ci def tearDown(self): 857db96d56Sopenharmony_ci signal_alarm(0) # Didn't deadlock. 867db96d56Sopenharmony_ci reap_children() 877db96d56Sopenharmony_ci 887db96d56Sopenharmony_ci for fn in self.test_files: 897db96d56Sopenharmony_ci try: 907db96d56Sopenharmony_ci os.remove(fn) 917db96d56Sopenharmony_ci except OSError: 927db96d56Sopenharmony_ci pass 937db96d56Sopenharmony_ci self.test_files[:] = [] 947db96d56Sopenharmony_ci 957db96d56Sopenharmony_ci def pickaddr(self, proto): 967db96d56Sopenharmony_ci if proto == socket.AF_INET: 977db96d56Sopenharmony_ci return (HOST, 0) 987db96d56Sopenharmony_ci else: 997db96d56Sopenharmony_ci # XXX: We need a way to tell AF_UNIX to pick its own name 1007db96d56Sopenharmony_ci # like AF_INET provides port==0. 1017db96d56Sopenharmony_ci dir = None 1027db96d56Sopenharmony_ci fn = tempfile.mktemp(prefix='unix_socket.', dir=dir) 1037db96d56Sopenharmony_ci self.test_files.append(fn) 1047db96d56Sopenharmony_ci return fn 1057db96d56Sopenharmony_ci 1067db96d56Sopenharmony_ci def make_server(self, addr, svrcls, hdlrbase): 1077db96d56Sopenharmony_ci class MyServer(svrcls): 1087db96d56Sopenharmony_ci def handle_error(self, request, client_address): 1097db96d56Sopenharmony_ci self.close_request(request) 1107db96d56Sopenharmony_ci raise 1117db96d56Sopenharmony_ci 1127db96d56Sopenharmony_ci class MyHandler(hdlrbase): 1137db96d56Sopenharmony_ci def handle(self): 1147db96d56Sopenharmony_ci line = self.rfile.readline() 1157db96d56Sopenharmony_ci self.wfile.write(line) 1167db96d56Sopenharmony_ci 1177db96d56Sopenharmony_ci if verbose: print("creating server") 1187db96d56Sopenharmony_ci try: 1197db96d56Sopenharmony_ci server = MyServer(addr, MyHandler) 1207db96d56Sopenharmony_ci except PermissionError as e: 1217db96d56Sopenharmony_ci # Issue 29184: cannot bind() a Unix socket on Android. 1227db96d56Sopenharmony_ci self.skipTest('Cannot create server (%s, %s): %s' % 1237db96d56Sopenharmony_ci (svrcls, addr, e)) 1247db96d56Sopenharmony_ci self.assertEqual(server.server_address, server.socket.getsockname()) 1257db96d56Sopenharmony_ci return server 1267db96d56Sopenharmony_ci 1277db96d56Sopenharmony_ci @threading_helper.reap_threads 1287db96d56Sopenharmony_ci def run_server(self, svrcls, hdlrbase, testfunc): 1297db96d56Sopenharmony_ci server = self.make_server(self.pickaddr(svrcls.address_family), 1307db96d56Sopenharmony_ci svrcls, hdlrbase) 1317db96d56Sopenharmony_ci # We had the OS pick a port, so pull the real address out of 1327db96d56Sopenharmony_ci # the server. 1337db96d56Sopenharmony_ci addr = server.server_address 1347db96d56Sopenharmony_ci if verbose: 1357db96d56Sopenharmony_ci print("ADDR =", addr) 1367db96d56Sopenharmony_ci print("CLASS =", svrcls) 1377db96d56Sopenharmony_ci 1387db96d56Sopenharmony_ci t = threading.Thread( 1397db96d56Sopenharmony_ci name='%s serving' % svrcls, 1407db96d56Sopenharmony_ci target=server.serve_forever, 1417db96d56Sopenharmony_ci # Short poll interval to make the test finish quickly. 1427db96d56Sopenharmony_ci # Time between requests is short enough that we won't wake 1437db96d56Sopenharmony_ci # up spuriously too many times. 1447db96d56Sopenharmony_ci kwargs={'poll_interval':0.01}) 1457db96d56Sopenharmony_ci t.daemon = True # In case this function raises. 1467db96d56Sopenharmony_ci t.start() 1477db96d56Sopenharmony_ci if verbose: print("server running") 1487db96d56Sopenharmony_ci for i in range(3): 1497db96d56Sopenharmony_ci if verbose: print("test client", i) 1507db96d56Sopenharmony_ci testfunc(svrcls.address_family, addr) 1517db96d56Sopenharmony_ci if verbose: print("waiting for server") 1527db96d56Sopenharmony_ci server.shutdown() 1537db96d56Sopenharmony_ci t.join() 1547db96d56Sopenharmony_ci server.server_close() 1557db96d56Sopenharmony_ci self.assertEqual(-1, server.socket.fileno()) 1567db96d56Sopenharmony_ci if HAVE_FORKING and isinstance(server, socketserver.ForkingMixIn): 1577db96d56Sopenharmony_ci # bpo-31151: Check that ForkingMixIn.server_close() waits until 1587db96d56Sopenharmony_ci # all children completed 1597db96d56Sopenharmony_ci self.assertFalse(server.active_children) 1607db96d56Sopenharmony_ci if verbose: print("done") 1617db96d56Sopenharmony_ci 1627db96d56Sopenharmony_ci def stream_examine(self, proto, addr): 1637db96d56Sopenharmony_ci with socket.socket(proto, socket.SOCK_STREAM) as s: 1647db96d56Sopenharmony_ci s.connect(addr) 1657db96d56Sopenharmony_ci s.sendall(TEST_STR) 1667db96d56Sopenharmony_ci buf = data = receive(s, 100) 1677db96d56Sopenharmony_ci while data and b'\n' not in buf: 1687db96d56Sopenharmony_ci data = receive(s, 100) 1697db96d56Sopenharmony_ci buf += data 1707db96d56Sopenharmony_ci self.assertEqual(buf, TEST_STR) 1717db96d56Sopenharmony_ci 1727db96d56Sopenharmony_ci def dgram_examine(self, proto, addr): 1737db96d56Sopenharmony_ci with socket.socket(proto, socket.SOCK_DGRAM) as s: 1747db96d56Sopenharmony_ci if HAVE_UNIX_SOCKETS and proto == socket.AF_UNIX: 1757db96d56Sopenharmony_ci s.bind(self.pickaddr(proto)) 1767db96d56Sopenharmony_ci s.sendto(TEST_STR, addr) 1777db96d56Sopenharmony_ci buf = data = receive(s, 100) 1787db96d56Sopenharmony_ci while data and b'\n' not in buf: 1797db96d56Sopenharmony_ci data = receive(s, 100) 1807db96d56Sopenharmony_ci buf += data 1817db96d56Sopenharmony_ci self.assertEqual(buf, TEST_STR) 1827db96d56Sopenharmony_ci 1837db96d56Sopenharmony_ci def test_TCPServer(self): 1847db96d56Sopenharmony_ci self.run_server(socketserver.TCPServer, 1857db96d56Sopenharmony_ci socketserver.StreamRequestHandler, 1867db96d56Sopenharmony_ci self.stream_examine) 1877db96d56Sopenharmony_ci 1887db96d56Sopenharmony_ci def test_ThreadingTCPServer(self): 1897db96d56Sopenharmony_ci self.run_server(socketserver.ThreadingTCPServer, 1907db96d56Sopenharmony_ci socketserver.StreamRequestHandler, 1917db96d56Sopenharmony_ci self.stream_examine) 1927db96d56Sopenharmony_ci 1937db96d56Sopenharmony_ci @requires_forking 1947db96d56Sopenharmony_ci def test_ForkingTCPServer(self): 1957db96d56Sopenharmony_ci with simple_subprocess(self): 1967db96d56Sopenharmony_ci self.run_server(socketserver.ForkingTCPServer, 1977db96d56Sopenharmony_ci socketserver.StreamRequestHandler, 1987db96d56Sopenharmony_ci self.stream_examine) 1997db96d56Sopenharmony_ci 2007db96d56Sopenharmony_ci @requires_unix_sockets 2017db96d56Sopenharmony_ci def test_UnixStreamServer(self): 2027db96d56Sopenharmony_ci self.run_server(socketserver.UnixStreamServer, 2037db96d56Sopenharmony_ci socketserver.StreamRequestHandler, 2047db96d56Sopenharmony_ci self.stream_examine) 2057db96d56Sopenharmony_ci 2067db96d56Sopenharmony_ci @requires_unix_sockets 2077db96d56Sopenharmony_ci def test_ThreadingUnixStreamServer(self): 2087db96d56Sopenharmony_ci self.run_server(socketserver.ThreadingUnixStreamServer, 2097db96d56Sopenharmony_ci socketserver.StreamRequestHandler, 2107db96d56Sopenharmony_ci self.stream_examine) 2117db96d56Sopenharmony_ci 2127db96d56Sopenharmony_ci @requires_unix_sockets 2137db96d56Sopenharmony_ci @requires_forking 2147db96d56Sopenharmony_ci def test_ForkingUnixStreamServer(self): 2157db96d56Sopenharmony_ci with simple_subprocess(self): 2167db96d56Sopenharmony_ci self.run_server(ForkingUnixStreamServer, 2177db96d56Sopenharmony_ci socketserver.StreamRequestHandler, 2187db96d56Sopenharmony_ci self.stream_examine) 2197db96d56Sopenharmony_ci 2207db96d56Sopenharmony_ci def test_UDPServer(self): 2217db96d56Sopenharmony_ci self.run_server(socketserver.UDPServer, 2227db96d56Sopenharmony_ci socketserver.DatagramRequestHandler, 2237db96d56Sopenharmony_ci self.dgram_examine) 2247db96d56Sopenharmony_ci 2257db96d56Sopenharmony_ci def test_ThreadingUDPServer(self): 2267db96d56Sopenharmony_ci self.run_server(socketserver.ThreadingUDPServer, 2277db96d56Sopenharmony_ci socketserver.DatagramRequestHandler, 2287db96d56Sopenharmony_ci self.dgram_examine) 2297db96d56Sopenharmony_ci 2307db96d56Sopenharmony_ci @requires_forking 2317db96d56Sopenharmony_ci def test_ForkingUDPServer(self): 2327db96d56Sopenharmony_ci with simple_subprocess(self): 2337db96d56Sopenharmony_ci self.run_server(socketserver.ForkingUDPServer, 2347db96d56Sopenharmony_ci socketserver.DatagramRequestHandler, 2357db96d56Sopenharmony_ci self.dgram_examine) 2367db96d56Sopenharmony_ci 2377db96d56Sopenharmony_ci @requires_unix_sockets 2387db96d56Sopenharmony_ci def test_UnixDatagramServer(self): 2397db96d56Sopenharmony_ci self.run_server(socketserver.UnixDatagramServer, 2407db96d56Sopenharmony_ci socketserver.DatagramRequestHandler, 2417db96d56Sopenharmony_ci self.dgram_examine) 2427db96d56Sopenharmony_ci 2437db96d56Sopenharmony_ci @requires_unix_sockets 2447db96d56Sopenharmony_ci def test_ThreadingUnixDatagramServer(self): 2457db96d56Sopenharmony_ci self.run_server(socketserver.ThreadingUnixDatagramServer, 2467db96d56Sopenharmony_ci socketserver.DatagramRequestHandler, 2477db96d56Sopenharmony_ci self.dgram_examine) 2487db96d56Sopenharmony_ci 2497db96d56Sopenharmony_ci @requires_unix_sockets 2507db96d56Sopenharmony_ci @requires_forking 2517db96d56Sopenharmony_ci def test_ForkingUnixDatagramServer(self): 2527db96d56Sopenharmony_ci self.run_server(ForkingUnixDatagramServer, 2537db96d56Sopenharmony_ci socketserver.DatagramRequestHandler, 2547db96d56Sopenharmony_ci self.dgram_examine) 2557db96d56Sopenharmony_ci 2567db96d56Sopenharmony_ci @threading_helper.reap_threads 2577db96d56Sopenharmony_ci def test_shutdown(self): 2587db96d56Sopenharmony_ci # Issue #2302: shutdown() should always succeed in making an 2597db96d56Sopenharmony_ci # other thread leave serve_forever(). 2607db96d56Sopenharmony_ci class MyServer(socketserver.TCPServer): 2617db96d56Sopenharmony_ci pass 2627db96d56Sopenharmony_ci 2637db96d56Sopenharmony_ci class MyHandler(socketserver.StreamRequestHandler): 2647db96d56Sopenharmony_ci pass 2657db96d56Sopenharmony_ci 2667db96d56Sopenharmony_ci threads = [] 2677db96d56Sopenharmony_ci for i in range(20): 2687db96d56Sopenharmony_ci s = MyServer((HOST, 0), MyHandler) 2697db96d56Sopenharmony_ci t = threading.Thread( 2707db96d56Sopenharmony_ci name='MyServer serving', 2717db96d56Sopenharmony_ci target=s.serve_forever, 2727db96d56Sopenharmony_ci kwargs={'poll_interval':0.01}) 2737db96d56Sopenharmony_ci t.daemon = True # In case this function raises. 2747db96d56Sopenharmony_ci threads.append((t, s)) 2757db96d56Sopenharmony_ci for t, s in threads: 2767db96d56Sopenharmony_ci t.start() 2777db96d56Sopenharmony_ci s.shutdown() 2787db96d56Sopenharmony_ci for t, s in threads: 2797db96d56Sopenharmony_ci t.join() 2807db96d56Sopenharmony_ci s.server_close() 2817db96d56Sopenharmony_ci 2827db96d56Sopenharmony_ci def test_close_immediately(self): 2837db96d56Sopenharmony_ci class MyServer(socketserver.ThreadingMixIn, socketserver.TCPServer): 2847db96d56Sopenharmony_ci pass 2857db96d56Sopenharmony_ci 2867db96d56Sopenharmony_ci server = MyServer((HOST, 0), lambda: None) 2877db96d56Sopenharmony_ci server.server_close() 2887db96d56Sopenharmony_ci 2897db96d56Sopenharmony_ci def test_tcpserver_bind_leak(self): 2907db96d56Sopenharmony_ci # Issue #22435: the server socket wouldn't be closed if bind()/listen() 2917db96d56Sopenharmony_ci # failed. 2927db96d56Sopenharmony_ci # Create many servers for which bind() will fail, to see if this result 2937db96d56Sopenharmony_ci # in FD exhaustion. 2947db96d56Sopenharmony_ci for i in range(1024): 2957db96d56Sopenharmony_ci with self.assertRaises(OverflowError): 2967db96d56Sopenharmony_ci socketserver.TCPServer((HOST, -1), 2977db96d56Sopenharmony_ci socketserver.StreamRequestHandler) 2987db96d56Sopenharmony_ci 2997db96d56Sopenharmony_ci def test_context_manager(self): 3007db96d56Sopenharmony_ci with socketserver.TCPServer((HOST, 0), 3017db96d56Sopenharmony_ci socketserver.StreamRequestHandler) as server: 3027db96d56Sopenharmony_ci pass 3037db96d56Sopenharmony_ci self.assertEqual(-1, server.socket.fileno()) 3047db96d56Sopenharmony_ci 3057db96d56Sopenharmony_ci 3067db96d56Sopenharmony_ciclass ErrorHandlerTest(unittest.TestCase): 3077db96d56Sopenharmony_ci """Test that the servers pass normal exceptions from the handler to 3087db96d56Sopenharmony_ci handle_error(), and that exiting exceptions like SystemExit and 3097db96d56Sopenharmony_ci KeyboardInterrupt are not passed.""" 3107db96d56Sopenharmony_ci 3117db96d56Sopenharmony_ci def tearDown(self): 3127db96d56Sopenharmony_ci os_helper.unlink(os_helper.TESTFN) 3137db96d56Sopenharmony_ci 3147db96d56Sopenharmony_ci def test_sync_handled(self): 3157db96d56Sopenharmony_ci BaseErrorTestServer(ValueError) 3167db96d56Sopenharmony_ci self.check_result(handled=True) 3177db96d56Sopenharmony_ci 3187db96d56Sopenharmony_ci def test_sync_not_handled(self): 3197db96d56Sopenharmony_ci with self.assertRaises(SystemExit): 3207db96d56Sopenharmony_ci BaseErrorTestServer(SystemExit) 3217db96d56Sopenharmony_ci self.check_result(handled=False) 3227db96d56Sopenharmony_ci 3237db96d56Sopenharmony_ci def test_threading_handled(self): 3247db96d56Sopenharmony_ci ThreadingErrorTestServer(ValueError) 3257db96d56Sopenharmony_ci self.check_result(handled=True) 3267db96d56Sopenharmony_ci 3277db96d56Sopenharmony_ci def test_threading_not_handled(self): 3287db96d56Sopenharmony_ci with threading_helper.catch_threading_exception() as cm: 3297db96d56Sopenharmony_ci ThreadingErrorTestServer(SystemExit) 3307db96d56Sopenharmony_ci self.check_result(handled=False) 3317db96d56Sopenharmony_ci 3327db96d56Sopenharmony_ci self.assertIs(cm.exc_type, SystemExit) 3337db96d56Sopenharmony_ci 3347db96d56Sopenharmony_ci @requires_forking 3357db96d56Sopenharmony_ci def test_forking_handled(self): 3367db96d56Sopenharmony_ci ForkingErrorTestServer(ValueError) 3377db96d56Sopenharmony_ci self.check_result(handled=True) 3387db96d56Sopenharmony_ci 3397db96d56Sopenharmony_ci @requires_forking 3407db96d56Sopenharmony_ci def test_forking_not_handled(self): 3417db96d56Sopenharmony_ci ForkingErrorTestServer(SystemExit) 3427db96d56Sopenharmony_ci self.check_result(handled=False) 3437db96d56Sopenharmony_ci 3447db96d56Sopenharmony_ci def check_result(self, handled): 3457db96d56Sopenharmony_ci with open(os_helper.TESTFN) as log: 3467db96d56Sopenharmony_ci expected = 'Handler called\n' + 'Error handled\n' * handled 3477db96d56Sopenharmony_ci self.assertEqual(log.read(), expected) 3487db96d56Sopenharmony_ci 3497db96d56Sopenharmony_ci 3507db96d56Sopenharmony_ciclass BaseErrorTestServer(socketserver.TCPServer): 3517db96d56Sopenharmony_ci def __init__(self, exception): 3527db96d56Sopenharmony_ci self.exception = exception 3537db96d56Sopenharmony_ci super().__init__((HOST, 0), BadHandler) 3547db96d56Sopenharmony_ci with socket.create_connection(self.server_address): 3557db96d56Sopenharmony_ci pass 3567db96d56Sopenharmony_ci try: 3577db96d56Sopenharmony_ci self.handle_request() 3587db96d56Sopenharmony_ci finally: 3597db96d56Sopenharmony_ci self.server_close() 3607db96d56Sopenharmony_ci self.wait_done() 3617db96d56Sopenharmony_ci 3627db96d56Sopenharmony_ci def handle_error(self, request, client_address): 3637db96d56Sopenharmony_ci with open(os_helper.TESTFN, 'a') as log: 3647db96d56Sopenharmony_ci log.write('Error handled\n') 3657db96d56Sopenharmony_ci 3667db96d56Sopenharmony_ci def wait_done(self): 3677db96d56Sopenharmony_ci pass 3687db96d56Sopenharmony_ci 3697db96d56Sopenharmony_ci 3707db96d56Sopenharmony_ciclass BadHandler(socketserver.BaseRequestHandler): 3717db96d56Sopenharmony_ci def handle(self): 3727db96d56Sopenharmony_ci with open(os_helper.TESTFN, 'a') as log: 3737db96d56Sopenharmony_ci log.write('Handler called\n') 3747db96d56Sopenharmony_ci raise self.server.exception('Test error') 3757db96d56Sopenharmony_ci 3767db96d56Sopenharmony_ci 3777db96d56Sopenharmony_ciclass ThreadingErrorTestServer(socketserver.ThreadingMixIn, 3787db96d56Sopenharmony_ci BaseErrorTestServer): 3797db96d56Sopenharmony_ci def __init__(self, *pos, **kw): 3807db96d56Sopenharmony_ci self.done = threading.Event() 3817db96d56Sopenharmony_ci super().__init__(*pos, **kw) 3827db96d56Sopenharmony_ci 3837db96d56Sopenharmony_ci def shutdown_request(self, *pos, **kw): 3847db96d56Sopenharmony_ci super().shutdown_request(*pos, **kw) 3857db96d56Sopenharmony_ci self.done.set() 3867db96d56Sopenharmony_ci 3877db96d56Sopenharmony_ci def wait_done(self): 3887db96d56Sopenharmony_ci self.done.wait() 3897db96d56Sopenharmony_ci 3907db96d56Sopenharmony_ci 3917db96d56Sopenharmony_ciif HAVE_FORKING: 3927db96d56Sopenharmony_ci class ForkingErrorTestServer(socketserver.ForkingMixIn, BaseErrorTestServer): 3937db96d56Sopenharmony_ci pass 3947db96d56Sopenharmony_ci 3957db96d56Sopenharmony_ci 3967db96d56Sopenharmony_ciclass SocketWriterTest(unittest.TestCase): 3977db96d56Sopenharmony_ci def test_basics(self): 3987db96d56Sopenharmony_ci class Handler(socketserver.StreamRequestHandler): 3997db96d56Sopenharmony_ci def handle(self): 4007db96d56Sopenharmony_ci self.server.wfile = self.wfile 4017db96d56Sopenharmony_ci self.server.wfile_fileno = self.wfile.fileno() 4027db96d56Sopenharmony_ci self.server.request_fileno = self.request.fileno() 4037db96d56Sopenharmony_ci 4047db96d56Sopenharmony_ci server = socketserver.TCPServer((HOST, 0), Handler) 4057db96d56Sopenharmony_ci self.addCleanup(server.server_close) 4067db96d56Sopenharmony_ci s = socket.socket( 4077db96d56Sopenharmony_ci server.address_family, socket.SOCK_STREAM, socket.IPPROTO_TCP) 4087db96d56Sopenharmony_ci with s: 4097db96d56Sopenharmony_ci s.connect(server.server_address) 4107db96d56Sopenharmony_ci server.handle_request() 4117db96d56Sopenharmony_ci self.assertIsInstance(server.wfile, io.BufferedIOBase) 4127db96d56Sopenharmony_ci self.assertEqual(server.wfile_fileno, server.request_fileno) 4137db96d56Sopenharmony_ci 4147db96d56Sopenharmony_ci def test_write(self): 4157db96d56Sopenharmony_ci # Test that wfile.write() sends data immediately, and that it does 4167db96d56Sopenharmony_ci # not truncate sends when interrupted by a Unix signal 4177db96d56Sopenharmony_ci pthread_kill = test.support.get_attribute(signal, 'pthread_kill') 4187db96d56Sopenharmony_ci 4197db96d56Sopenharmony_ci class Handler(socketserver.StreamRequestHandler): 4207db96d56Sopenharmony_ci def handle(self): 4217db96d56Sopenharmony_ci self.server.sent1 = self.wfile.write(b'write data\n') 4227db96d56Sopenharmony_ci # Should be sent immediately, without requiring flush() 4237db96d56Sopenharmony_ci self.server.received = self.rfile.readline() 4247db96d56Sopenharmony_ci big_chunk = b'\0' * test.support.SOCK_MAX_SIZE 4257db96d56Sopenharmony_ci self.server.sent2 = self.wfile.write(big_chunk) 4267db96d56Sopenharmony_ci 4277db96d56Sopenharmony_ci server = socketserver.TCPServer((HOST, 0), Handler) 4287db96d56Sopenharmony_ci self.addCleanup(server.server_close) 4297db96d56Sopenharmony_ci interrupted = threading.Event() 4307db96d56Sopenharmony_ci 4317db96d56Sopenharmony_ci def signal_handler(signum, frame): 4327db96d56Sopenharmony_ci interrupted.set() 4337db96d56Sopenharmony_ci 4347db96d56Sopenharmony_ci original = signal.signal(signal.SIGUSR1, signal_handler) 4357db96d56Sopenharmony_ci self.addCleanup(signal.signal, signal.SIGUSR1, original) 4367db96d56Sopenharmony_ci response1 = None 4377db96d56Sopenharmony_ci received2 = None 4387db96d56Sopenharmony_ci main_thread = threading.get_ident() 4397db96d56Sopenharmony_ci 4407db96d56Sopenharmony_ci def run_client(): 4417db96d56Sopenharmony_ci s = socket.socket(server.address_family, socket.SOCK_STREAM, 4427db96d56Sopenharmony_ci socket.IPPROTO_TCP) 4437db96d56Sopenharmony_ci with s, s.makefile('rb') as reader: 4447db96d56Sopenharmony_ci s.connect(server.server_address) 4457db96d56Sopenharmony_ci nonlocal response1 4467db96d56Sopenharmony_ci response1 = reader.readline() 4477db96d56Sopenharmony_ci s.sendall(b'client response\n') 4487db96d56Sopenharmony_ci 4497db96d56Sopenharmony_ci reader.read(100) 4507db96d56Sopenharmony_ci # The main thread should now be blocking in a send() syscall. 4517db96d56Sopenharmony_ci # But in theory, it could get interrupted by other signals, 4527db96d56Sopenharmony_ci # and then retried. So keep sending the signal in a loop, in 4537db96d56Sopenharmony_ci # case an earlier signal happens to be delivered at an 4547db96d56Sopenharmony_ci # inconvenient moment. 4557db96d56Sopenharmony_ci while True: 4567db96d56Sopenharmony_ci pthread_kill(main_thread, signal.SIGUSR1) 4577db96d56Sopenharmony_ci if interrupted.wait(timeout=float(1)): 4587db96d56Sopenharmony_ci break 4597db96d56Sopenharmony_ci nonlocal received2 4607db96d56Sopenharmony_ci received2 = len(reader.read()) 4617db96d56Sopenharmony_ci 4627db96d56Sopenharmony_ci background = threading.Thread(target=run_client) 4637db96d56Sopenharmony_ci background.start() 4647db96d56Sopenharmony_ci server.handle_request() 4657db96d56Sopenharmony_ci background.join() 4667db96d56Sopenharmony_ci self.assertEqual(server.sent1, len(response1)) 4677db96d56Sopenharmony_ci self.assertEqual(response1, b'write data\n') 4687db96d56Sopenharmony_ci self.assertEqual(server.received, b'client response\n') 4697db96d56Sopenharmony_ci self.assertEqual(server.sent2, test.support.SOCK_MAX_SIZE) 4707db96d56Sopenharmony_ci self.assertEqual(received2, test.support.SOCK_MAX_SIZE - 100) 4717db96d56Sopenharmony_ci 4727db96d56Sopenharmony_ci 4737db96d56Sopenharmony_ciclass MiscTestCase(unittest.TestCase): 4747db96d56Sopenharmony_ci 4757db96d56Sopenharmony_ci def test_all(self): 4767db96d56Sopenharmony_ci # objects defined in the module should be in __all__ 4777db96d56Sopenharmony_ci expected = [] 4787db96d56Sopenharmony_ci for name in dir(socketserver): 4797db96d56Sopenharmony_ci if not name.startswith('_'): 4807db96d56Sopenharmony_ci mod_object = getattr(socketserver, name) 4817db96d56Sopenharmony_ci if getattr(mod_object, '__module__', None) == 'socketserver': 4827db96d56Sopenharmony_ci expected.append(name) 4837db96d56Sopenharmony_ci self.assertCountEqual(socketserver.__all__, expected) 4847db96d56Sopenharmony_ci 4857db96d56Sopenharmony_ci def test_shutdown_request_called_if_verify_request_false(self): 4867db96d56Sopenharmony_ci # Issue #26309: BaseServer should call shutdown_request even if 4877db96d56Sopenharmony_ci # verify_request is False 4887db96d56Sopenharmony_ci 4897db96d56Sopenharmony_ci class MyServer(socketserver.TCPServer): 4907db96d56Sopenharmony_ci def verify_request(self, request, client_address): 4917db96d56Sopenharmony_ci return False 4927db96d56Sopenharmony_ci 4937db96d56Sopenharmony_ci shutdown_called = 0 4947db96d56Sopenharmony_ci def shutdown_request(self, request): 4957db96d56Sopenharmony_ci self.shutdown_called += 1 4967db96d56Sopenharmony_ci socketserver.TCPServer.shutdown_request(self, request) 4977db96d56Sopenharmony_ci 4987db96d56Sopenharmony_ci server = MyServer((HOST, 0), socketserver.StreamRequestHandler) 4997db96d56Sopenharmony_ci s = socket.socket(server.address_family, socket.SOCK_STREAM) 5007db96d56Sopenharmony_ci s.connect(server.server_address) 5017db96d56Sopenharmony_ci s.close() 5027db96d56Sopenharmony_ci server.handle_request() 5037db96d56Sopenharmony_ci self.assertEqual(server.shutdown_called, 1) 5047db96d56Sopenharmony_ci server.server_close() 5057db96d56Sopenharmony_ci 5067db96d56Sopenharmony_ci def test_threads_reaped(self): 5077db96d56Sopenharmony_ci """ 5087db96d56Sopenharmony_ci In #37193, users reported a memory leak 5097db96d56Sopenharmony_ci due to the saving of every request thread. Ensure that 5107db96d56Sopenharmony_ci not all threads are kept forever. 5117db96d56Sopenharmony_ci """ 5127db96d56Sopenharmony_ci class MyServer(socketserver.ThreadingMixIn, socketserver.TCPServer): 5137db96d56Sopenharmony_ci pass 5147db96d56Sopenharmony_ci 5157db96d56Sopenharmony_ci server = MyServer((HOST, 0), socketserver.StreamRequestHandler) 5167db96d56Sopenharmony_ci for n in range(10): 5177db96d56Sopenharmony_ci with socket.create_connection(server.server_address): 5187db96d56Sopenharmony_ci server.handle_request() 5197db96d56Sopenharmony_ci self.assertLess(len(server._threads), 10) 5207db96d56Sopenharmony_ci server.server_close() 5217db96d56Sopenharmony_ci 5227db96d56Sopenharmony_ci 5237db96d56Sopenharmony_ciif __name__ == "__main__": 5247db96d56Sopenharmony_ci unittest.main() 525