Repository navigation
Add Android CI that runs the tests on an emulator - #30
Merged
Merged
Conversation
Cross-compile the test suite with the official Swift SDK for Android (Swift 6.3.3, checksum from swift.org) and run it on an x86_64 API 28 emulator via reactivecircus/android-emulator-runner. The host toolchain is downloaded from swift.org and its signature verified, and the NDK preinstalled on the runner (r27d) is linked into the SDK. utils/android_test.sh does the building, staging and running, so the same steps work locally against any emulator or device reachable via adb (make test-android). It stages the test runner with the Swift runtime libraries from the SDK and libc++_shared.so from the NDK, pushes them to /data/local/tmp and propagates the XCTest exit code. ExecuteOnBackgroundThread.swift now imports the Android module: the Swift SDK for Android exposes bionic as `Android`, not `Glibc`, so the test helper hit its #error on Android.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #30 +/- ##
=======================================
Coverage 96.32% 96.32%
=======================================
Files 108 108
Lines 8100 8100
=======================================
Hits 7802 7802
Misses 298 298 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Closed
The first run failed with "gpg: no valid OpenPGP data found": the signing keys arrived compressed. Let curl decode any declared content encoding and pass the result through zcat -f for gzip bytes served without one, as swiftlang/github-workflows does. Also name the job explicitly so the SDK checksum from the matrix no longer shows up in the check name.
The Android job failed to compile ExecuteOnBackgroundThread.swift: pthread_create's start routine takes `void* _Nonnull` in the NDK r27 headers but `void* _Nullable` from r28 on, and on Glibc. Bind the argument as an optional so the closure compiles with either. Link libc++_shared for COpenCombineHelpers on Android. SwiftPM adds -lstdc++ for C++ targets there, but Android's libstdc++ only provides operator new/delete, so std::system_error, std::terminate and the exception runtime the helpers use would be left undefined.
Closed
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
utils/android_test.sh(alsomake test-android): the same build → stage → run steps for local use against any emulator or device reachable via adb.buildandruncan be invoked separately, andrunaccepts XCTest filters.COpenCombineHelperslinkslibc++_sharedon Android. SwiftPM adds-lstdc++for C++ targets, but Android'slibstdc++only providesoperator new/delete. Without this,std::system_error,std::terminateand the exception runtime the helpers use would be left undefined.ExecuteOnBackgroundThread.swiftimportsAndroid, because the Swift SDK for Android has noGlibcmodule. It also binds thepthread_createstart-routine argument as an optional: the argument is_Nonnullin the NDK r27 headers but_Nullablefrom r28 on and with Glibc.Workflow details
curl --compressed | zcat -fbecause the CDN can serve them compressed. The "Swift 6.x Release Signing Key" expired on 2026-09-16, but gpg still accepts the 6.3.3 signature, which was made before that.swift sdk installwith the checksum from swift.org's release API, the same source as the Wasm SDK checksum inwasm.yml.$ANDROID_NDK_HOME), linked into the SDK by the script through the bundle'ssetup-android-sdk.sh.reactivecircus/android-emulator-runner@v2, API 28,arch: x86_64(the action defaults to 32-bitx86), with KVM enabled via udev. Unused runner toolchains are removed first to leave room for the emulator, as swiftlang's Android job does./data/local/tmp/OpenCombineTests, next to the SDK's Swift runtime libraries and the NDK'slibc++_shared.so. The XCTest exit code decides the job result.Testing
assertCrasheschecks, which re-launch the test binary and expect it to crash.