Skip to content

Commit 963fd0d

Browse files
ci(audience): run linux PlayMode under xvfb (SDK-317 / SDK-318)
- Reworks playmode-linux to run inside a docker container under xvfb, via .github/scripts/audience/playmode-linux.sh. game-ci/unity-test-runner@v4 hardcodes -nographics, so PlayMode tests came back inconclusive and silently passed. - Watchdog SIGTERMs Unity 30s after "Test run completed" so cells exit on suite finish; handles Unity 6's known shutdown hang. - -force-glcore at runtime skips the Unity 6 Vulkan init and matches the Unity 2021.3 default path. - Suppresses in-app log pane on Unity 6 Linux to skip llvmpipe rasterising UI Toolkit triangles per frame. - Stamps CI build info into Player.log on player startup; gated to CI runs only. - Mirrors SDK output and OnError fires to Debug.Log so failures land in Player.log. - DiskStore.ReadBatch treats missing queue dir as empty (matches existing guards). - Live-fire test SetUp ignores cleanup-time OnError fires so background flush cancellations do not fail unrelated tests. - Trims 30 unused packages from the sample-app manifest. - Extracts the macOS and Windows playmode runners and the Windows VS Build Tools setup to .github/scripts/, mirroring the Linux pattern. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 4017213 commit 963fd0d

14 files changed

