22import time
33import os
44import subprocess
5+ import socket
56from pathlib import Path
67
78from selenium import webdriver
@@ -24,22 +25,75 @@ class MacTest(UnityTest):
2425
2526 altdriver = None
2627
28+ @staticmethod
29+ def _wait_for_tcp_port (host : str , port : int , * , timeout_seconds : float , poll_seconds : float = 1.0 ) -> bool :
30+ """
31+ Wait until a TCP port is accepting connections.
32+ This avoids long hangs inside AltDriver connection logic when the AltTester
33+ server hasn't started (common on macOS CI).
34+ """
35+ deadline = time .time () + float (timeout_seconds )
36+ while time .time () < deadline :
37+ try :
38+ with socket .create_connection ((host , int (port )), timeout = 1.0 ):
39+ return True
40+ except OSError :
41+ time .sleep (float (poll_seconds ))
42+ return False
43+
44+ @staticmethod
45+ def _dump_player_log_tail ():
46+ """
47+ Best-effort dump of Player.log to understand why AltTester server didn't start.
48+ """
49+ candidates = [
50+ os .path .expanduser ("~/Library/Logs/Unity/Player.log" ),
51+ # Standalone Player logs often land under ~/Library/Logs/<Company>/<Product>/Player.log
52+ os .path .expanduser (f"~/Library/Logs/Immutable/{ os .getenv ('UNITY_APP_NAME' , 'SampleApp' )} /Player.log" ),
53+ os .path .expanduser (f"~/Library/Logs/Immutable/{ os .getenv ('UNITY_APP_NAME' , 'Sample Unity 6 macOS' )} /Player.log" ),
54+ os .path .expanduser (f"~/Library/Logs/Immutable/{ os .getenv ('UNITY_APP_NAME' , '' )} /Player.log" ),
55+ ]
56+ seen = set ()
57+ for path in candidates :
58+ if not path or path in seen :
59+ continue
60+ seen .add (path )
61+ try :
62+ if not os .path .exists (path ):
63+ continue
64+ print (f"----- Player.log tail ({ path } ) -----" )
65+ with open (path , "r" , encoding = "utf-8" , errors = "ignore" ) as f :
66+ lines = f .read ().splitlines ()
67+ tail = lines [- 250 :] if len (lines ) > 250 else lines
68+ for line in tail :
69+ print (line )
70+ print (f"----- end Player.log tail ({ path } ) -----" )
71+ return
72+ except Exception as e :
73+ print (f"Failed to read Player.log at { path } : { e } " )
74+ print ("Player.log not found in known locations." )
75+
2776 @classmethod
2877 def setUpClass (cls ):
2978 open_sample_app ()
30- # macOS runners can take a while to start the AltTester server inside Unity.
31- # Retry connection instead of failing immediately with "Connection refused".
79+ # Avoid 20-30 minute hangs: first wait for the AltTester server port to open,
80+ # then attempt a small number of AltDriver connections.
81+ if not cls ._wait_for_tcp_port ("127.0.0.1" , 13000 , timeout_seconds = 90 , poll_seconds = 1.0 ):
82+ cls ._dump_player_log_tail ()
83+ raise SystemExit ("AltTester server port 13000 never opened on macOS." )
84+
3285 last_err = None
33- for attempt in range (12 ): # ~60s total
86+ for attempt in range (3 ):
3487 try :
3588 cls .altdriver = AltDriver (timeout = 120 )
3689 last_err = None
3790 break
3891 except Exception as e :
3992 last_err = e
40- print (f"AltDriver connect attempt { attempt + 1 } /12 failed: { e } " )
41- time .sleep (5 )
93+ print (f"AltDriver connect attempt { attempt + 1 } /3 failed: { e } " )
94+ time .sleep (2 )
4295 if last_err is not None :
96+ cls ._dump_player_log_tail ()
4397 raise SystemExit (f"Failed to connect AltDriver on macOS: { last_err } " )
4498 cls .stop_browser ()
4599
0 commit comments