Skip to content

Commit 8e57337

Browse files
authored
Add emulator-test-folder and test-env inputs (#2)
* Add emulator-test-folder and test-env inputs * Fix test inputs * Debug script * Debug script * Debug script * Run tests from test folder so relative path references work * Update README * Patch tests before running * Patch tests before running * Use outptuts for build * Use outptuts for build * Use outptuts for build * Use outptuts for build * Use outputs for build * Update toolchains install location * Add swift-sdk output
1 parent ae8c4cd commit 8e57337

File tree

3 files changed

+191
-37
lines changed

3 files changed

+191
-37
lines changed

.github/workflows/test-action.yml

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,54 @@ jobs:
1717
with:
1818
path: swift-android-action
1919

20+
- name: Checkout apple/swift-numerics
21+
uses: actions/checkout@v4
22+
with:
23+
repository: apple/swift-numerics
24+
path: apple/swift-numerics
25+
- name: Setup Toolchain
26+
id: setup-toolchain
27+
uses: ./swift-android-action/
28+
#uses: skiptools/swift-android-action@v2
29+
with:
30+
# just set up the toolchain and don't build anything
31+
build-package: false
32+
- name: Build Package With Toolchain
33+
working-directory: apple/swift-numerics
34+
run: |
35+
echo "SWIFT COMMAND: ${{ steps.setup-toolchain.outputs.swift-build }}"
36+
${{ steps.setup-toolchain.outputs.swift-build }} -c debug
37+
ls -la .build/${{ steps.setup-toolchain.outputs.swift-sdk }}/debug
38+
${{ steps.setup-toolchain.outputs.swift-build }} -c release
39+
ls -la .build/${{ steps.setup-toolchain.outputs.swift-sdk }}/release
40+
41+
- name: Checkout jpsim/Yams
42+
uses: actions/checkout@v4
43+
with:
44+
repository: jpsim/Yams
45+
path: jpsim/Yams
46+
- name: Fix jpsim/Yams for Android
47+
working-directory: jpsim/Yams
48+
run: |
49+
# Android tests that use measure have too high a stddev
50+
perl -pi -e 's;self.measure ;do ;g' Tests/YamsTests/PerformanceTests.swift
51+
- name: Test jpsim/Yams
52+
uses: ./swift-android-action/
53+
#uses: skiptools/swift-android-action@v2
54+
with:
55+
package-path: jpsim/Yams
56+
run-tests: ${{ matrix.os != 'macos-15' }} # no tests on macOS ARM
57+
copy-files: Tests
58+
test-env: TEST_WORKSPACE=1
59+
2060
- name: Checkout apple/swift-algorithms
2161
uses: actions/checkout@v4
2262
with:
2363
repository: apple/swift-algorithms
2464
path: apple/swift-algorithms
2565
- name: Test apple/swift-algorithms
2666
uses: ./swift-android-action/
27-
#uses: skiptools/swift-android-action@main
67+
#uses: skiptools/swift-android-action@v2
2868
with:
2969
package-path: apple/swift-algorithms
3070
run-tests: ${{ matrix.os != 'macos-15' }} # no tests on macOS ARM
@@ -36,7 +76,7 @@ jobs:
3676
path: skiptools/swift-sqlite
3777
- name: Test skiptools/swift-sqlite
3878
uses: ./swift-android-action/
39-
#uses: skiptools/swift-android-action@main
79+
#uses: skiptools/swift-android-action@v2
4080
with:
4181
package-path: skiptools/swift-sqlite
4282
run-tests: ${{ matrix.os != 'macos-15' }} # no tests on macOS ARM

README.md

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,12 @@ jobs:
7171
| package-path | The folder where the swift package is checked out | . |
7272
| swift-build-flags | Additional flags to pass to the swift build command | |
7373
| swift-test-flags | Additional flags to pass to the swift test command | |
74+
| test-env | Test environment variables key=value | |
75+
| build-package | Whether to build the Swit package | true |
7476
| build-tests | Whether to build the package tests or just the sources | true |
7577
| run-tests | Whether to run the tests or just perform the build | true |
7678
| copy-files | Additional files to copy to emulator for testing | |
79+
| anddroid-emulator-test-folder | Emulator folder where tests are copied and run | /data/local/tmp/android-xctest |
7780
| android-api-level | The API level of the Android emulator to run against | 29 |
7881
| android-emulator-options | Options to pass to the Android emulator | -no-window … |
7982
| android-emulator-boot-timeout | Emulator boot timeout in seconds | 600 |
@@ -98,6 +101,79 @@ jobs:
98101
run-tests: false
99102
```
100103

104+
### Test Resources and Environment Variables
105+
106+
Unit tests sometimes need to load local resources, such as configuration
107+
files and mocking or parsing inputs. This is typically handled
108+
using [Bundle.module](https://developer.apple.com/documentation/xcode/bundling-resources-with-a-swift-package),
109+
which will be automatically copied up to the Android emulator when
110+
testing and so should work transparently.
111+
112+
However, in some cases a test script may expect a specific set
113+
of local files to be present, such as when a unit test needs to
114+
examine the contents of the source code itself. In these cases,
115+
you can use the `copy-files` input parameter to specify local files
116+
to copy up to the emulator when running.
117+
118+
Similarly, some test cases may expect a certain environment to be set.
119+
This can be accomplished using the `test-env` parameter, which
120+
is a space separated list of key=value pairs of environment
121+
variables to set when running the tests.
122+
123+
For example:
124+
125+
```yml
126+
- name: Test Android Package
127+
uses: skiptools/swift-android-action@v2
128+
with:
129+
copy-files: Tests
130+
test-env: TEST_WORKSPACE=1
131+
```
132+
133+
### Installing without Building
134+
135+
You may wish to use this action to just install the toolchain and
136+
Android SDK without performing the build. For example, if you
137+
wish to build multiple packages consecutively, and don't need to
138+
run the test cases. In this case, you can set the
139+
`build-package` input to false, and then use the action's
140+
`swift-build` output to get the complete `swift build` command
141+
with all the appropriate paths and arguments to build using the
142+
SDK.
143+
144+
For example:
145+
146+
```yml
147+
- name: Setup Toolchain
148+
id: setup-toolchain
149+
uses: skiptools/swift-android-action@v2
150+
with:
151+
# just set up the toolchain but don't build anything
152+
build-package: false
153+
- name: Checkout apple/swift-numerics
154+
uses: actions/checkout@v4
155+
- name: Build Package With Toolchain
156+
run: |
157+
# build twice, once with debug and once with release
158+
${{ steps.setup-toolchain.outputs.swift-build }} -c debug
159+
ls .build/${{ steps.setup-toolchain.outputs.swift-sdk }}/debug
160+
${{ steps.setup-toolchain.outputs.swift-build }} -c release
161+
ls .build/${{ steps.setup-toolchain.outputs.swift-sdk }}/release
162+
```
163+
164+
The actual `swift-build` command will vary between operating systems
165+
and architectures. For example, on Ubuntu 24.04, it might be:
166+
167+
```
168+
/home/runner/swift/toolchains/swift-6.0.2-RELEASE/usr/bin/swift build --swift-sdk x86_64-unknown-linux-android24
169+
```
170+
171+
while on macOS-15 it will be:
172+
173+
```
174+
/Users/runner/Library/Developer/Toolchains/swift-6.0.2-RELEASE.xctoolchain/usr/bin/swift build --swift-sdk aarch64-unknown-linux-android24
175+
```
176+
101177

102178
## Complete Universal CI Example
103179

action.yml

Lines changed: 73 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@ description: 'Cross-compiles a swift package for Android and runs the test cases
33
branding:
44
icon: 'target'
55
color: 'orange'
6+
outputs:
7+
swift-build:
8+
description: 'The swift build command using the installed toolchain and SDK'
9+
value: ${{ steps.install.outputs.swiftcmd }}
10+
swift-sdk:
11+
description: 'The swift SDK that is used to build for Android'
12+
value: ${{ steps.install.outputs.swift-sdk }}
613
inputs:
714
swift-version:
815
description: 'The version of the Swift toolchain to use'
@@ -20,6 +27,14 @@ inputs:
2027
description: 'Additional flags to pass to the swift test command'
2128
required: true
2229
default: ''
30+
android-emulator-test-folder:
31+
description: 'Emulator folder where tests are copied and run'
32+
required: true
33+
default: '/data/local/tmp/android-xctest'
34+
test-env:
35+
description: 'Test environment variables key=value'
36+
required: true
37+
default: ''
2338
android-emulator-options:
2439
description: 'Options to pass to the Android emulator'
2540
required: true
@@ -28,6 +43,14 @@ inputs:
2843
description: 'Emulator boot timeout in seconds'
2944
required: true
3045
default: 600
46+
build-package:
47+
description: 'Whether to build the package or just set up the SDK'
48+
required: true
49+
default: 'true'
50+
build-tests:
51+
description: 'Whether to build the tests or just the sources'
52+
required: true
53+
default: 'true'
3154
run-tests:
3255
description: 'Whether to run the tests or just the build'
3356
required: true
@@ -36,14 +59,11 @@ inputs:
3659
description: 'Additional files to copy to emulator for testing'
3760
required: true
3861
default: ''
39-
build-tests:
40-
description: 'Whether to build the tests or just the sources'
41-
required: true
42-
default: 'true'
4362
android-api-level:
4463
description: 'The API level of the Android emulator to run against'
4564
required: true
4665
default: 29
66+
4767
runs:
4868
using: "composite"
4969
steps:
@@ -112,9 +132,9 @@ runs:
112132
cd ~/swift-download
113133
SWIFT_ID="swift-${{ steps.setup.outputs.swift-version }}-RELEASE"
114134
if [ ${RUNNER_OS} == 'Linux' ]; then
115-
mkdir -p ${HOME}/swift/$SWIFT_ID
116-
tar -xzf swift.tar.gz -C ~/swift/$SWIFT_ID --strip 1
117-
SWIFT_INSTALLATION=$HOME/swift/$SWIFT_ID/usr
135+
mkdir -p ${HOME}/swift/toolchains/$SWIFT_ID
136+
tar -xzf swift.tar.gz -C ${HOME}/swift/toolchains/$SWIFT_ID --strip 1
137+
SWIFT_INSTALLATION=$HOME/swift/toolchains/$SWIFT_ID/usr
118138
elif [ ${RUNNER_OS} == 'macOS' ]; then
119139
/usr/sbin/installer -pkg swift.pkg -target CurrentUserHomeDirectory
120140
SWIFT_INSTALLATION=${HOME}/Library/Developer/Toolchains/${SWIFT_ID}.xctoolchain/usr
@@ -124,14 +144,11 @@ runs:
124144
exit 1
125145
fi
126146
echo "SWIFT_INSTALLATION=${SWIFT_INSTALLATION}" >> $GITHUB_ENV
127-
echo "${SWIFT_INSTALLATION}/bin" >> $GITHUB_PATH
128-
129-
- name: Check Swift Version
130-
shell: bash
131-
run: |
132-
swift --version
147+
# needed to override locally-installed `swift` command
148+
#echo "${SWIFT_INSTALLATION}/bin" >> $GITHUB_PATH
133149
134150
- name: Install Swift Android SDK
151+
id: install
135152
shell: bash
136153
run: |
137154
set +x
@@ -153,9 +170,9 @@ runs:
153170
curl -fsSL https://github.com/skiptools/swift-android-toolchain/releases/download/${{ steps.setup.outputs.swift-version }}/${SWIFT_SDK_ID}.artifactbundle.tar.gz --output ${SWIFT_SDK_ID}.artifactbundle.tar.gz
154171
155172
# first check if it already installed (we may be running this workflow multiple times for an action, in which case it will already be present)
156-
swift sdk configure --show-configuration ${SWIFT_SDK_ID} ${SWIFT_SDK_TARGET} &> /dev/null || swift sdk install ${SWIFT_SDK_ID}.artifactbundle.tar.gz
173+
${SWIFT_INSTALLATION}/bin/swift sdk configure --show-configuration ${SWIFT_SDK_ID} ${SWIFT_SDK_TARGET} &> /dev/null || ${SWIFT_INSTALLATION}/bin/swift sdk install ${SWIFT_SDK_ID}.artifactbundle.tar.gz
157174
158-
swift sdk configure --show-configuration ${SWIFT_SDK_ID} ${SWIFT_SDK_TARGET}
175+
${SWIFT_INSTALLATION}/bin/swift sdk configure --show-configuration ${SWIFT_SDK_ID} ${SWIFT_SDK_TARGET}
159176
160177
if [ ${RUNNER_OS} == 'Linux' ]; then
161178
SWIFT_SDK_ROOT="${HOME}/.config/swiftpm/swift-sdks"
@@ -178,56 +195,77 @@ runs:
178195
179196
echo "SWIFT_SDK_HOME=${SWIFT_SDK_HOME}" >> $GITHUB_ENV
180197
198+
echo "swiftcmd=${SWIFT_INSTALLATION}/bin/swift build --swift-sdk ${SWIFT_SDK_TARGET} -Xswiftc -DSKIP_BRIDGE ${{ inputs.swift-build-flags }}" >> $GITHUB_OUTPUT
199+
echo "swift-sdk=${SWIFT_SDK_TARGET}" >> $GITHUB_OUTPUT
200+
201+
- name: Check Swift Version
202+
shell: bash
203+
run: |
204+
echo "Swift Command: ${{ steps.install.outputs.swiftcmd }}"
205+
${{ steps.install.outputs.swiftcmd }} --version
206+
181207
- name: Build Swift Package with Android SDK
208+
if: ${{ inputs.build-package == 'true' }}
182209
shell: bash
183210
working-directory: ${{ inputs.package-path }}
184211
run: |
185212
if [ "${{ inputs.build-tests }}" == 'true' ]; then
186213
BUILD_TESTS="--build-tests"
187214
fi
188-
SKIP_BRIDGE=1 swift build ${BUILD_TESTS} --swift-sdk ${SWIFT_SDK_TARGET} -Xswiftc -Xclang-linker -Xswiftc -fuse-ld=lld -Xswiftc -DSKIP_BRIDGE ${{ inputs.swift-build-flags }}
215+
SKIP_BRIDGE=1 ${{ steps.install.outputs.swiftcmd }} ${BUILD_TESTS}
189216
190217
- name: Prepare Android Emulator Test Script
191-
if: ${{ inputs.run-tests == 'true' && inputs.build-tests == 'true' }}
218+
if: ${{ inputs.run-tests == 'true' && inputs.build-tests == 'true' && inputs.build-package == 'true' }}
192219
shell: bash
193-
working-directory: ${{ inputs.package-path }}/.build
220+
working-directory: ${{ inputs.package-path }}
194221
run: |
195-
set -x
196-
197222
if [ ${RUNNER_ARCH} == 'ARM64' ] && [ ${RUNNER_OS} == 'macOS' ]; then
198223
echo "::error::Cannot run tests on ARM64 macOS due to HVF error: HV_UNSUPPORTED. See https://github.com/ReactiveCircus/android-emulator-runner/issues/350#issuecomment-2030065889"
199224
exit 1
200225
fi
201226
202-
mkdir android-xctest
227+
#inputs.android-emulator-test-folder = /data/local/tmp/android-xctest
228+
REMOTE_FOLDER=$(dirname "${{ inputs.android-emulator-test-folder }}")
229+
TEST_BASE_FOLDER=$(basename "${{ inputs.android-emulator-test-folder }}")
230+
BUILD_DIR=".build"
231+
PACK_DIR="${BUILD_DIR}/${TEST_BASE_FOLDER}"
232+
233+
mkdir -p ${PACK_DIR}
203234
204235
# copy the built test binary
205-
cp -va ${SWIFT_SDK_TARGET}/debug/*.xctest android-xctest
236+
cp -va ${BUILD_DIR}/${SWIFT_SDK_TARGET}/debug/*.xctest ${PACK_DIR}
206237
207238
# copy any optional resource bundles
208-
cp -vaf ${SWIFT_SDK_TARGET}/debug/*.resources android-xctest || true
209-
239+
cp -vaf ${BUILD_DIR}/${SWIFT_SDK_TARGET}/debug/*.resources ${PACK_DIR} || true
210240
# 6.0.2 keeps libraries in per-API folders
211-
cp -vaf ${SWIFT_SDK_HOME}/usr/lib/${{ steps.setup.outputs.android-sdk-arch }}-linux-android/${SWIFT_SDK_ANROID_API}/lib*.so android-xctest || true
241+
cp -vaf ${SWIFT_SDK_HOME}/usr/lib/${{ steps.setup.outputs.android-sdk-arch }}-linux-android/${SWIFT_SDK_ANROID_API}/lib*.so ${PACK_DIR} || true
212242
213243
# 6.0.3 keeps libraries in the parent folder
214-
cp -vaf ${SWIFT_SDK_HOME}/usr/lib/${{ steps.setup.outputs.android-sdk-arch }}-linux-android/lib*.so android-xctest || true
244+
cp -vaf ${SWIFT_SDK_HOME}/usr/lib/${{ steps.setup.outputs.android-sdk-arch }}-linux-android/lib*.so ${PACK_DIR} || true
215245
216-
rm -v android-xctest/lib{c,dl,log,m,z}.so
246+
# clear out libraries that are already provided by Android
247+
rm -v ${PACK_DIR}/lib{c,dl,log,m,z}.so || true
217248
218249
if [ "${{ inputs.copy-files }}" != '' ]; then
219-
cp -vaf ${{ inputs.copy-files }} android-xctest
250+
cp -vaf ${{ inputs.copy-files }} ${PACK_DIR}
220251
fi
221252
222-
echo "adb push android-xctest /data/local/tmp" > run-android-tests.sh
223-
for XCTEST in android-xctest/*.xctest; do
224-
echo "adb shell /data/local/tmp/${XCTEST} ${{ inputs.swift-test-flags }}" >> run-android-tests.sh
253+
# create the script that will be run once the emulator is launched
254+
SCRIPT_FILE="run-android-tests.sh"
255+
256+
cd ${BUILD_DIR}
257+
echo "adb push ${TEST_BASE_FOLDER} ${REMOTE_FOLDER}" > ${SCRIPT_FILE}
258+
for XCTEST in ${TEST_BASE_FOLDER}/*.xctest; do
259+
XCTEST_BASE=$(basename "${XCTEST}")
260+
echo "adb shell 'cd ${REMOTE_FOLDER}/${TEST_BASE_FOLDER} && ${{ inputs.test-env }} ./${XCTEST_BASE} ${{ inputs.swift-test-flags }}'" >> ${SCRIPT_FILE}
225261
done
226262
227-
chmod +x run-android-tests.sh
263+
cat ${SCRIPT_FILE}
264+
265+
chmod +x ${SCRIPT_FILE}
228266
229267
- name: Setup Android Emulator Cache
230-
if: ${{ inputs.run-tests == 'true' && inputs.build-tests == 'true' }}
268+
if: ${{ inputs.run-tests == 'true' && inputs.build-tests == 'true' && inputs.build-package == 'true' }}
231269
uses: actions/cache@v4
232270
id: avd-cache
233271
with:
@@ -237,7 +275,7 @@ runs:
237275
key: avd-${{ inputs.android-api-level }}-${{ steps.setup.outputs.android-emulator-arch }}
238276

239277
- name: Create Android Emulator Cache
240-
if: ${{ inputs.run-tests == 'true' && inputs.build-tests == 'true' && steps.avd-cache.outputs.cache-hit != 'true' }}
278+
if: ${{ inputs.run-tests == 'true' && inputs.build-tests == 'true' && inputs.build-package == 'true' && steps.avd-cache.outputs.cache-hit != 'true' }}
241279
uses: reactivecircus/android-emulator-runner@v2
242280
with:
243281
force-avd-creation: false
@@ -250,7 +288,7 @@ runs:
250288
script: echo "Generated Android Emulator snapshot for caching."
251289

252290
- name: Run Tests on Android emulator
253-
if: ${{ inputs.run-tests == 'true' && inputs.build-tests == 'true' }}
291+
if: ${{ inputs.run-tests == 'true' && inputs.build-tests == 'true' && inputs.build-package == 'true' }}
254292
uses: reactivecircus/android-emulator-runner@v2
255293
with:
256294
force-avd-creation: false

0 commit comments

Comments
 (0)