Lines changed: 651 additions & 492 deletions
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Ensures Visual Studio Build Tools (VC.Tools + Win10 SDK) are present on the runner.
2+
# Workflow caller: .github/workflows/test-audience-sample-app.yml (Windows IL2CPP cells).
3+
4+
$vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
5+
6+
# Match Unity's detection logic: vswhere requires VC.Tools (any version), registry
7+
# probe for any Win10 SDK at v10.0/InstallationFolder. Pinning a specific SDK
8+
# version in -requires is too strict; VCTools ships with whatever Win10 SDK is
9+
# current, and Unity accepts any.
10+
function Test-Toolchain {
11+
$vc = if (Test-Path $vswhere) {
12+
& $vswhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath 2>$null
13+
} else { '' }
14+
$sdk = (Get-ItemProperty 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows\v10.0' -ErrorAction SilentlyContinue).InstallationFolder
15+
return @{ VcTools = $vc; Win10Sdk = $sdk }
16+
}
17+
18+
$state = Test-Toolchain
19+
if ($state.VcTools -and $state.Win10Sdk) {
20+
Write-Output "VC.Tools at: $($state.VcTools)"
21+
Write-Output "Win10 SDK at: $($state.Win10Sdk)"
22+
exit 0
23+
}
24+
Write-Output "Toolchain incomplete. VC.Tools='$($state.VcTools)' Win10Sdk='$($state.Win10Sdk)'"
25+
26+
Write-Output "::group::Install VS 2022 Build Tools (VCTools + Win10 SDK)"
27+
$installer = "$env:RUNNER_TEMP\vs_BuildTools.exe"
28+
Invoke-WebRequest -Uri 'https://aka.ms/vs/17/release/vs_BuildTools.exe' -OutFile $installer
29+
30+
$installArgs = @(
31+
'--quiet','--wait','--norestart','--nocache',
32+
'--add','Microsoft.VisualStudio.Workload.VCTools',
33+
'--add','Microsoft.VisualStudio.Component.VC.Tools.x86.x64',
34+
'--add','Microsoft.VisualStudio.Component.Windows10SDK.20348',
35+
'--includeRecommended'
36+
)
37+
$p = Start-Process -FilePath $installer -ArgumentList $installArgs -Wait -PassThru -NoNewWindow
38+
# 3010 = success, reboot pending (tools are usable without reboot).
39+
if ($p.ExitCode -ne 0 -and $p.ExitCode -ne 3010) {
40+
Write-Output "::error::VS Build Tools installer exited $($p.ExitCode)"
41+
exit $p.ExitCode
42+
}
43+
Write-Output "::endgroup::"
44+
45+
$state = Test-Toolchain
46+
if (-not ($state.VcTools -and $state.Win10Sdk)) {
47+
Write-Output "::group::diagnostic"
48+
Write-Output "VC.Tools path (vswhere): '$($state.VcTools)'"
49+
Write-Output "Win10 SDK (registry v10.0/InstallationFolder): '$($state.Win10Sdk)'"
50+
Write-Output "--- all VS installations ---"
51+
if (Test-Path $vswhere) { & $vswhere -all -products * -format json }
52+
Write-Output "--- HKLM Win10 SDK roots ---"
53+
Get-ChildItem 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows' -ErrorAction SilentlyContinue | Format-List
54+
Write-Output "::endgroup::"
55+
Write-Output "::error::Install reported success but VC.Tools or Win10 SDK still not detected. Runner service account likely lacks admin to install system-wide. Install VS Build Tools manually on IMX_SDKBUILD: vs_BuildTools.exe --quiet --wait --add Microsoft.VisualStudio.Workload.VCTools --includeRecommended"
56+
exit 1
57+
}
58+
Write-Output "Verified VC.Tools at: $($state.VcTools)"
59+
Write-Output "Verified Win10 SDK at: $($state.Win10Sdk)"
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#!/bin/bash
2+
# Installs the Unity editor and (for IL2CPP cells) the mac-il2cpp module.
3+
# Idempotent. Sets UNITY_PATH in GITHUB_ENV so the playmode step picks it up.
4+
# Workflow caller: .github/workflows/test-audience-sample-app.yml (playmode job).
5+
#
6+
# Inputs (env): UNITY_VERSION, UNITY_CHANGESET, BACKEND.
7+
8+
set -uo pipefail
9+
10+
HUB="/Applications/Unity Hub.app/Contents/MacOS/Unity Hub"
11+
12+
echo "::group::install editor"
13+
"$HUB" -- --headless install \
14+
--version "$UNITY_VERSION" --changeset "$UNITY_CHANGESET" --architecture arm64 \
15+
|| echo "(install non-zero, OK if 'Editor already installed in this location')"
16+
echo "::endgroup::"
17+
18+
if [ "$BACKEND" = "IL2CPP" ]; then
19+
echo "::group::install mac-il2cpp module"
20+
"$HUB" -- --headless install-modules \
21+
--version "$UNITY_VERSION" --changeset "$UNITY_CHANGESET" --architecture arm64 \
22+
--module mac-il2cpp \
23+
|| echo "(install-modules non-zero, OK if 'No modules found to install')"
24+
echo "::endgroup::"
25+
fi
26+
27+
EDITOR_APP=""
28+
for cand in \
29+
"/Applications/Unity/Hub/Editor/$UNITY_VERSION-arm64/Unity.app" \
30+
"/Applications/Unity/Hub/Editor/$UNITY_VERSION/Unity.app"; do
31+
if [ -x "$cand/Contents/MacOS/Unity" ]; then EDITOR_APP="$cand"; break; fi
32+
done
33+
34+
IL2CPP_DIR=""
35+
if [ "$BACKEND" = "IL2CPP" ] && [ -n "$EDITOR_APP" ]; then
36+
for d in \
37+
"$EDITOR_APP/Contents/PlaybackEngines/MacStandaloneSupport/Variations/macos_arm64_player_nondevelopment_il2cpp" \
38+
"$EDITOR_APP/Contents/PlaybackEngines/MacStandaloneSupport/Variations/macos_x64_player_nondevelopment_il2cpp"; do
39+
if [ -d "$d" ]; then IL2CPP_DIR="$d"; break; fi
40+
done
41+
fi
42+
43+
MISSING=""
44+
[ -z "$EDITOR_APP" ] && MISSING="editor"
45+
[ "$BACKEND" = "IL2CPP" ] && [ -z "$IL2CPP_DIR" ] && MISSING="${MISSING:+$MISSING+}mac-il2cpp"
46+
if [ -n "$MISSING" ]; then
47+
echo "::error::Unity $UNITY_VERSION missing: $MISSING"
48+
ls -la /Applications/Unity/Hub/Editor/ 2>&1 || true
49+
"$HUB" -- --headless editors --installed 2>&1 || true
50+
exit 1
51+
fi
52+
53+
UNITY_PATH="$EDITOR_APP/Contents/MacOS/Unity"
54+
echo "Found Unity: $UNITY_PATH"
55+
[ -n "$IL2CPP_DIR" ] && echo "Found IL2CPP: $IL2CPP_DIR"
56+
echo "UNITY_PATH=$UNITY_PATH" >> "$GITHUB_ENV"
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Installs the Unity editor and (for IL2CPP cells) the windows-il2cpp module.
2+
# Idempotent. Sets UNITY_PATH in GITHUB_ENV so the playmode step picks it up.
3+
# Workflow caller: .github/workflows/test-audience-sample-app.yml (playmode job).
4+
#
5+
# Inputs (env): UNITY_VERSION, UNITY_CHANGESET, BACKEND.
6+
7+
$ErrorActionPreference = 'Continue'
8+
$hub = "C:\Program Files\Unity Hub\Unity Hub.exe"
9+
10+
Write-Output "::group::install editor"
11+
& $hub -- --headless install --version $env:UNITY_VERSION --changeset $env:UNITY_CHANGESET --architecture x86_64 2>&1 | Write-Output
12+
if ($LASTEXITCODE -ne 0) { Write-Output "(install non-zero, OK if 'Editor already installed in this location')" }
13+
$global:LASTEXITCODE = 0
14+
Write-Output "::endgroup::"
15+
16+
if ($env:BACKEND -eq 'IL2CPP') {
17+
Write-Output "::group::install windows-il2cpp module"
18+
& $hub -- --headless install-modules --version $env:UNITY_VERSION --changeset $env:UNITY_CHANGESET --architecture x86_64 --module windows-il2cpp 2>&1 | Write-Output
19+
if ($LASTEXITCODE -ne 0) { Write-Output "(install-modules non-zero, OK if 'No modules found to install')" }
20+
$global:LASTEXITCODE = 0
21+
Write-Output "::endgroup::"
22+
}
23+
24+
$editor = "C:\Program Files\Unity\Hub\Editor\$env:UNITY_VERSION\Editor\Unity.exe"
25+
$il2cpp = "C:\Program Files\Unity\Hub\Editor\$env:UNITY_VERSION\Editor\Data\PlaybackEngines\windowsstandalonesupport\Variations\win64_player_nondevelopment_il2cpp"
26+
$missing = @()
27+
if (-not (Test-Path $editor)) { $missing += 'editor' }
28+
if ($env:BACKEND -eq 'IL2CPP' -and -not (Test-Path $il2cpp)) { $missing += 'windows-il2cpp' }
29+
if ($missing.Count -gt 0) {
30+
Write-Output "::error::Unity $env:UNITY_VERSION missing: $($missing -join '+')"
31+
Get-ChildItem "C:\Program Files\Unity\Hub\Editor\" -ErrorAction SilentlyContinue | Format-Table
32+
& $hub -- --headless editors --installed
33+
exit 1
34+
}
35+
36+
Write-Output "Found Unity: $editor"
37+
if ($env:BACKEND -eq 'IL2CPP') { Write-Output "Found IL2CPP: $il2cpp" }
38+
39+
"UNITY_PATH=$editor" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"unity_versions": [
3+
{ "version": "2021.3.45f2", "changeset": "88f88f591b2e" },
4+
{ "version": "6000.4.0f1", "changeset": "8cf496087c8f" },
5+
{ "version": "2022.3.62f2", "changeset": "7670c08855a9" }
6+
],
7+
"scripting_backends": ["IL2CPP", "Mono2x"],
8+
"desktop_targets": [
9+
{ "target": "StandaloneWindows64", "runner": ["self-hosted", "Windows", "X64"], "install_unity_script": ".github/scripts/audience/install-unity-windows.ps1", "run_playmode_script": ".github/scripts/audience/playmode-windows.ps1" },
10+
{ "target": "StandaloneOSX", "runner": ["self-hosted", "macOS", "ARM64"], "install_unity_script": ".github/scripts/audience/install-unity-macos.sh", "run_playmode_script": ".github/scripts/audience/playmode-macos.sh" },
11+
{ "target": "StandaloneLinux64", "runner": "ubuntu-latest-8-cores", "install_unity_script": "", "run_playmode_script": ".github/scripts/audience/playmode-linux.sh" }
12+
],
13+
"mobile_targets": [
14+
{ "target": "Android", "build_player_method": "AndroidBuilder.Build" },
15+
{ "target": "iOS", "build_player_method": "IosBuilder.Build" }
16+
],
17+
"pr_exclude": [
18+
{ "unity": { "version": "2022.3.62f2", "changeset": "7670c08855a9" } }
19+
]
20+
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
#!/bin/bash
2+
# Audience SDK PlayMode test runner for Linux: in-container body.
3+
# Runs inside the unityci/editor:ubuntu-X-linux-il2cpp-3 container.
4+
# Caller: .github/scripts/audience/playmode-linux.sh (host-side docker wrapper).
5+
6+
set -uo pipefail
7+
8+
LOG=/github/workspace/artifacts/unity.log
9+
ACTIVATION_LOG=/github/workspace/artifacts/activation.log
10+
RESULTS=/github/workspace/artifacts/test-results.xml
11+
PROJECT=/github/workspace/examples/audience
12+
13+
test_rc=1
14+
15+
activate_license() {
16+
unity-editor -batchmode -nographics -quit \
17+
-username "$UNITY_EMAIL" \
18+
-password "$UNITY_PASSWORD" \
19+
-serial "$UNITY_SERIAL" \
20+
-logFile - 2>&1 | tee "$ACTIVATION_LOG" || true
21+
22+
if grep -qE "License activation has failed|\[Licensing::Client\] Error: Code [0-9]+" "$ACTIVATION_LOG"; then
23+
echo "::error::Unity license activation failed."
24+
exit 1
25+
fi
26+
if ! grep -qE "Successfully activated the entitlement license" "$ACTIVATION_LOG"; then
27+
echo "::error::Unity license activation: no success marker in log."
28+
exit 1
29+
fi
30+
}
31+
32+
run_tests_with_watchdog() {
33+
# xvfb-run gives Unity a virtual X display. UI Toolkit needs GLX + render;
34+
# llvmpipe in the image provides software OpenGL so no GPU is needed.
35+
# -force-glcore skips the Unity 6 Vulkan init and matches the Unity 2021.3 default path.
36+
xvfb-run -a --server-args="-ac +extension GLX +render -noreset" -- \
37+
unity-editor \
38+
-batchmode \
39+
-force-glcore \
40+
-screen-fullscreen 0 \
41+
-screen-width 320 \
42+
-screen-height 240 \
43+
-projectPath "$PROJECT" \
44+
-runTests \
45+
-testPlatform StandaloneLinux64 \
46+
-testResults "$RESULTS" \
47+
-logFile "$LOG" &
48+
local unity_pid=$!
49+
50+
# Mirror Unity log to job stdout while the editor is alive.
51+
tail --pid=$unity_pid -F "$LOG" 2>/dev/null &
52+
53+
# Watchdog (vs fixed timeout) because per-version run length varies wildly:
54+
# Unity 2021.3 cells finish in ~2 min, Unity 6 in ~22 min, and Unity 6 has a
55+
# known post-test shutdown hang. SIGTERM 30 s after "Test run completed" so
56+
# each cell exits as soon as its suite finishes. 40 min hard cap as fallback.
57+
local deadline=$((SECONDS + 2400))
58+
local flush_deadline=0
59+
local kill_reason=""
60+
while kill -0 "$unity_pid" 2>/dev/null; do
61+
if [ "$SECONDS" -ge "$deadline" ]; then
62+
kill_reason="hard-cap-40m"
63+
break
64+
fi
65+
if [ "$flush_deadline" -eq 0 ] && grep -q "Test run completed" "$LOG" 2>/dev/null; then
66+
flush_deadline=$((SECONDS + 30))
67+
echo "[watchdog] saw \"Test run completed\" at ${SECONDS}s; SIGTERM after 30s flush window"
68+
fi
69+
if [ "$flush_deadline" -gt 0 ] && [ "$SECONDS" -ge "$flush_deadline" ]; then
70+
kill_reason="flush-window-elapsed"
71+
break
72+
fi
73+
sleep 5
74+
done
75+
76+
if [ -n "$kill_reason" ]; then
77+
echo "[watchdog] sending SIGTERM to Unity (reason: $kill_reason)"
78+
kill -TERM "$unity_pid" 2>/dev/null || true
79+
# 15 s grace, then SIGKILL.
80+
for _ in 1 2 3; do
81+
kill -0 "$unity_pid" 2>/dev/null || break
82+
sleep 5
83+
done
84+
if kill -0 "$unity_pid" 2>/dev/null; then
85+
echo "[watchdog] SIGTERM not honored, sending SIGKILL"
86+
kill -KILL "$unity_pid" 2>/dev/null || true
87+
fi
88+
fi
89+
90+
wait "$unity_pid" 2>/dev/null
91+
test_rc=$?
92+
if [ "$kill_reason" = "hard-cap-40m" ]; then
93+
echo "::warning::Unity hit the 40 min hard cap without logging \"Test run completed\". Inspect Player.log."
94+
fi
95+
}
96+
97+
capture_player_log() {
98+
# Player runs in a separate process from the editor; copy its Player.log so
99+
# HTTP traces and OnError fires are captured. Glob across companies / products.
100+
find /root/.config/unity3d -name "Player.log" 2>/dev/null | while IFS= read -r f; do
101+
co=$(basename "$(dirname "$(dirname "$f")")")
102+
pr=$(basename "$(dirname "$f")")
103+
cp "$f" "/github/workspace/artifacts/Player-${co}-${pr}.log" 2>/dev/null || true
104+
done
105+
}
106+
107+
return_license() {
108+
# Always return the seat to keep the activation pool from exhausting on reruns.
109+
unity-editor -batchmode -nographics -quit -returnlicense -logFile - 2>&1 || true
110+
}
111+
112+
activate_license
113+
run_tests_with_watchdog
114+
capture_player_log
115+
return_license
116+
117+
# Unity exits 2 on test failure or inconclusive; propagate so the step fails.
118+
exit "$test_rc"
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#!/bin/bash
2+
# Audience SDK PlayMode test runner for Linux: host-side docker wrapper.
3+
# Runs unityci/editor with the env and volume mounts the inner
4+
# playmode-linux-container.sh expects. Lives outside the container so the
5+
# workflow can launch all 3 desktop platforms from one matrix-shared.json entry.
6+
#
7+
# Manual docker run because game-ci/unity-test-runner@v4 hardcodes
8+
# -nographics. Without a virtual display every PlayMode test comes back
9+
# inconclusive, and the action's USE_EXIT_CODE=false suppresses Unity
10+
# exit 2, so cells went silently green.
11+
#
12+
# Workflow caller: .github/workflows/test-audience-sample-app.yml (playmode job).
13+
# Inputs (env): UNITY_VERSION, UNITY_EMAIL, UNITY_PASSWORD, UNITY_SERIAL,
14+
# AUDIENCE_TEST_PUBLISHABLE_KEY, AUDIENCE_SCRIPTING_BACKEND.
15+
16+
set -uo pipefail
17+
mkdir -p artifacts
18+
19+
docker run --rm \
20+
--workdir /github/workspace \
21+
--env UNITY_EMAIL --env UNITY_PASSWORD --env UNITY_SERIAL \
22+
--env AUDIENCE_TEST_PUBLISHABLE_KEY --env AUDIENCE_SCRIPTING_BACKEND \
23+
--env AUDIENCE_TEST_RUN_ID --env AUDIENCE_TEST_CELL_ID --env AUDIENCE_TEST_JOB_ID \
24+
--volume "$PWD":/github/workspace:z \
25+
--cpus=8 --memory=30487m \
26+
"unityci/editor:ubuntu-${UNITY_VERSION}-linux-il2cpp-3" \
27+
bash /github/workspace/.github/scripts/audience/playmode-linux-container.sh
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#!/bin/bash
2+
# Runs the audience PlayMode tests on macOS. Captures Player.log into artifacts/.
3+
# Surfaces Unity compile errors as ::error:: annotations.
4+
# Workflow caller: .github/workflows/test-audience-sample-app.yml (playmode job).
5+
#
6+
# Inputs (env): UNITY_PATH (set by install-unity-macos.sh), TARGET.
7+
8+
set -uo pipefail
9+
10+
LOG=artifacts/unity.log
11+
RESULTS="$(pwd)/artifacts/test-results.xml"
12+
13+
mkdir -p artifacts
14+
15+
# Tee Unity stdout to artifacts/unity.log so the annotation step has a file
16+
# to scan; pipefail propagates Unity's exit code through tee.
17+
"$UNITY_PATH" \
18+
-batchmode -nographics \
19+
-projectPath examples/audience \
20+
-runTests \
21+
-testPlatform "$TARGET" \
22+
-testResults "$RESULTS" \
23+
-logFile - 2>&1 | tee "$LOG"
24+
test_rc=${PIPESTATUS[0]}
25+
26+
# Player runs as a separate process; copy its Player.log so HTTP traces and
27+
# OnError fires are captured. Glob across companies and products.
28+
src="$HOME/Library/Logs"
29+
if [ -d "$src" ]; then
30+
find "$src" -name "Player.log" 2>/dev/null | while IFS= read -r f; do
31+
cp "$f" "artifacts/Player-$(basename "$(dirname "$f")").log" 2>/dev/null || true
32+
done
33+
fi
34+
35+
# Promote Unity compile errors to ::error:: annotations. Sanitize '::' so log
36+
# lines containing workflow commands cannot terminate the annotation early.
37+
if [ -f "$LOG" ]; then
38+
grep -E '(error CS[0-9]+:|Compilation failed:)' "$LOG" | sort -u | while IFS= read -r line; do
39+
trimmed="${line#"${line%%[![:space:]]*}"}"
40+
sanitized="${trimmed//::/%3A%3A}"
41+
echo "::error::$sanitized"
42+
done || true
43+
fi
44+
45+
exit "$test_rc"

0 commit comments

Comments
 (0)