diff --git a/scripts/run-ios-ui-tests.sh b/scripts/run-ios-ui-tests.sh index 4b826b4a88..b47b39764d 100755 --- a/scripts/run-ios-ui-tests.sh +++ b/scripts/run-ios-ui-tests.sh @@ -75,6 +75,33 @@ if ! command -v xcrun >/dev/null 2>&1; then exit 3 fi +HOST_ARCH="$(uname -m)" +ARM64_AVAILABLE=0 +if [ "$HOST_ARCH" = "x86_64" ]; then + ARM64_AVAILABLE="$(sysctl -n hw.optional.arm64 2>/dev/null || echo 0)" +fi +declare -a XCODE_ARCH_PREFIX=() +if [ "$HOST_ARCH" = "x86_64" ] && [ "$ARM64_AVAILABLE" = "1" ]; then + ri_log "Detected Rosetta shell; running Xcode tools under arm64" + XCODE_ARCH_PREFIX=(arch -arm64) +fi + +xcodebuild_cmd() { + if [ ${#XCODE_ARCH_PREFIX[@]} -gt 0 ]; then + "${XCODE_ARCH_PREFIX[@]}" xcodebuild "$@" + else + xcodebuild "$@" + fi +} + +xcrun_cmd() { + if [ ${#XCODE_ARCH_PREFIX[@]} -gt 0 ]; then + "${XCODE_ARCH_PREFIX[@]}" xcrun "$@" + else + xcrun "$@" + fi +} + JAVA17_BIN="$JAVA17_HOME/bin/java" cn1ss_setup "$JAVA17_BIN" "$CN1SS_HELPER_SOURCE_DIR" @@ -168,7 +195,7 @@ normalize_destination() { auto_select_destination() { local show_dest rc=0 best_line="" best_key="" line payload platform id name os priority key part value set +e - show_dest="$(xcodebuild -workspace "$WORKSPACE_PATH" -scheme "$SCHEME" -sdk iphonesimulator -showdestinations 2>/dev/null)" + show_dest="$(xcodebuild_cmd -workspace "$WORKSPACE_PATH" -scheme "$SCHEME" -sdk iphonesimulator -showdestinations 2>/dev/null)" rc=$? set -e @@ -237,6 +264,34 @@ auto_select_destination() { return $rc } +auto_select_destination_retry() { + local attempt=1 + local selected="" + while [ "$attempt" -le 3 ]; do + selected="$(auto_select_destination || true)" + if [ -n "$selected" ]; then + printf '%s\n' "$selected" + return 0 + fi + ri_log "Auto-select attempt $attempt did not return a destination; retrying" >&2 + sleep 5 + attempt=$((attempt + 1)) + done + return 1 +} + +destination_visible_to_xcodebuild() { + local destination="$1" + local id="" + id="$(printf '%s\n' "$destination" | sed -n 's/.*id=\([^,]*\).*/\1/p' | tr -d '\r[:space:]')" + [ -z "$id" ] && return 1 + set +e + xcodebuild_cmd -workspace "$WORKSPACE_PATH" -scheme "$SCHEME" -sdk iphonesimulator -showdestinations 2>/dev/null | grep -q "$id" + local rc=$? + set -e + return $rc +} + fallback_sim_destination() { if ! command -v xcrun >/dev/null 2>&1; then return @@ -304,7 +359,7 @@ fallback_sim_destination() { [ -n "$current_version" ] && best_line="$best_line,OS=$current_version" best_line="$best_line,name=$name" fi - done < <(xcrun simctl list devices 2>/dev/null) + done < <(xcrun_cmd simctl list devices 2>/dev/null) if [ -n "$best_line" ]; then printf '%s\n' "$best_line" @@ -315,7 +370,7 @@ fallback_sim_destination() { SIM_DESTINATION="${IOS_SIM_DESTINATION:-}" if [ -z "$SIM_DESTINATION" ]; then - SELECTED_DESTINATION="$(auto_select_destination || true)" + SELECTED_DESTINATION="$(auto_select_destination_retry || true)" if [ -n "${SELECTED_DESTINATION:-}" ]; then SIM_DESTINATION="$SELECTED_DESTINATION" ri_log "Auto-selected simulator destination '$SIM_DESTINATION'" @@ -335,17 +390,36 @@ if [ -z "$SIM_DESTINATION" ]; then fi SIM_DESTINATION="$(normalize_destination "$SIM_DESTINATION")" +BUILD_DESTINATION="$SIM_DESTINATION" -# Extract UDID and prefer id-only destination to avoid OS/SDK mismatches +# Extract UDID and prefer platform+id destination for xcodebuild stability SIM_UDID="$(printf '%s\n' "$SIM_DESTINATION" | sed -n 's/.*id=\([^,]*\).*/\1/p' | tr -d '\r[:space:]')" if [ -n "$SIM_UDID" ]; then ri_log "Booting simulator $SIM_UDID" BOOT_START=$(date +%s) - xcrun simctl boot "$SIM_UDID" >/dev/null 2>&1 || true - xcrun simctl bootstatus "$SIM_UDID" -b + xcrun_cmd simctl boot "$SIM_UDID" >/dev/null 2>&1 || true + xcrun_cmd simctl bootstatus "$SIM_UDID" -b BOOT_END=$(date +%s) echo "Simulator Boot : $(( (BOOT_END - BOOT_START) * 1000 )) ms" >> "$ARTIFACTS_DIR/ios-test-stats.txt" - SIM_DESTINATION="id=$SIM_UDID" + SIM_DESTINATION="platform=iOS Simulator,id=$SIM_UDID" + BUILD_DESTINATION="$SIM_DESTINATION" +fi +if ! destination_visible_to_xcodebuild "$SIM_DESTINATION"; then + ri_log "Selected simulator destination not visible to xcodebuild; attempting re-selection" + SELECTED_DESTINATION="$(auto_select_destination_retry || true)" + if [ -n "${SELECTED_DESTINATION:-}" ]; then + SIM_DESTINATION="$(normalize_destination "$SELECTED_DESTINATION")" + SIM_UDID="$(printf '%s\n' "$SIM_DESTINATION" | sed -n 's/.*id=\([^,]*\).*/\1/p' | tr -d '\r[:space:]')" + if [ -n "$SIM_UDID" ]; then + SIM_DESTINATION="platform=iOS Simulator,id=$SIM_UDID" + fi + BUILD_DESTINATION="$SIM_DESTINATION" + ri_log "Re-selected simulator destination '$SIM_DESTINATION'" + else + ri_log "Auto-selection still did not return a destination; continuing with '$SIM_DESTINATION'" + BUILD_DESTINATION="" + ri_log "Using default simulator destination for build" + fi fi ri_log "Running DeviceRunner on destination '$SIM_DESTINATION'" @@ -355,23 +429,67 @@ BUILD_LOG="$ARTIFACTS_DIR/xcodebuild-build.log" ri_log "Building simulator app with xcodebuild" COMPILE_START=$(date +%s) -if ! xcodebuild \ - -workspace "$WORKSPACE_PATH" \ - -scheme "$SCHEME" \ - -sdk iphonesimulator \ - -configuration Debug \ - -destination "$SIM_DESTINATION" \ - -destination-timeout 120 \ - -derivedDataPath "$DERIVED_DATA_DIR" \ - build | tee "$BUILD_LOG"; then - ri_log "STAGE:XCODE_BUILD_FAILED -> See $BUILD_LOG" - exit 10 +build_with_destination() { + local dest="$1" + local args=( + -workspace "$WORKSPACE_PATH" + -scheme "$SCHEME" + -sdk iphonesimulator + -configuration Debug + -derivedDataPath "$DERIVED_DATA_DIR" + build + ) + if [ -n "$dest" ]; then + args=( + -workspace "$WORKSPACE_PATH" + -scheme "$SCHEME" + -sdk iphonesimulator + -configuration Debug + -destination "$dest" + -destination-timeout 120 + -derivedDataPath "$DERIVED_DATA_DIR" + build + ) + fi + xcodebuild_cmd "${args[@]}" | tee "$BUILD_LOG" +} + +if ! build_with_destination "$BUILD_DESTINATION"; then + if grep -q "Unable to find a destination matching the provided destination specifier" "$BUILD_LOG"; then + ri_log "xcodebuild could not find destination; retrying after re-selection" + SELECTED_DESTINATION="$(auto_select_destination_retry || true)" + if [ -n "${SELECTED_DESTINATION:-}" ]; then + SIM_DESTINATION="$(normalize_destination "$SELECTED_DESTINATION")" + SIM_UDID="$(printf '%s\n' "$SIM_DESTINATION" | sed -n 's/.*id=\([^,]*\).*/\1/p' | tr -d '\r[:space:]')" + if [ -n "$SIM_UDID" ]; then + SIM_DESTINATION="platform=iOS Simulator,id=$SIM_UDID" + fi + BUILD_DESTINATION="$SIM_DESTINATION" + ri_log "Retrying xcodebuild with destination '$BUILD_DESTINATION'" + if ! build_with_destination "$BUILD_DESTINATION"; then + ri_log "Retrying xcodebuild with default simulator destination" + if ! build_with_destination ""; then + ri_log "STAGE:XCODE_BUILD_FAILED -> See $BUILD_LOG" + exit 10 + fi + fi + else + ri_log "Retrying xcodebuild with default simulator destination" + if ! build_with_destination ""; then + ri_log "STAGE:XCODE_BUILD_FAILED -> See $BUILD_LOG" + exit 10 + fi + fi + else + ri_log "STAGE:XCODE_BUILD_FAILED -> See $BUILD_LOG" + exit 10 + fi fi COMPILE_END=$(date +%s) COMPILATION_TIME=$((COMPILE_END - COMPILE_START)) ri_log "Compilation time: ${COMPILATION_TIME}s" -BUILD_SETTINGS="$(xcodebuild -workspace "$WORKSPACE_PATH" -scheme "$SCHEME" -sdk iphonesimulator -configuration Debug -showBuildSettings 2>/dev/null || true)" +BUILD_SETTINGS="$(xcodebuild_cmd -workspace "$WORKSPACE_PATH" -scheme "$SCHEME" -sdk iphonesimulator -configuration Debug -showBuildSettings 2>/dev/null || true)" TARGET_BUILD_DIR="$(printf '%s\n' "$BUILD_SETTINGS" | awk -F' = ' '/ TARGET_BUILD_DIR /{print $2; exit}')" WRAPPER_NAME="$(printf '%s\n' "$BUILD_SETTINGS" | awk -F' = ' '/ WRAPPER_NAME /{print $2; exit}')" if [ -z "$WRAPPER_NAME" ]; then @@ -436,7 +554,7 @@ APP_PROCESS_NAME="${WRAPPER_NAME%.app}" resolved_id="$(trim_whitespace "$id_part")" break fi - done < <(xcrun simctl list devices 2>/dev/null) + done < <(xcrun_cmd simctl list devices 2>/dev/null) SIM_DEVICE_ID="$resolved_id" fi fi @@ -444,13 +562,13 @@ APP_PROCESS_NAME="${WRAPPER_NAME%.app}" if [ -n "$SIM_DEVICE_ID" ]; then ri_log "Booting simulator $SIM_DEVICE_ID" BOOT_START=$(date +%s) - xcrun simctl boot "$SIM_DEVICE_ID" >/dev/null 2>&1 || true - xcrun simctl bootstatus "$SIM_DEVICE_ID" -b + xcrun_cmd simctl boot "$SIM_DEVICE_ID" >/dev/null 2>&1 || true + xcrun_cmd simctl bootstatus "$SIM_DEVICE_ID" -b BOOT_END=$(date +%s) echo "Simulator Boot (Run) : $(( (BOOT_END - BOOT_START) * 1000 )) ms" >> "$ARTIFACTS_DIR/ios-test-stats.txt" else ri_log "Warning: simulator UDID not resolved; relying on default booted device" - xcrun simctl bootstatus booted -b || true + xcrun_cmd simctl bootstatus booted -b || true fi LOG_STREAM_PID=0 @@ -460,22 +578,22 @@ APP_PROCESS_NAME="${WRAPPER_NAME%.app}" wait "$LOG_STREAM_PID" 2>/dev/null || true fi if [ -n "$SIM_DEVICE_ID" ] && [ -n "$BUNDLE_IDENTIFIER" ]; then - xcrun simctl terminate "$SIM_DEVICE_ID" "$BUNDLE_IDENTIFIER" >/dev/null 2>&1 || true + xcrun_cmd simctl terminate "$SIM_DEVICE_ID" "$BUNDLE_IDENTIFIER" >/dev/null 2>&1 || true fi } trap cleanup EXIT ri_log "Streaming simulator logs to $TEST_LOG" if [ -n "$SIM_DEVICE_ID" ]; then - xcrun simctl terminate "$SIM_DEVICE_ID" "$BUNDLE_IDENTIFIER" >/dev/null 2>&1 || true - xcrun simctl uninstall "$SIM_DEVICE_ID" "$BUNDLE_IDENTIFIER" >/dev/null 2>&1 || true + xcrun_cmd simctl terminate "$SIM_DEVICE_ID" "$BUNDLE_IDENTIFIER" >/dev/null 2>&1 || true + xcrun_cmd simctl uninstall "$SIM_DEVICE_ID" "$BUNDLE_IDENTIFIER" >/dev/null 2>&1 || true - xcrun simctl spawn "$SIM_DEVICE_ID" \ + xcrun_cmd simctl spawn "$SIM_DEVICE_ID" \ log stream --style json --level debug \ --predicate 'eventMessage CONTAINS "CN1SS"' \ > "$TEST_LOG" 2>&1 & else - xcrun simctl spawn booted log stream --style compact --level debug --predicate 'composedMessage CONTAINS "CN1SS"' > "$TEST_LOG" 2>&1 & + xcrun_cmd simctl spawn booted log stream --style compact --level debug --predicate 'composedMessage CONTAINS "CN1SS"' > "$TEST_LOG" 2>&1 & fi LOG_STREAM_PID=$! sleep 2 @@ -487,7 +605,7 @@ APP_PROCESS_NAME="${WRAPPER_NAME%.app}" local attempt=1 while true; do local output - if output="$(xcrun simctl launch "$target" "$BUNDLE_IDENTIFIER" 2>&1)"; then + if output="$(xcrun_cmd simctl launch "$target" "$BUNDLE_IDENTIFIER" 2>&1)"; then printf '%s\n' "$output" >> "$LAUNCH_LOG" return 0 fi @@ -496,7 +614,7 @@ APP_PROCESS_NAME="${WRAPPER_NAME%.app}" return 1 fi ri_log "simctl launch failed (attempt $attempt), retrying" - xcrun simctl bootstatus "$target" -b >/dev/null 2>&1 || true + xcrun_cmd simctl bootstatus "$target" -b >/dev/null 2>&1 || true sleep 5 attempt=$((attempt + 1)) done @@ -505,7 +623,7 @@ APP_PROCESS_NAME="${WRAPPER_NAME%.app}" ri_log "Installing simulator app bundle" INSTALL_START=$(date +%s) if [ -n "$SIM_DEVICE_ID" ]; then - if ! xcrun simctl install "$SIM_DEVICE_ID" "$APP_BUNDLE_PATH"; then + if ! xcrun_cmd simctl install "$SIM_DEVICE_ID" "$APP_BUNDLE_PATH"; then ri_log "FATAL: simctl install failed" exit 11 fi @@ -518,7 +636,7 @@ APP_PROCESS_NAME="${WRAPPER_NAME%.app}" fi LAUNCH_END=$(date +%s) else - if ! xcrun simctl install booted "$APP_BUNDLE_PATH"; then + if ! xcrun_cmd simctl install booted "$APP_BUNDLE_PATH"; then ri_log "FATAL: simctl install failed" exit 11 fi @@ -560,13 +678,13 @@ wait "$LOG_STREAM_PID" 2>/dev/null || true LOG_STREAM_PID=0 FALLBACK_LOG="$ARTIFACTS_DIR/device-runner-fallback.log" -xcrun simctl spawn "$SIM_DEVICE_ID" \ +xcrun_cmd simctl spawn "$SIM_DEVICE_ID" \ log show --style syslog --last 30m \ --predicate 'eventMessage CONTAINS "CN1SS"' \ > "$FALLBACK_LOG" 2>/dev/null || true if [ -n "$SIM_DEVICE_ID" ]; then - xcrun simctl terminate "$SIM_DEVICE_ID" "$BUNDLE_IDENTIFIER" >/dev/null 2>&1 || true + xcrun_cmd simctl terminate "$SIM_DEVICE_ID" "$BUNDLE_IDENTIFIER" >/dev/null 2>&1 || true fi declare -a CN1SS_SOURCES=("SIMLOG:$TEST_LOG")