ReviewOS

also looking at this

craft-native/craft

fix(mobile-e2e): launch iOS apps without a pty, so a cold simulator cannot eat the budget

#212
Merged glennmichael123 wants to merge fix/mobile-e2e-ios-launch into main
5 files +74 -23
packages/ios/fixtures/zig-slice/build-and-run.shmodified+28-5
Changes to packages/ios/fixtures/zig-slice/build-and-run.sh
@@ -22,6 +22,9 @@ echo "==> building the craft iOS simulator library"
2222SDK="$(xcrun --sdk iphonesimulator --show-sdk-path)"
2323APP="$OUT/CraftSlice.app"
2424rm -rf "$OUT"; mkdir -p "$APP"
25# Absolute, because the app writes its console to paths under here and resolves
26# them from its own working directory, not this script's.
27OUT="$(cd "$OUT" && pwd)"; APP="$OUT/CraftSlice.app"
2528
2629echo "==> compiling the fixture"
2730# The ObjC translation units first, then swiftc drives the link. swiftc is the
@@ -117,9 +120,22 @@ xcrun simctl location "$UDID" set 37.3317,-122.0307
117120# i=68 assertion below fails loudly, which is the right way round.
118121xcrun simctl privacy "$UDID" grant kTCCServiceSpeechRecognition "$BUNDLE_ID" 2>/dev/null || true
119122
123# The app's stdout and stderr, each to a file, gathered into $LOG as it runs.
124#
125# Not `simctl launch --console-pty`, for the reason scripts/mobile-e2e/ios.ts
126# gives: the first pty launch after a cold boot took about 200 seconds to start
127# the app, against 10 for a plain launch, and that wait came out of this
128# script's budget. `NSUnbufferedIO=YES` is what lets a file see the output
129# while the app runs; without it nothing arrives. And no pty means no CRLF, so
130# the lines grepped below end where they appear to.
131STDOUT_LOG="$OUT/app-stdout.log"
132STDERR_LOG="$OUT/app-stderr.log"
120133LOG="$OUT/console.log"
121xcrun simctl launch --console-pty "$UDID" "$BUNDLE_ID" > "$LOG" 2>&1 &
122LAUNCH_PID=$!
134: > "$LOG"
135SIMCTL_CHILD_NSUnbufferedIO=YES xcrun simctl launch --terminate-running-process \
136 --stdout="$STDOUT_LOG" --stderr="$STDERR_LOG" "$UDID" "$BUNDLE_ID"
137
138gather_log() { cat "$STDOUT_LOG" "$STDERR_LOG" > "$LOG" 2>/dev/null || true; }
123139
124140# The round trip is fast, but a cold simulator is not. Poll rather than sleep a
125141# fixed amount, so a slow boot does not read as a failure.
@@ -141,6 +157,7 @@ DEADLINE=$(( $(date +%s) + SLICE_TIMEOUT ))
141157
142158missing_ids() {
143159 local missing=""
160 gather_log
144161 for id in $AWAITED_IDS; do
145162 # ERE with an explicit boundary rather than \b, which is a GNU
146163 # extension this script cannot count on, and rather than a bare
@@ -159,12 +176,13 @@ while :; do
159176 echo "FAIL: timed out after ${SLICE_TIMEOUT}s waiting for:$MISSING"
160177 echo " The app never got that far — this is a timeout, not a wrong answer."
161178 echo " Raise CRAFT_SLICE_TIMEOUT if the machine is simply slow."
162 kill "$LAUNCH_PID" 2>/dev/null || true
179 xcrun simctl terminate "$UDID" "$BUNDLE_ID" 2>/dev/null || true
163180 exit 1
164181 fi
165182 sleep 1
166183done
167kill "$LAUNCH_PID" 2>/dev/null || true
184xcrun simctl terminate "$UDID" "$BUNDLE_ID" 2>/dev/null || true
185gather_log
168186
169187echo "==> console"
170188cat "$LOG" || true
@@ -200,7 +218,12 @@ echo "==> assertions"
200218PLAIN="$OUT/console.plain"
201219sed -e $'s/\x1b\[[0-9;]*m//g' -e 's/\r$//' "$LOG" > "$PLAIN"
202220
203count() { grep -cE "craft-bridge dispatch t=mobile a=[A-Za-z]+ i=$1\$" "$PLAIN" || true; }
221# The same boundary missing_ids waits on. This used to demand the id end the
222# line, while the wait accepted any non-digit after it, so a line the loop had
223# already counted as arrived could fail its assertion here: on main, run
224# 35094828558 waited for i=76, found it, and then reported that
225# getCurrentPosition "did not return the simulated coordinate".
226count() { grep -cE "craft-bridge dispatch t=mobile a=[A-Za-z]+ i=$1(\$|[^0-9])" "$PLAIN" || true; }
204227
205228C1="$(count 1)"; C2="$(count 2)"; C3="$(count 3)"
206229