Skip to content

Commit c6f8855

Browse files
authored
Merge pull request #183 from cconlon/androidTestFixes
Android: fix instrumented test compatibility and add emulator CI
2 parents 10d1db0 + 77b479b commit c6f8855

36 files changed

+709
-267
lines changed
Lines changed: 81 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,18 @@
1-
name: Android Gradle Build test logic
1+
name: Android Gradle Build and Test
22

33
on:
4-
workflow_call:
5-
inputs:
6-
os:
7-
required: true
8-
type: string
9-
jdk_distro:
10-
required: true
11-
type: string
12-
jdk_version:
13-
required: true
14-
type: string
4+
push:
5+
branches: [ 'master', 'main', 'release/**' ]
6+
pull_request:
7+
branches: [ 'master' ]
8+
9+
concurrency:
10+
group: android-${{ github.head_ref || github.ref }}
11+
cancel-in-progress: true
1512

1613
jobs:
17-
build_wolfssljni:
18-
runs-on: ${{ inputs.os }}
14+
build_wolfcryptjni:
15+
runs-on: ubuntu-latest
1916
steps:
2017
- name: Clone wolfcrypt-jni
2118
uses: actions/checkout@v4
@@ -31,22 +28,80 @@ jobs:
3128
- name: Create blank options.h
3229
run: cp IDE/Android/app/src/main/cpp/wolfssl/wolfssl/options.h.in IDE/Android/app/src/main/cpp/wolfssl/wolfssl/options.h
3330

34-
# Setup Java
31+
# Setup Java with Gradle caching
3532
- name: Setup java
3633
uses: actions/setup-java@v4
3734
with:
38-
distribution: ${{ inputs.jdk_distro }}
39-
java-version: ${{ inputs.jdk_version }}
35+
distribution: 'zulu'
36+
java-version: '21'
37+
cache: 'gradle'
38+
39+
# Build all targets in single Gradle invocation
40+
- name: Gradle Build
41+
run: cd IDE/Android && ./gradlew --build-cache assembleDebug assembleDebugUnitTest assembleDebugAndroidTest
4042

41-
# Gradle assembleDebug
42-
- name: Gradle assembleDebug
43-
run: cd IDE/Android && ls && ./gradlew assembleDebug
43+
# Enable KVM for hardware acceleration (required for emulator)
44+
- name: Enable KVM
45+
run: |
46+
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
47+
sudo udevadm control --reload-rules
48+
sudo udevadm trigger --name-match=kvm
4449
45-
# Gradle assembleDebugUnitTest
46-
- name: Gradle assembleDebugUnitTest
47-
run: cd IDE/Android && ls && ./gradlew assembleDebugUnitTest
50+
# Cache AVD snapshot for faster emulator boot
51+
- name: AVD cache
52+
uses: actions/cache@v4
53+
id: avd-cache
54+
with:
55+
path: |
56+
~/.android/avd/*
57+
~/.android/adb*
58+
key: avd-wolfcryptjni-30-x86_64-atd-v1
4859

49-
# Gradle assembleDebugAndroidTest
50-
- name: Gradle assembleDebugAndroidTest
51-
run: cd IDE/Android && ls && ./gradlew assembleDebugAndroidTest
60+
# Create AVD and generate snapshot for caching
61+
- name: Create AVD and generate snapshot
62+
if: steps.avd-cache.outputs.cache-hit != 'true'
63+
uses: reactivecircus/android-emulator-runner@v2
64+
with:
65+
api-level: 30
66+
arch: x86_64
67+
target: aosp_atd
68+
force-avd-creation: false
69+
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
70+
disable-animations: true
71+
script: echo "Generated AVD snapshot for caching"
5272

73+
# Run instrumented tests on Android emulator
74+
- name: Run Android Instrumented Tests
75+
uses: reactivecircus/android-emulator-runner@v2
76+
timeout-minutes: 15
77+
with:
78+
api-level: 30
79+
arch: x86_64
80+
target: aosp_atd
81+
force-avd-creation: false
82+
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
83+
disable-animations: true
84+
script: |
85+
adb wait-for-device
86+
adb shell mkdir -p /data/local/tmp/examples/certs/intermediate
87+
adb shell mkdir -p /data/local/tmp/examples/certs/rsapss
88+
adb shell mkdir -p /data/local/tmp/examples/certs/crl
89+
adb push ./examples/certs/ /data/local/tmp/examples/
90+
adb logcat -c
91+
cd IDE/Android && ./gradlew connectedDebugAndroidTest --no-daemon --no-watch-fs || { adb logcat -d > /tmp/logcat.txt 2>&1; echo "=== LOGCAT (errors) ==="; grep -i "exception\|error\|fatal" /tmp/logcat.txt || true; exit 1; }
92+
adb logcat -d > /tmp/logcat.txt 2>&1 || true
93+
pgrep -f '[q]emu-system' | xargs -r kill -9 2>/dev/null || true
94+
pgrep -f '[c]rashpad' | xargs -r kill -9 2>/dev/null || true
95+
sleep 2
96+
97+
# Upload test reports even on failure
98+
- name: Upload Test Reports
99+
uses: actions/upload-artifact@v4
100+
if: always()
101+
timeout-minutes: 5
102+
with:
103+
name: android-test-reports
104+
path: |
105+
IDE/Android/app/build/reports/androidTests/
106+
/tmp/logcat.txt
107+
retention-days: 14

.github/workflows/main.yml

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -139,21 +139,6 @@ jobs:
139139
jdk_version: ${{ matrix.jdk_version }}
140140
wolfssl_configure: ${{ matrix.wolfssl_configure }}
141141

142-
# ----------------------- Android Gradle build ------------------------
143-
# Run Android gradle build over PR code, only running on Linux with one
144-
# JDK/version for now.
145-
android-gradle:
146-
strategy:
147-
matrix:
148-
os: [ 'ubuntu-latest' ]
149-
jdk_version: [ '21' ]
150-
name: Android Gradle (${{ matrix.os }} Zulu JDK ${{ matrix.jdk_version }})
151-
uses: ./.github/workflows/android_gradle.yml
152-
with:
153-
os: ${{ matrix.os }}
154-
jdk_distro: "zulu"
155-
jdk_version: ${{ matrix.jdk_version }}
156-
157142
# --------------------- Maven build - test pom.xml --------------------
158143
# Run Maven build over PR code, running on Linux and Mac with only one
159144
# JDK/version for now.

IDE/Android/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
/.idea/workspace.xml
88
/.idea/navEditor.xml
99
/.idea/assetWizardSettings.xml
10+
/.idea/androidTestResultsUserPreferences.xml
1011
.DS_Store
1112
/build
1213
/captures

IDE/Android/.idea/vcs.xml

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

IDE/Android/README.md

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,35 @@ del wolfssl
7575
mklink /D wolfssl ..\..\..\..\..\..\..\src\java\com\wolfssl\
7676
```
7777

78-
## 3. Import and Build the Example Project with Android Studio
78+
## 3. Push Certificate and KeyStore Files to Android Device
79+
80+
Several JUnit tests require access to certificate and KeyStore files. These
81+
files are located in the `examples/certs` directory and must be pushed to
82+
the Android device or emulator before running tests.
83+
84+
Start the emulator or connect your device, then use `adb push` from the root
85+
wolfcrypt-jni directory. This step can be done after starting Android Studio
86+
and compiling the project, but must be done before running the test cases.
87+
88+
```
89+
adb shell mkdir -p /data/local/tmp/examples/certs/intermediate
90+
adb shell mkdir -p /data/local/tmp/examples/certs/rsapss
91+
adb shell mkdir -p /data/local/tmp/examples/certs/crl
92+
adb push ./examples/certs/ /data/local/tmp/examples/
93+
```
94+
95+
This will push all certificate files, KeyStore files (.jks, .wks, .p12),
96+
and subdirectories (intermediate, rsapss, crl) needed by the JUnit tests.
97+
98+
If this step is skipped, tests in the following classes will be skipped due
99+
to missing certificate files:
100+
101+
- `WolfSSLKeyStoreTest`
102+
- `WolfCryptPKIXCertPathValidatorTest`
103+
- `WolfCryptPKIXRevocationCheckerTest`
104+
- `WolfSSLCertManagerOCSPTest`
105+
106+
## 4. Import and Build the Example Project with Android Studio
79107

80108
1) Open the Android Studio project by double clicking on the `Android` folder
81109
in wolfcrypt-jni/IDE/. Or, from inside Android Studio, open the `Android`

IDE/Android/app/build.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ android {
1212
versionCode 1
1313
versionName "1.0"
1414
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
15+
testInstrumentationRunnerArguments notClass: 'com.wolfssl.wolfcrypt.test.WolfCryptTestSuite,com.wolfssl.provider.jce.test.WolfJCETestSuite,com.wolfssl.wolfcrypt.test.fips.WolfCryptFipsTestSuite'
1516
externalNativeBuild {
1617
cmake {
1718
cppFlags ""
@@ -35,7 +36,6 @@ android {
3536
}
3637
sourceSets {
3738
main.java.srcDirs += '../../../src/main/java'
38-
test.java.srcDirs += '../../../src/main/test'
3939
}
4040
namespace 'com.example.wolfssl'
4141
}
@@ -45,6 +45,7 @@ dependencies {
4545
implementation 'com.android.support:appcompat-v7:28.0.0'
4646
implementation 'com.android.support.constraint:constraint-layout:2.0.4'
4747
testImplementation 'junit:junit:4.13.2'
48+
androidTestImplementation 'junit:junit:4.13.2'
4849
androidTestImplementation 'com.android.support.test:runner:1.0.2'
4950
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
5051
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../../../../../../src/test/java/com/wolfssl

IDE/Android/app/src/main/cpp/CMakeLists.txt

Lines changed: 36 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -45,42 +45,48 @@ if ("${WOLFSSL_PKG_TYPE}" MATCHES "normal")
4545
# wolfssl/options.h by configure if using: "./configure --enable-jni".
4646
# This list may be configurable depending on use case and desired
4747
# optimizations.
48-
add_definitions(-DWC_RSA_BLINDING -DWOLFSSL_SHA224 -DWOLFSSL_SHA384
49-
-DWOLFSSL_SHA512 -DHAVE_HKDF -DNO_DSA -DHAVE_ECC
50-
-DECC_SHAMIR -DWC_RSA_PSS -DWOLFSSL_BASE64_ENCODE
51-
-DWOLFSSL_SHA3 -DHAVE_POLY1305 -DHAVE_CHACHA -DHAVE_HASHDRBG
52-
-DHAVE_TLS_EXTENSIONS -DHAVE_SUPPORTED_CURVES -DHAVE_FFDHE_2048
53-
-DWOLFSSL_TLS13 -DHAVE_EXTENDED_MASTER -DWOLFSSL_JNI
54-
-DHAVE_EX_DATA -DWOLFSSL_DTLS -DOPENSSL_EXTRA -DOPENSSL_ALL
55-
-DHAVE_CRL -DHAVE_OCSP -DHAVE_CRL_MONITOR
56-
-DPERSIST_SESSION_CACHE -DPERSIST_CERT_CACHE -DATOMIC_USER
57-
-DHAVE_PK_CALLBACKS -DWOLFSSL_CERT_EXT -DWOLFSSL_CERT_GEN
58-
-DHAVE_SNI -DHAVE_ALPN -DNO_RC4 -DHAVE_ENCRYPT_THEN_MAC
59-
-DNO_MD4 -DWOLFSSL_ENCRYPTED_KEYS -DHAVE_DH_DEFAULT_PARAMS
60-
-DNO_ERROR_QUEUE -DWOLFSSL_EITHER_SIDE -DWC_RSA_NO_PADDING
61-
-DWC_RSA_PSS -DWOLFSSL_PSS_LONG_SALT -DWOLFSSL_TICKET_HAVE_ID
62-
-DWOLFSSL_ERROR_CODE_OPENSSL -DWOLFSSL_ALWAYS_VERIFY_CB
63-
-DWOLFSSL_VERIFY_CB_ALL_CERTS -DWOLFSSL_EXTRA_ALERTS
64-
-DHAVE_EXT_CACHE -DWOLFSSL_FORCE_CACHE_ON_TICKET
65-
-DWOLFSSL_AKID_NAME -DHAVE_CTS -DNO_DES3 -DGCM_TABLE_4BIT
66-
-DTFM_TIMING_RESISTANT -DECC_TIMING_RESISTANT
67-
-DHAVE_AESGCM -DSIZEOF_LONG=4 -DSIZEOF_LONG_LONG=8
68-
-DWOLFSSL_KEY_GEN -DWOLFSSL_PUBLIC_MP
69-
-DWOLFSSL_CUSTOM_CONFIG
48+
add_definitions(-DWOLFSSL_JNI -DATOMIC_USER -DHAVE_PK_CALLBACKS -DERROR_QUEUE_PER_THREAD
49+
-DHAVE_EX_DATA -DHAVE_CRL -DHAVE_CRL_MONITOR -DHAVE_OCSP -DHAVE_THREAD_LS
50+
-DKEEP_PEER_CERT -DPERSIST_CERT_CACHE -DPERSIST_SESSION_CACHE
51+
-DSESSION_CERTS -DWC_NO_ASYNC_THREADING -DWOLFSSL_ALT_CERT_CHAINS
52+
-DWOLFSSL_ALT_NAMES -DWOLFSSL_ALWAYS_KEEP_SNI -DWOLFSSL_ALWAYS_VERIFY_CB
53+
-DWOLFSSL_VERIFY_CB_ALL_CERTS -DWOLFSSL_ASN_PRINT -DWOLFSSL_ASN_TEMPLATE
54+
-DWOLFSSL_BASE64_ENCODE -DWOLFSSL_CERT_EXT -DWOLFSSL_CERT_GEN
55+
-DWOLFSSL_CERT_NAME_ALL -DWOLFSSL_CERT_REQ -DWOLFSSL_KEY_GEN -DWOLFSSL_DTLS
56+
-DWOLFSSL_DTLS13 -DWOLFSSL_DTLS_DROP_STATS -DWOLFSSL_DTLS_MTU
57+
-DWOLFSSL_SEND_HRR_COOKIE -DWOLFSSL_EITHER_SIDE -DWOLFSSL_PUBLIC_MP
58+
-DWOLFSSL_SYS_CA_CERTS -DWOLFSSL_TICKET_HAVE_ID -DWOLFSSL_TLS13
59+
-DWOLFSSL_TLS13_MIDDLEBOX_COMPAT -DWOLFSSL_USE_ALIGN -DWOLFSSL_EXTRA_ALERTS
60+
-DHAVE_EXT_CACHE -DWOLFSSL_FORCE_CACHE_ON_TICKET -DWOLFSSL_AKID_NAME
61+
-DHAVE_TLS_EXTENSIONS -DHAVE_ALPN -DHAVE_ENCRYPT_THEN_MAC
62+
-DHAVE_EXTENDED_MASTER -DHAVE_SERVER_RENEGOTIATION_INFO -DHAVE_SNI
63+
-DHAVE_SUPPORTED_CURVES -DWOLFSSL_ENCRYPTED_KEYS
64+
-DOPENSSL_ALL -DOPENSSL_EXTRA -DWOLFSSL_ERROR_CODE_OPENSSL
65+
-DWOLFSSL_SHA224 -DWOLFSSL_SHA3 -DWOLFSSL_SHA384 -DWOLFSSL_SHA512
66+
-DHAVE_ECC -DECC_MIN_KEY_SZ=224 -DECC_SHAMIR
67+
-DECC_TIMING_RESISTANT -DTFM_TIMING_RESISTANT
68+
-DWC_RSA_BLINDING -DWC_RSA_NO_PADDING -DWC_RSA_PSS -DWOLFSSL_PSS_LONG_SALT
69+
-DHAVE_AESGCM -DGCM_TABLE_4BIT -DHAVE_CTS -DWOLFSSL_AES_DIRECT
70+
-DHAVE_CHACHA -DHAVE_POLY1305
71+
-DHAVE_DH_DEFAULT_PARAMS -DHAVE_FFDHE_2048
72+
-DHAVE_HASHDRBG -DHAVE_HKDF
73+
-DNO_DES3 -DNO_DES3_TLS_SUITES -DNO_DO178 -DNO_DSA -DNO_ERROR_QUEUE -DNO_MD4
74+
-DNO_OLD_TLS -DNO_RC4 -DWOLFSSL_NO_SHAKE128 -DWOLFSSL_NO_SHAKE256
75+
76+
-DSIZEOF_LONG=4 -DSIZEOF_LONG_LONG=8 -DWOLFSSL_CUSTOM_CONFIG
7077

7178
# For gethostbyname()
7279
-DHAVE_NETDB_H
7380

74-
# Defines added for debugging. These can be removed if debug
75-
# logging is not needed and will increase performance and reduce
76-
# library footprint size if removed.
81+
# Defines added for debugging. These can be removed if debug logging is not needed
82+
# and will increase performance and reduce library footprint size if removed.
7783
#-DDEBUG_WOLFSSL -DWOLFSSL_ANDROID_DEBUG
7884

79-
# Defines added for wolfCrypt test and benchmark only, may not
80-
# be needed for your own application. Add -DNO_FILESYSTEM to
81-
# disable file system use for wolfCrypt test, but make sure
82-
# to remove this define in production applications as
83-
# filesystem access is required for wolfJCE use.
85+
# Defines added for wolfCrypt test and benchmark only, may not be needed for your
86+
# own application.
87+
# Add -DNO_FILESYSTEM to disable file system use for wolfCrypt test, but make sure
88+
# to remove this define in production applications as filesystem access is required
89+
# for wolfJCE use.
8490
-DUSE_CERT_BUFFERS_2048 -DUSE_CERT_BUFFERS_256
8591
-DNO_WRITE_TEMP_FILES -DNO_MAIN_DRIVER
8692
)

IDE/Android/gradle.properties

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,3 @@ org.gradle.jvmargs=-Xmx1536m
1313
# This option should only be used with decoupled projects. More details, visit
1414
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
1515
# org.gradle.parallel=true
16-
17-

0 commit comments

Comments
 (0)