Files
DarkRoom/tools/face-tests-on-device.sh
dtourolle 84fade99ec Put the developer docs under docs/dev and index the folder for users first
docs/ had 26 developer documents flat beside the manual, and the two
audiences are very differently sized: most readers want the manual and
the gesture reference, a few want the register, the designs and the
measurements. The manual and gestures.md stay at the top; everything for
someone changing the code moves to docs/dev/, and the two documents that
name their own successors — the v0.1 milestone and the UI-refinement plan
— go to docs/dev/archive/ rather than being deleted, since both are still
cited. docs/README.md is the index, users first.

Every reference follows: code comments, Cargo manifests, the workflows,
the pre-commit hook, the bench and traceability tools (which locate the
repo root by docs/dev/requirements.md now), packaging, the Docker READMEs,
CLAUDE.md, CONTRIBUTING.md and the README. The matrix links one level
deeper and is regenerated. Links out of the moved documents into the tree
gain a level; a link checker over every Markdown file finds none broken.
2026-09-20 21:16:03 +02:00

79 lines
2.7 KiB
Bash
Executable File

#!/usr/bin/env bash
# Run dr-face's test suite on a connected Android device.
#
# ./tools/face-tests-on-device.sh [extra cargo test args…]
#
# ## Why this exists
#
# `dr-face`'s similarity scan picks its dot product per machine (docs/dev/faces.md
# §9): AVX2 where the CPU has it, **NEON on aarch64**, and a portable loop
# otherwise. The NEON kernel is the one that runs on the phone and the tablet,
# and it is the one a desktop `cargo test` never executes — a wrong lane index
# or a mishandled tail there would be a silent wrong answer on exactly the
# devices nobody runs the test suite on.
#
# `the_fastest_kernel_agrees_with_the_portable_one` is written to catch that,
# and this is how it gets to run on the hardware it is about. Everything else
# in the suite comes along for free: `dr-face` carries no weights and touches
# no display, so its tests are a plain ARM64 binary that runs under `adb
# shell` with nothing installed.
#
# Not part of CI, which has no device attached. Run it when the kernels change.
set -euo pipefail
TARGET=aarch64-linux-android
API=26
DEST=/data/local/tmp/dr_face_tests
ndk="${ANDROID_NDK_HOME:-}"
if [[ -z "$ndk" ]]; then
# The newest NDK the SDK has, which is what the app is built with.
ndk=$(find "${ANDROID_HOME:-$HOME/Android/Sdk}/ndk" -maxdepth 1 -mindepth 1 -type d 2>/dev/null |
sort -V | tail -1)
fi
[[ -n "$ndk" && -d "$ndk" ]] || {
echo "no NDK found — set ANDROID_NDK_HOME" >&2
exit 1
}
clang="$ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/$TARGET$API-clang"
[[ -x "$clang" ]] || {
echo "no $TARGET$API-clang in $ndk" >&2
exit 1
}
rustup target list --installed | grep -qx "$TARGET" || rustup target add "$TARGET"
# Told to the device before the build, so a missing tablet costs seconds rather
# than the two minutes it takes to compile for it.
adb devices | grep -qw device || {
echo "no device attached — plug the tablet in and enable USB debugging" >&2
exit 1
}
echo "building dr-face tests for $TARGET…"
binary=$(
CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER="$clang" \
CC_aarch64_linux_android="$clang" \
cargo test -p dr-face --lib --release --target "$TARGET" --no-run --message-format=json "$@" |
python3 -c '
import json, sys
for line in sys.stdin:
m = json.loads(line)
if m.get("profile", {}).get("test") and m.get("executable"):
print(m["executable"])
' | tail -1
)
[[ -n "$binary" ]] || {
echo "cargo produced no test binary" >&2
exit 1
}
echo "pushing $(basename "$binary")…"
adb push "$binary" "$DEST" >/dev/null
adb shell chmod 755 "$DEST"
# `--test-threads` left alone: the scan spawns its own workers and the point is
# to exercise them the way the app will.
adb shell "$DEST" --color never
adb shell rm -f "$DEST"