|
| 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" |
0 commit comments