Skip to content

fix zai thinkback test assertions #157

fix zai thinkback test assertions

fix zai thinkback test assertions #157

Workflow file for this run

name: Termux (Android arm64)
on:
push:
branches: [main]
tags: ['[0-9]+.[0-9]+.[0-9]+']
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: jiro4989/setup-nim-action@v2
with:
nim-version: stable
repo-token: ${{ secrets.GITHUB_TOKEN }}
parent-nim-install-directory: $HOME
nim-install-directory: nim-toolchain
- name: Install dependencies
# All deps resolve by name from threecode.nimble via the public
# package registry; tags are versions, so tag builds get tagged
# dependency versions.
run: |
nimble install -y --depsOnly
- name: Download Android NDK
# The main binary builds for Termux via NDK cross-compile. No
# -d:termux: that links -landroid-glob (a Termux package for
# pre-API-28 devices); targeting API 28+ gets glob natively.
# OpenSSL is dlopen'ed at runtime (Termux's openssl package
# provides libssl.so.3), so no TLS libs are linked here.
run: |
curl -fsSL -o ndk.zip https://dl.google.com/android/repository/android-ndk-r26c-linux.zip
unzip -q ndk.zip
echo "NDK_CLANG=$PWD/android-ndk-r26c/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android28-clang" >> "$GITHUB_ENV"
- name: Compute build flags
run: |
if [[ "${GITHUB_REF}" == refs/tags/* ]]; then
# autoupdate on releases only, like the other platform builds
echo "BUILD_FLAGS=-d:autoUpdate" >> "$GITHUB_ENV"
fi
- name: Build (cross, --os:android --cpu:arm64)
run: |
nim c -d:release --os:android --cpu:arm64 -d:ssl -d:testPlainHttp ${{ env.BUILD_FLAGS }} \
--clang.exe:"$NDK_CLANG" --clang.linkerexe:"$NDK_CLANG" \
-o:3code-android src/threecode.nim
file 3code-android
# TLS check for the smoke job, cross-compiled here: installing nim
# inside the emulated container (pkg install under qemu) can
# outlive any reasonable job budget, so the container only RUNS
# binaries now. Same flags; config.nims adds the Termux RUNPATH.
nim c -d:release --os:android --cpu:arm64 -d:ssl -d:testPlainHttp \
--clang.exe:"$NDK_CLANG" --clang.linkerexe:"$NDK_CLANG" \
-o:tlscheck-android tests/android_tlscheck.nim
- name: Verify Termux RUNPATH
# Nim's openssl wrapper dlopens libssl.so.3/libcrypto.so.3 at
# module init; Android's linker only finds them via the binary's
# DT_RUNPATH (config.nims bakes in the Termux prefix). The android
# binary can't run on this x86 host, so guard the runpath here;
# without it the binary dies on startup with "could not import:
# SSL_CTX_ctrl".
run: |
readelf -d 3code-android | grep -q 'RUNPATH.*\[/data/data/com.termux/files/usr/lib\]'
- name: Package
run: |
mkdir -p 3code-termux-arm64
cp 3code-android 3code-termux-arm64/3code
cp tlscheck-android 3code-termux-arm64/tlscheck
# Can't run the android binary on the x86 host; version comes
# from the nimble file (tag releases) or the short SHA.
grep -m1 '^version' threecode.nimble | cut -d'"' -f2 > 3code-termux-arm64/VERSION
git rev-parse --short=8 HEAD >> 3code-termux-arm64/VERSION
cp README.md LICENSE 3code-termux-arm64/
tar czf 3code-termux-arm64.tar.gz 3code-termux-arm64
- name: Upload artifact (GitHub Actions)
uses: actions/upload-artifact@v4
with:
name: 3code-termux-arm64
path: 3code-termux-arm64.tar.gz
smoke:
# Run the cross-built binary inside an emulated Termux (qemu-aarch64
# + bionic, provided by termux/termux-docker). The x86 runner can't
# execute the binary natively, so this container is the only way to
# catch startup failures (dlopen paths, tmpdir, TLS) without a phone.
needs: build
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: 3code-termux-arm64
- name: Smoke test in emulated Termux
run: |
set -e
tar xzf 3code-termux-arm64.tar.gz
# Register qemu binfmt handlers; runner docker can't exec arm64
# images without this (locally docker-desktop does it for you).
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes > /dev/null
# The image's Termux tree is owned by uid/gid 1000 (system); run
# the container as that user so pkg and $HOME behave.
CID=$(docker create -t --platform linux/arm64 --user 1000:1000 \
termux/termux-docker:latest sleep 300)
docker start $CID >/dev/null
trap 'docker rm -f $CID >/dev/null 2>&1 || true' EXIT
docker exec $CID mkdir -p /data/data/com.termux/files/usr/tmp
docker cp 3code-termux-arm64/3code $CID:/data/data/com.termux/files/usr/tmp/3code
docker exec -t -e THREECODE_ALLOW_ROOT=1 $CID \
/data/data/com.termux/files/usr/tmp/3code --version
# --help exits 2 (ExitUsage) by design; assert it runs at all.
docker exec -t -e THREECODE_ALLOW_ROOT=1 $CID sh -c \
'/data/data/com.termux/files/usr/tmp/3code --help > /dev/null; \
test $? -eq 2'
# TLS init is the fragile part on Termux: the openssl wrapper
# dlopens libssl.so.3/libcrypto.so.3 at module init, and it only
# works when DT_RUNPATH (asserted in the build job) points at the
# Termux lib dir. A bare --version doesn't touch TLS; the
# cross-compiled tlscheck does a verified handshake the same way
# api.nim does. No -t: output must pipe into grep.
docker cp 3code-termux-arm64/tlscheck $CID:/data/data/com.termux/files/usr/tmp/tlscheck
docker exec $CID /data/data/com.termux/files/usr/tmp/tlscheck \
| grep -q 'tls handshake ok'
- name: Upload artifact to 3code.capocasa.dev
if: github.ref == 'refs/heads/main'
run: |
# --retry: 5xx is transient on the upload endpoint
curl -f --retry 5 --retry-delay 5 -H "Authorization: Bearer ${{ secrets.RELEASE_SECRET }}" -F "file=@3code-termux-arm64.tar.gz" \
https://3code.capocasa.dev/main/builds/upload.nim
yrc-stress:
# YRC is Nim's experimental thread-safe ORC (shared heap, atomic RC,
# concurrent cycle collector), only in devel (>= 2.3.1). 3code keeps a
# GUI animation thread painting a footer from a shared lock-protected
# frame model; stock ORC's non-atomic refcount races corrupt the heap,
# which glibc tolerates but Android's hardened_malloc aborts on
# ("write after free", the termux freeze). YRC makes those cross-thread
# RC ops safe. This job cross-compiles the tty stress tests + a stub
# 3code to arm64 with --mm:yrc and runs them in emulated Termux
# (termux-docker) to confirm the freeze is gone on the target that
# actually aborts. Requires Nim devel, so it uses nim-version: devel
# (the build/smoke jobs stay on stable for the shipped binary).
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: jiro4989/setup-nim-action@v2
with:
nim-version: devel
repo-token: ${{ secrets.GITHUB_TOKEN }}
parent-nim-install-directory: $HOME
nim-install-directory: nim-toolchain
- name: Install dependencies
# All deps resolve by name from threecode.nimble via the public
# package registry; tags are versions, so tag builds get tagged
# dependency versions.
run: |
nimble install -y --depsOnly
- name: Download Android NDK
run: |
curl -fsSL -o ndk.zip https://dl.google.com/android/repository/android-ndk-r26c-linux.zip
unzip -q ndk.zip
echo "NDK_CLANG=$PWD/android-ndk-r26c/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android28-clang" >> "$GITHUB_ENV"
- name: Cross-compile yrc stub + stress tests (arm64)
# The stub and the tty stress tests are built for android/arm64
# with --mm:yrc so they run under bionic in termux-docker. The
# stress tests drive the stub through a PTY, so THREECODE_TEST_STUB_BINARY
# points the test harness at the prebuilt arm64 stub (it can't run
# `nim` at test time in the container).
run: |
set -e
mkdir -p build
COMMON="-d:release --os:android --cpu:arm64 --mm:yrc -d:ssl -d:testPlainHttp -d:providerStub -d:fastStubRetries --threads:on --path:src --path:tests --clang.exe:$NDK_CLANG --clang.linkerexe:$NDK_CLANG"
nim c $COMMON --nimcache:build/yrc_stub_cache -o:build/3code_stub_android src/threecode.nim
for t in test_spinner_race_stress test_resize_ticker test_gui_join_freeze; do
nim c $COMMON --nimcache:build/yrc_${t}_cache -o:build/${t}_android tests/tty/${t}.nim
done
file build/3code_stub_android
- name: Run yrc stress tests in emulated Termux
run: |
set -e
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes > /dev/null
CID=$(docker create -t --platform linux/arm64 --user 1000:1000 \
termux/termux-docker:latest sleep 1800)
docker start $CID >/dev/null
trap 'docker rm -f $CID >/dev/null 2>&1 || true' EXIT
W=/data/data/com.termux/files/usr/tmp/work
docker exec $CID mkdir -p $W
docker cp build/3code_stub_android $CID:$W/3code_stub
docker cp build/test_spinner_race_stress_android $CID:$W/test_spinner_race_stress
docker cp build/test_resize_ticker_android $CID:$W/test_resize_ticker
docker cp build/test_gui_join_freeze_android $CID:$W/test_gui_join_freeze
for t in test_spinner_race_stress test_resize_ticker test_gui_join_freeze; do
docker exec -t \
-e THREECODE_TEST_STUB_BINARY=$W/3code_stub \
-e THREECODE_ALLOW_ROOT=1 \
$CID sh -c "cd $W && ./$t"
done