bneradt commented on code in PR #12291: URL: https://github.com/apache/trafficserver/pull/12291#discussion_r2153091760
########## tests/gold_tests/autest-site/ports.py: ########## @@ -30,6 +31,72 @@ g_ports = None # ports we can use +class AsyncPortQueue(OrderedSetQueue): + + def __init__(self): + super().__init__() + self._listening_ports = _get_listening_ports() + + async def select_available(self, amount, dmin, dmax): + rmin = dmin - 2000 + rmax = 65536 - dmax + + port_tasks = [] + await asyncio.gather(*port_tasks) + if rmax > amount: + # Fill in ports, starting above the upper OS-usable port range. + port = dmax + 1 + while port < 65536 and self.qsize() < amount: + port_tasks.append(self._check_port(port)) + port += 1 + if rmin > amount and self.qsize() < amount: + port = 2001 + # Fill in more ports, starting at 2001, well above well known ports, + # and going up until the minimum port range used by the OS. + while port < dmin and self.qsize() < amount: + port_tasks.append(self._check_port(port)) + port += 1 + + await asyncio.gather(*port_tasks) + + async def _check_port(self, port): + if await self._is_port_open(port): + host.WriteDebug('_setup_port_queue', f"Rejecting an already open port: {port}") + else: + host.WriteDebug('_setup_port_queue', f"Adding a possible port to connect to: {port}") + self.put(port) + + async def _is_port_open(self, port, address=None): + ret = False + if address is None: + address = "localhost" + + if port in self._listening_ports: + host.WriteDebug('PortOpen', f"{port} is open because it is in the listening sockets set.") + return True + + try: + # Try to connect on that port. If we can connect on it, then someone is + # listening on that port and therefore the port is open. + reader, writer = await asyncio.open_connection(address, port, limit=1) + writer.close() + await writer.wait_closed() + ret = True + host.WriteDebug( + 'PortOpen', f"Connection to port {port} succeeded, the port is open, " + "and a future connection cannot use it") + except ConnectionRefusedError: Review Comment: Running this locally, in a Rancher docker vm on my Apple silicon macbook pro, I get the following exception: ``` ╰─➤ ./autest.sh --sandbox /tmp/sb --clean=none -f emergency 20:07:30 [4/186] Running Test emergency:E Generating Report: -------------- Test: emergency: Exception File: emergency.test.py Directory: /home/bneradt/src/ts_asf_master_pr_reviews/tests/gold_tests/shutdown Reason: Traceback (most recent call last): File "/home/bneradt/src/ts_asf_master_pr_reviews/tests/gold_tests/autest-site/ports.py", line 246, in _setup_port_queue loop = asyncio.get_running_loop() RuntimeError: no running event loop During handling of the above exception, another exception occurred: Traceback (most recent call last): File "/home/bneradt/.local/share/virtualenvs/tests-68jNU4xi/lib/python3.13/site-packages/autest/core/runtesttask.py", line 34, in __call__ tl = self.__logic.Run(self.__test) File "/home/bneradt/.local/share/virtualenvs/tests-68jNU4xi/lib/python3.13/site-packages/autest/runlogic/runlogic.py", line 18, in Run if not tmp.Start(obj): ~~~~~~~~~^^^^^ File "/home/bneradt/.local/share/virtualenvs/tests-68jNU4xi/lib/python3.13/site-packages/autest/runlogic/test.py", line 90, in Start loadTest(self.__test) ~~~~~~~~^^^^^^^^^^^^^ File "/home/bneradt/.local/share/virtualenvs/tests-68jNU4xi/lib/python3.13/site-packages/autest/core/test.py", line 292, in loadTest execFile(fileName, locals, locals) ~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/bneradt/.local/share/virtualenvs/tests-68jNU4xi/lib/python3.13/site-packages/autest/common/execfile.py", line 16, in execFile exec(safeCompile(f.read(), fname), globals, locals) ~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/bneradt/src/ts_asf_master_pr_reviews/tests/gold_tests/shutdown/emergency.test.py", line 25, in <module> ts = Test.MakeATSProcess('ts') File "/home/bneradt/src/ts_asf_master_pr_reviews/tests/gold_tests/autest-site/trafficserver.test.ext", line 348, in MakeATSProcess get_port(p, "port") ~~~~~~~~^^^^^^^^^^^ File "/home/bneradt/src/ts_asf_master_pr_reviews/tests/gold_tests/autest-site/ports.py", line 282, in get_port _setup_port_queue() ~~~~~~~~~~~~~~~~~^^ File "/home/bneradt/src/ts_asf_master_pr_reviews/tests/gold_tests/autest-site/ports.py", line 249, in _setup_port_queue asyncio.run(async_setup()) ~~~~~~~~~~~^^^^^^^^^^^^^^^ File "/usr/lib64/python3.13/asyncio/runners.py", line 195, in run return runner.run(main) ~~~~~~~~~~^^^^^^ File "/usr/lib64/python3.13/asyncio/runners.py", line 118, in run return self._loop.run_until_complete(task) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^ File "/usr/lib64/python3.13/asyncio/base_events.py", line 719, in run_until_complete return future.result() ~~~~~~~~~~~~~^^ File "/home/bneradt/src/ts_asf_master_pr_reviews/tests/gold_tests/autest-site/ports.py", line 243, in async_setup await g_ports.select_available(amount, dmin, dmax) File "/home/bneradt/src/ts_asf_master_pr_reviews/tests/gold_tests/autest-site/ports.py", line 60, in select_available await asyncio.gather(*port_tasks) File "/home/bneradt/src/ts_asf_master_pr_reviews/tests/gold_tests/autest-site/ports.py", line 63, in _check_port if await self._is_port_open(port): ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/bneradt/src/ts_asf_master_pr_reviews/tests/gold_tests/autest-site/ports.py", line 81, in _is_port_open reader, writer = await asyncio.open_connection(address, port, limit=1) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib64/python3.13/asyncio/streams.py", line 48, in open_connection transport, _ = await loop.create_connection( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lambda: protocol, host, port, **kwds) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib64/python3.13/asyncio/base_events.py", line 1168, in create_connection raise OSError('Multiple exceptions: {}'.format( ', '.join(str(exc) for exc in exceptions))) OSError: Multiple exceptions: [Errno 111] Connect call failed ('::1', 61001, 0, 0), [Errno 111] Connect call failed ('127.0.0.1', 61001) Total of 1 test Unknown: 0 Exception: 1 Failed: 0 Warning: 0 Skipped: 0 Passed: 0 ``` It seems like we need to add OSError to the list of handles exceptions: ```patch diff --git a/tests/gold_tests/autest-site/ports.py b/tests/gold_tests/autest-site/ports.py index 0b8ec00e5..c5259634c 100644 --- a/tests/gold_tests/autest-site/ports.py +++ b/tests/gold_tests/autest-site/ports.py @@ -85,7 +85,7 @@ class AsyncPortQueue(OrderedSetQueue): host.WriteDebug( 'PortOpen', f"Connection to port {port} succeeded, the port is open, " "and a future connection cannot use it") - except ConnectionRefusedError: + except (ConnectionRefusedError, OSError): host.WriteDebug( 'PortOpen', f"socket error for port {port}, port is closed, " "and therefore a future connection can use it") ``` -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: github-unsubscr...@trafficserver.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org