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

Reply via email to