91e75e620b
CI: cua-driver distro-compat matrix / Resolve release version (push) Waiting to run
CI: cua-driver distro-compat matrix / debian:12 (glibc 2.36) (push) Blocked by required conditions
CI: cua-driver distro-compat matrix / fedora:41 (glibc 2.40) (push) Blocked by required conditions
CI: cua-driver distro-compat matrix / rockylinux:9 (glibc 2.34) (push) Blocked by required conditions
CI: cua-driver distro-compat matrix / ubuntu:22.04 (glibc 2.35) (push) Blocked by required conditions
CI: cua-driver distro-compat matrix / ubuntu:24.04 (glibc 2.39) (push) Blocked by required conditions
CI: cua-driver distro-compat matrix / Distro compat summary (push) Blocked by required conditions
CI: Nix Linux Rust source / Nix / compositor build (push) Waiting to run
CI: Nix Linux Rust source / Nix / driver package (push) Waiting to run
CI: Nix Linux Rust source / Nix / Rust unit tests (push) Waiting to run
CI: Rust Linux unit / Rust Linux unit and compile (push) Waiting to run
CI: Rust Windows unit / Rust Windows unit and compile (push) Waiting to run
CI: SPDX Headers / Check SPDX headers (warn-only) (push) Waiting to run
CD: Docs MCP Server / build (linux/amd64) (push) Waiting to run
CD: Docs MCP Server / build (linux/arm64) (push) Waiting to run
CD: Docs MCP Server / merge (push) Blocked by required conditions
242 lines
8.6 KiB
Bash
Executable File
242 lines
8.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Run the canonical Rust desktop matrix in a logged-in macOS user session.
|
|
# macOS harness tests use the installed, TCC-authorized cua-driver daemon path.
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
REPO_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"
|
|
DRIVER_ROOT="${REPO_ROOT}/libs/cua-driver"
|
|
RUST_ROOT="${DRIVER_ROOT}/rust"
|
|
SUITE="${CUA_E2E_INTERNAL_LANE:-all}"
|
|
BUILD_FIXTURES=1
|
|
|
|
usage() {
|
|
cat <<'EOF'
|
|
Usage: run-rust-e2e.sh [--no-build]
|
|
|
|
Run from a logged-in macOS desktop after install-local and TCC authorization.
|
|
The testkit proxies MCP calls through the installed CuaDriver daemon.
|
|
The contributor-facing command always runs the complete matrix.
|
|
EOF
|
|
}
|
|
|
|
while (($#)); do
|
|
case "$1" in
|
|
--no-build) BUILD_FIXTURES=0 ;;
|
|
-h|--help) usage; exit 0 ;;
|
|
*) echo "unknown argument: $1" >&2; usage >&2; exit 2 ;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
case "$SUITE" in
|
|
shared|native|capture|all) ;;
|
|
*) echo "unsupported internal lane: $SUITE" >&2; exit 2 ;;
|
|
esac
|
|
|
|
if ! git -C "${REPO_ROOT}" diff --quiet || ! git -C "${REPO_ROOT}" diff --cached --quiet; then
|
|
echo "macOS canonical E2E requires a clean tracked working tree" >&2
|
|
exit 2
|
|
fi
|
|
if [[ -z "${CUA_E2E_SOURCE_SHA:-}" ]]; then
|
|
CUA_E2E_SOURCE_SHA="$(git -C "${REPO_ROOT}" rev-parse HEAD)"
|
|
fi
|
|
if [[ ! "${CUA_E2E_SOURCE_SHA}" =~ ^[0-9a-fA-F]{40}$ ]]; then
|
|
echo "CUA_E2E_SOURCE_SHA must be a full 40-character commit SHA" >&2
|
|
exit 2
|
|
fi
|
|
export CUA_E2E_SOURCE_SHA
|
|
|
|
ARTIFACT_DIR="${REPO_ROOT}/artifacts/cua-driver/macos"
|
|
RECORDING_ROOT="${ARTIFACT_DIR}/recordings"
|
|
if [[ -e "${RECORDING_ROOT}" ]]; then
|
|
RECORDING_ARCHIVE="$(mktemp -d "${TMPDIR:-/tmp}/cua-macos-e2e-recordings.XXXXXX")"
|
|
mv "${RECORDING_ROOT}" "${RECORDING_ARCHIVE}/recordings"
|
|
echo "Previous recordings preserved at ${RECORDING_ARCHIVE}/recordings"
|
|
fi
|
|
mkdir -p "${RECORDING_ROOT}"
|
|
RESULTS_FILE="${ARTIFACT_DIR}/results.jsonl"
|
|
DECLARATIONS_FILE="${ARTIFACT_DIR}/cases.jsonl"
|
|
ENVIRONMENT_FILE="${ARTIFACT_DIR}/environment.jsonl"
|
|
SUMMARY_FILE="${ARTIFACT_DIR}/summary.md"
|
|
mkdir -p "${ARTIFACT_DIR}"
|
|
: > "${DECLARATIONS_FILE}"
|
|
: > "${ENVIRONMENT_FILE}"
|
|
: > "${RESULTS_FILE}"
|
|
rm -f "${SUMMARY_FILE}"
|
|
|
|
export CUA_E2E_DECLARATIONS_FILE="${DECLARATIONS_FILE}"
|
|
export CUA_E2E_ENVIRONMENT_FILE="${ENVIRONMENT_FILE}"
|
|
export CUA_E2E_RESULTS_FILE="${RESULTS_FILE}"
|
|
export CUA_E2E_RECORDINGS_ROOT="${RECORDING_ROOT}"
|
|
export CUA_TEST_WORKSPACE_ROOT="${RUST_ROOT}"
|
|
export CUA_TEST_DRIVER_BIN="${RUST_ROOT}/target/release/cua-driver"
|
|
export CUA_TEST_APPS_ROOT="${RUST_ROOT}/test-apps"
|
|
export CUA_TEST_REQUIRE_FIXTURES=1
|
|
export CUA_TEST_DRIVER_STDERR=1
|
|
|
|
command -v ffmpeg >/dev/null || { echo "ffmpeg is required for E2E trajectory videos" >&2; exit 1; }
|
|
command -v ffprobe >/dev/null || { echo "ffprobe is required for E2E trajectory validation" >&2; exit 1; }
|
|
command -v jq >/dev/null || { echo "jq is required for E2E ownership validation" >&2; exit 1; }
|
|
|
|
if [[ "${BUILD_FIXTURES}" == 1 ]]; then
|
|
cargo build --release -p cua-driver --manifest-path "${RUST_ROOT}/Cargo.toml"
|
|
bash "${DRIVER_ROOT}/tests/fixtures/build/macos.sh"
|
|
fi
|
|
|
|
if [[ ! -x "${CUA_TEST_DRIVER_BIN}" ]]; then
|
|
echo "Required driver binary was not built: ${CUA_TEST_DRIVER_BIN}" >&2
|
|
exit 1
|
|
fi
|
|
|
|
required_fixtures=()
|
|
required_fixtures+=("${CUA_TEST_APPS_ROOT}/harness-electron/CuaTestHarness.Electron.app")
|
|
if [[ "${SUITE}" == shared || "${SUITE}" == all ]]; then
|
|
required_fixtures+=(
|
|
"${CUA_TEST_APPS_ROOT}/harness-tauri/CuaTestHarness.Tauri.app"
|
|
"${CUA_TEST_APPS_ROOT}/harness-wkwebview/CuaTestHarness.WKWebView.app"
|
|
)
|
|
fi
|
|
if [[ "${SUITE}" == native || "${SUITE}" == all ]]; then
|
|
required_fixtures+=(
|
|
"${CUA_TEST_APPS_ROOT}/harness-appkit/CuaTestHarness.AppKit.app"
|
|
"${CUA_TEST_APPS_ROOT}/harness-swiftui/CuaTestHarness.SwiftUI.app"
|
|
)
|
|
fi
|
|
for fixture in "${required_fixtures[@]}"; do
|
|
[[ -d "${fixture}" ]] || { echo "Required fixture missing: ${fixture}" >&2; exit 1; }
|
|
done
|
|
|
|
FAILURE_COUNT=0
|
|
|
|
run_report() {
|
|
(cd "${RUST_ROOT}" && cargo run -p cua-driver-testkit --bin cua-e2e-report -- \
|
|
--declarations "${DECLARATIONS_FILE}" \
|
|
--environment "${ENVIRONMENT_FILE}" \
|
|
--results "${RESULTS_FILE}" \
|
|
--artifact-root "${ARTIFACT_DIR}" \
|
|
--require-video \
|
|
--output "${SUMMARY_FILE}")
|
|
}
|
|
|
|
echo "[PREFLIGHT] macOS daemon identity, fixture, AX, capture, and video"
|
|
set +e
|
|
(cd "${RUST_ROOT}" && cargo test -p cua-driver --test e2e_environment_preflight_test -- \
|
|
--ignored --exact canonical_e2e_environment_is_ready --nocapture --test-threads=1) \
|
|
2>&1 | tee "${ARTIFACT_DIR}/environment-preflight.log"
|
|
PREFLIGHT_EXIT=${PIPESTATUS[0]}
|
|
set -e
|
|
if [[ "${PREFLIGHT_EXIT}" != 0 ]]; then
|
|
set +e
|
|
run_report
|
|
set -e
|
|
echo "macOS E2E environment preflight failed" >&2
|
|
exit 1
|
|
fi
|
|
|
|
run_test() {
|
|
local name="$1"; shift
|
|
echo "[RUN] ${name}"
|
|
set +e
|
|
(cd "${RUST_ROOT}" && "$@") 2>&1 | tee "${ARTIFACT_DIR}/${name}.log"
|
|
local exit_code=${PIPESTATUS[0]}
|
|
set -e
|
|
if [[ "${exit_code}" != 0 ]]; then
|
|
FAILURE_COUNT=$((FAILURE_COUNT + 1))
|
|
fi
|
|
}
|
|
|
|
if [[ "${SUITE}" == shared || "${SUITE}" == all ]]; then
|
|
run_test shared-app-matrix cargo test -p cua-driver --test cross_platform_behavior_test -- \
|
|
--ignored --exact shared_web_action_matrix_is_state_verified \
|
|
--nocapture --test-threads=1
|
|
fi
|
|
if [[ "${SUITE}" == native || "${SUITE}" == all ]]; then
|
|
for appkit_test in \
|
|
harness_appkit_smoke \
|
|
harness_appkit_text_input \
|
|
harness_appkit_type_text_background \
|
|
harness_appkit_scroll_foreground \
|
|
harness_appkit_scroll_background \
|
|
harness_appkit_counter \
|
|
harness_appkit_counter_px_background \
|
|
harness_appkit_right_click_px_foreground \
|
|
harness_appkit_right_click_px_background \
|
|
harness_appkit_double_click_px_foreground \
|
|
harness_appkit_double_click_px_background \
|
|
harness_appkit_slider_drag_px_foreground \
|
|
harness_appkit_slider_drag_px_background; do
|
|
run_test "appkit-${appkit_test}" cargo test -p cua-driver --test harness_appkit_test -- \
|
|
--ignored --exact "${appkit_test}" --nocapture --test-threads=1
|
|
done
|
|
for swiftui_test in \
|
|
harness_swiftui_smoke \
|
|
harness_swiftui_counter_background \
|
|
harness_swiftui_set_value_background \
|
|
harness_swiftui_popover_foreground; do
|
|
run_test "swiftui-${swiftui_test}" cargo test -p cua-driver --test harness_swiftui_test -- \
|
|
--ignored --exact "${swiftui_test}" --nocapture --test-threads=1
|
|
done
|
|
run_test installed-app-launch cargo test -p cua-driver --test installed_app_launch_macos_test -- \
|
|
--ignored --nocapture --test-threads=1
|
|
run_test installed-app-textedit cargo test -p cua-driver --test installed_app_textedit_macos_test -- \
|
|
--ignored --exact background_type_on_native_cocoa_is_ax_verified \
|
|
--nocapture --test-threads=1
|
|
fi
|
|
if [[ "${SUITE}" == capture || "${SUITE}" == all ]]; then
|
|
run_test capture-contract cargo test -p cua-driver --test capture_contract_test -- \
|
|
--ignored --nocapture --test-threads=1
|
|
run_test desktop-scope cargo test -p cua-driver --test desktop_scope_macos_test -- \
|
|
--ignored --nocapture --test-threads=1
|
|
fi
|
|
|
|
video_count=0
|
|
while IFS= read -r -d '' video; do
|
|
video_count=$((video_count + 1))
|
|
if ! ffprobe -v error -show_entries format=duration \
|
|
-of default=noprint_wrappers=1:nokey=1 "${video}" >/dev/null; then
|
|
echo "[VIDEO FAIL] Unplayable trajectory: ${video}" >&2
|
|
FAILURE_COUNT=$((FAILURE_COUNT + 1))
|
|
fi
|
|
done < <(find "${RECORDING_ROOT}" -type f -name recording.mp4 -print0)
|
|
|
|
OWNED_VIDEOS="$(mktemp)"
|
|
jq -r 'select(.evidence.video != null) | .evidence.video' "${RESULTS_FILE}" > "${OWNED_VIDEOS}"
|
|
while IFS= read -r -d '' video; do
|
|
relative="${video#${ARTIFACT_DIR}/}"
|
|
if [[ "${relative}" == recordings/environment-preflight-*/recording.mp4 ]]; then
|
|
continue
|
|
fi
|
|
if ! grep -Fxq -- "${relative}" "${OWNED_VIDEOS}"; then
|
|
echo "[VIDEO FAIL] Orphan trajectory has no typed result row: ${relative}" >&2
|
|
FAILURE_COUNT=$((FAILURE_COUNT + 1))
|
|
fi
|
|
done < <(find "${RECORDING_ROOT}" -type f -name recording.mp4 -print0)
|
|
rm -f "${OWNED_VIDEOS}"
|
|
|
|
while IFS= read -r -d '' error_file; do
|
|
echo "[VIDEO FAIL] ${error_file}" >&2
|
|
cat "${error_file}" >&2
|
|
FAILURE_COUNT=$((FAILURE_COUNT + 1))
|
|
done < <(find "${RECORDING_ROOT}" -type f -name recording-error.txt -print0)
|
|
|
|
if [[ "${video_count}" == 0 ]]; then
|
|
echo "[VIDEO FAIL] No E2E trajectory videos were produced" >&2
|
|
FAILURE_COUNT=$((FAILURE_COUNT + 1))
|
|
fi
|
|
|
|
set +e
|
|
run_report
|
|
REPORT_EXIT=$?
|
|
set -e
|
|
if [[ "${REPORT_EXIT}" != 0 ]]; then
|
|
echo "macOS E2E result validation failed" >&2
|
|
FAILURE_COUNT=$((FAILURE_COUNT + 1))
|
|
fi
|
|
|
|
if [[ "${FAILURE_COUNT}" != 0 ]]; then
|
|
echo "macOS Rust E2E suite had ${FAILURE_COUNT} failing lane(s)" >&2
|
|
exit 1
|
|
fi
|
|
echo "macOS Rust E2E suite completed: ${SUITE}"
|