fix zai thinkback test assertions #157
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |