Skip to content

Commit 48304d4

Browse files
fix(mac): improve AltTester connection diagnostics and host discovery
- Try connecting to AltTester on multiple candidate hosts (localhost + interface IPs from Player.log). - Dump Player.log and AltTester-Server.log tails on failure to pinpoint bind/port issues. - Keep a bounded connection budget to avoid long CI hangs.
1 parent dbf9ba6 commit 48304d4

1 file changed

Lines changed: 108 additions & 19 deletions

File tree

sample/Tests/test/test_mac.py

Lines changed: 108 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import os
44
import subprocess
55
import socket
6+
import re
67
from pathlib import Path
78

89
from selenium import webdriver
@@ -24,6 +25,7 @@
2425
class MacTest(UnityTest):
2526

2627
altdriver = None
28+
_altdriver_host = None
2729

2830
@staticmethod
2931
def _wait_for_tcp_port(host: str, port: int, *, timeout_seconds: float, poll_seconds: float = 1.0) -> bool:
@@ -73,28 +75,115 @@ def _dump_player_log_tail():
7375
print(f"Failed to read Player.log at {path}: {e}")
7476
print("Player.log not found in known locations.")
7577

78+
@staticmethod
79+
def _dump_alttester_server_log_tail():
80+
"""
81+
Best-effort dump of AltTester server log when connection fails.
82+
The Player.log usually prints where this file is stored.
83+
"""
84+
product = os.getenv("UNITY_APP_NAME", "SampleApp")
85+
candidates = [
86+
os.path.expanduser(f"~/Library/Application Support/Immutable/{product}/AltTester-Server.log"),
87+
os.path.expanduser("~/Library/Application Support/Immutable/Sample Unity 6 macOS/AltTester-Server.log"),
88+
os.path.expanduser("~/Library/Application Support/Immutable/SampleApp/AltTester-Server.log"),
89+
]
90+
seen = set()
91+
for path in candidates:
92+
if not path or path in seen:
93+
continue
94+
seen.add(path)
95+
try:
96+
if not os.path.exists(path):
97+
continue
98+
print(f"----- AltTester-Server.log tail ({path}) -----")
99+
with open(path, "r", encoding="utf-8", errors="ignore") as f:
100+
lines = f.read().splitlines()
101+
tail = lines[-250:] if len(lines) > 250 else lines
102+
for line in tail:
103+
print(line)
104+
print(f"----- end AltTester-Server.log tail ({path}) -----")
105+
return
106+
except Exception as e:
107+
print(f"Failed to read AltTester-Server.log at {path}: {e}")
108+
print("AltTester-Server.log not found in known locations.")
109+
76110
@classmethod
77-
def setUpClass(cls):
78-
open_sample_app()
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.")
111+
def _get_candidate_altdriver_hosts(cls):
112+
"""
113+
AltTester on macOS CI sometimes doesn't bind to 127.0.0.1.
114+
Parse Player.log for host interface IPs (Unity prints them early),
115+
and try those as connection hosts.
116+
"""
117+
hosts = ["127.0.0.1", "localhost"]
84118

85-
last_err = None
86-
for attempt in range(3):
119+
candidates = [
120+
os.path.expanduser("~/Library/Logs/Unity/Player.log"),
121+
os.path.expanduser(f"~/Library/Logs/Immutable/{os.getenv('UNITY_APP_NAME', 'SampleApp')}/Player.log"),
122+
os.path.expanduser("~/Library/Logs/Immutable/Sample Unity 6 macOS/Player.log"),
123+
]
124+
seen = set()
125+
for path in candidates:
126+
if not path or path in seen:
127+
continue
128+
seen.add(path)
87129
try:
88-
cls.altdriver = AltDriver(timeout=120)
89-
last_err = None
90-
break
91-
except Exception as e:
92-
last_err = e
93-
print(f"AltDriver connect attempt {attempt + 1}/3 failed: {e}")
94-
time.sleep(2)
95-
if last_err is not None:
96-
cls._dump_player_log_tail()
97-
raise SystemExit(f"Failed to connect AltDriver on macOS: {last_err}")
130+
if not os.path.exists(path):
131+
continue
132+
with open(path, "r", encoding="utf-8", errors="ignore") as f:
133+
text = f.read()
134+
# Example line:
135+
# "Found 2 interfaces on host : 0) 172.16.200.1 1) 169.254.90.9"
136+
ips = re.findall(r"\b(?:\d{1,3}\.){3}\d{1,3}\b", text)
137+
for ip in ips:
138+
if ip not in hosts:
139+
hosts.append(ip)
140+
except Exception:
141+
pass
142+
143+
# De-dupe while preserving order
144+
deduped = []
145+
for h in hosts:
146+
if h not in deduped:
147+
deduped.append(h)
148+
return deduped
149+
150+
@classmethod
151+
def _connect_altdriver(cls):
152+
"""
153+
Connect to AltTester server using a resilient host discovery strategy.
154+
"""
155+
if cls._altdriver_host:
156+
# Fast path if we already found a working host.
157+
return AltDriver(cls._altdriver_host, 13000, timeout=120)
158+
159+
hosts = cls._get_candidate_altdriver_hosts()
160+
print(f"AltDriver candidate hosts: {hosts}")
161+
162+
# Total budget for waiting for the port to appear across all hosts.
163+
deadline = time.time() + 90
164+
last_host_tried = None
165+
166+
while time.time() < deadline:
167+
for host in hosts:
168+
last_host_tried = host
169+
if cls._wait_for_tcp_port(host, 13000, timeout_seconds=3, poll_seconds=1.0):
170+
try:
171+
driver = AltDriver(host, 13000, timeout=120)
172+
cls._altdriver_host = host
173+
print(f"AltDriver connected via host: {host}")
174+
return driver
175+
except Exception as e:
176+
print(f"AltDriver connect failed on host {host}: {e}")
177+
time.sleep(1)
178+
179+
cls._dump_player_log_tail()
180+
cls._dump_alttester_server_log_tail()
181+
raise SystemExit(f"AltTester server port 13000 never opened on macOS (last host tried: {last_host_tried}).")
182+
183+
@classmethod
184+
def setUpClass(cls):
185+
open_sample_app()
186+
cls.altdriver = cls._connect_altdriver()
98187
cls.stop_browser()
99188

100189
@classmethod

0 commit comments

Comments
 (0)