-
Notifications
You must be signed in to change notification settings - Fork 901
[QA-1126] Adding sanity check against real devices for Prod builds #5526
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weโll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
815c739
ed5b752
5b012e1
a6ef2ea
047b762
2af019e
6181378
772245c
a2ed706
2856545
58c98fa
a44a8dc
b0fb071
26cb4ce
a371efb
b8172f9
4b2f0da
6b2ac29
22644ab
5fc3c02
e9afd92
a6bd9b6
c6f8fe2
9a724d8
a5721f3
e20c814
7bedb1f
85f0bd9
d3d02f4
cab4461
9474133
47a9117
7dc5b99
909b0d0
bbd7e7c
6be753b
62b9088
7a98555
c4ebde7
be325eb
b6e90e4
b1a74c6
a6efb31
b74d3b1
ab481d2
f803752
bb8dda4
12edccc
15b5b86
da9b60f
9bf3d1e
0aafc52
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -143,7 +143,7 @@ jobs: | |
| uses: bitwarden/gh-actions/get-keyvault-secrets@main | ||
| with: | ||
| keyvault: gh-android | ||
| secrets: "UPLOAD-KEYSTORE-PASSWORD,UPLOAD-BETA-KEYSTORE-PASSWORD,UPLOAD-BETA-KEY-PASSWORD,PLAY-KEYSTORE-PASSWORD,PLAY-BETA-KEYSTORE-PASSWORD,PLAY-BETA-KEY-PASSWORD" | ||
| secrets: "UPLOAD-KEYSTORE-PASSWORD,UPLOAD-BETA-KEYSTORE-PASSWORD,UPLOAD-BETA-KEY-PASSWORD,PLAY-KEYSTORE-PASSWORD,PLAY-BETA-KEYSTORE-PASSWORD,PLAY-BETA-KEY-PASSWORD,BWS-ACCESS-TOKEN" | ||
|
|
||
| - name: Retrieve secrets | ||
| env: | ||
|
|
@@ -261,6 +261,47 @@ jobs: | |
| keyAlias:bitwarden \ | ||
| keyPassword:${{ env.PLAY-KEYSTORE-PASSWORD }} | ||
|
|
||
| - name: Retrieve test data | ||
| if: ${{ (matrix.variant == 'prod') && (matrix.artifact == 'apk') }} | ||
| uses: bitwarden/sm-action@14f92f1d294ae3c2b6a3845d389cd2c318b0dfd8 # v2.2.0 | ||
| with: | ||
| access_token: ${{ steps.get-kv-secrets.outputs.BWS-ACCESS-TOKEN }} | ||
| secrets: | | ||
| 63e93f73-5118-4a62-9db8-b3160176aa8a > TEST_ACCOUNT_CREDS | ||
|
|
||
| - name: Configure .json test data file | ||
| run: printf %s '${{ env.TEST_ACCOUNT_CREDS }}' > app/src/androidTest/assets/TestData.json | ||
|
|
||
| - name: Build test APK (espresso) | ||
| if: ${{ (matrix.variant == 'prod') && (matrix.artifact == 'apk') }} | ||
| env: | ||
| _TEST_APK_PATH: app/build/outputs/apk/androidTest/standard/release/com.x8bit.bitwarden-standard-release-androidTest.apk | ||
| _TEST_APK_SIGNED_PATH: app/build/outputs/apk/androidTest/standard/release/com.x8bit.bitwarden-test.apk | ||
| run: | | ||
| bundle exec fastlane assembleTestApk \ | ||
| storeFile:app_play-keystore.jks \ | ||
| storePassword:${{ env.PLAY-KEYSTORE-PASSWORD }} \ | ||
| keyAlias:bitwarden \ | ||
| keyPassword:${{ env.PLAY-KEYSTORE-PASSWORD }} | ||
| mv $_TEST_APK_PATH $_TEST_APK_SIGNED_PATH | ||
|
|
||
| # TODO: test if bundle exec fastlane assembleTestApk works and replace this step | ||
| # - name: Sign and rename test APK | ||
| # if: ${{ (matrix.variant == 'prod') && (matrix.artifact == 'apk') }} | ||
| # env: | ||
| # _TEST_APK_PATH: app/build/outputs/apk/androidTest/standard/release/com.x8bit.bitwarden-standard-release-androidTest.apk | ||
| # _TEST_APK_SIGNED_PATH: app/build/outputs/apk/androidTest/standard/release/com.x8bit.bitwarden-test.apk | ||
| # _PLAY_KEYSTORE_PASSWORD: ${{ steps.get-kv-secrets.outputs.PLAY-KEYSTORE-PASSWORD }} | ||
| # _PLAY_KEYSTORE_ALIAS: ${{ steps.get-kv-secrets.outputs.PLAY-KEYSTORE-ALIAS }} | ||
| # run: | | ||
| # $ANDROID_SDK_ROOT/build-tools/34.0.0/apksigner sign \ | ||
| # --ks keystores/app_play-keystore.jks \ | ||
| # --ks-key-alias bitwarden \ | ||
| # --ks-pass pass:$_PLAY_KEYSTORE_PASSWORD \ | ||
| # --key-pass pass:$_PLAY_KEYSTORE_PASSWORD \ | ||
| # $_TEST_APK_PATH | ||
| # mv $_TEST_APK_PATH $_TEST_APK_SIGNED_PATH | ||
|
|
||
| - name: Generate beta Play Store APK | ||
| if: ${{ (matrix.variant == 'prod') && (matrix.artifact == 'apk') }} | ||
| env: | ||
|
|
@@ -302,6 +343,14 @@ jobs: | |
| path: app/build/outputs/apk/standard/release/com.x8bit.bitwarden.apk | ||
| if-no-files-found: error | ||
|
|
||
| - name: Upload test .apk artifact | ||
| if: ${{ (matrix.variant == 'prod') && (matrix.artifact == 'apk') }} | ||
| uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 | ||
| with: | ||
| name: com.x8bit.bitwarden-test.apk | ||
| path: app/build/outputs/apk/androidTest/standard/release/com.x8bit.bitwarden-test.apk | ||
| if-no-files-found: error | ||
|
|
||
| - name: Upload beta .apk artifact | ||
| if: ${{ (matrix.variant == 'prod') && (matrix.artifact == 'apk') }} | ||
| uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 | ||
|
|
@@ -422,6 +471,19 @@ jobs: | |
| bundle exec fastlane publishProdToPlayStore | ||
| bundle exec fastlane publishBetaToPlayStore | ||
|
|
||
| test-device: | ||
| name: Test device | ||
| needs: publish_playstore | ||
| uses: bitwarden/android/.github/workflows/test-device.yml@QA-1126b/adding-native-sanity-test #TODO replace branch with main before merging | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This TODO needs to be addressed. |
||
| with: | ||
| apk_filename: com.x8bit.bitwarden.apk | ||
| test_apk_filename: com.x8bit.bitwarden-test.apk | ||
| permissions: | ||
| actions: read | ||
| checks: write | ||
| contents: read | ||
| id-token: write | ||
|
|
||
| publish_fdroid: | ||
| name: Publish F-Droid artifacts | ||
| needs: | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,16 +1,90 @@ | ||
| name: Test Device | ||
|
|
||
| on: | ||
| workflow_dispatch: | ||
| workflow_call: | ||
| inputs: | ||
| apk_filename: | ||
| type: string | ||
| description: "Filename of the APK file to test" | ||
| default: com.x8bit.bitwarden.apk | ||
| test_apk_filename: | ||
| type: string | ||
| description: "Filename of the test APK file to test" | ||
| default: com.x8bit.bitwarden-test.apk | ||
|
|
||
| env: | ||
| _APK_PATH: artifacts/${{ inputs.apk_filename }} | ||
| _TEST_APK_PATH: artifacts/${{ inputs.test_apk_filename }} | ||
|
|
||
| # TODO confirm if these permissions are needed | ||
| permissions: | ||
| contents: read | ||
| actions: read | ||
| checks: write | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| id-token: write | ||
|
|
||
| jobs: | ||
| test: | ||
| name: Test Device | ||
| test-device: | ||
| name: Check main build against real devices | ||
| runs-on: ubuntu-24.04 | ||
|
|
||
| steps: | ||
| - name: Placeholder step | ||
| run: echo "Placeholder workflow step" | ||
| - name: Log in to Azure | ||
| uses: bitwarden/gh-actions/azure-login@main | ||
| with: | ||
| subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} | ||
| tenant_id: ${{ secrets.AZURE_TENANT_ID }} | ||
| client_id: ${{ secrets.AZURE_CLIENT_ID }} | ||
|
|
||
| - name: Get E2E secrets from Azure | ||
| uses: bitwarden/gh-actions/get-keyvault-secrets@main | ||
| with: | ||
| keyvault: gh-android | ||
| secrets: "SAUCE-LABS-USERNAME,SAUCE-LABS-ACCESS-KEY" | ||
| id: get-kv-secrets | ||
|
|
||
| - name: Log out from Azure | ||
| uses: bitwarden/gh-actions/azure-logout@main | ||
|
|
||
| - name: Download release APK artifact | ||
| uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 | ||
| with: | ||
| name: ${{ inputs.apk_filename }} | ||
| path: artifacts | ||
|
|
||
| - name: Download test APK artifact | ||
| uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 | ||
| with: | ||
| name: ${{ inputs.test_apk_filename }} | ||
| path: artifacts | ||
|
|
||
| - name: Install saucectl | ||
| run: | | ||
| npm i -g saucectl | ||
| - name: Upload APK to SauceLabs storage | ||
| run: | | ||
| saucectl storage upload $_APK_PATH | ||
| env: | ||
| SAUCE_USERNAME: ${{ steps.get-kv-secrets.outputs.SAUCE-LABS-USERNAME }} | ||
| SAUCE_ACCESS_KEY: ${{ steps.get-kv-secrets.outputs.SAUCE-LABS-ACCESS-KEY }} | ||
|
|
||
| - name: Upload test APK to SauceLabs storage | ||
| env: | ||
| SAUCE_USERNAME: ${{ steps.get-kv-secrets.outputs.SAUCE-LABS-USERNAME }} | ||
| SAUCE_ACCESS_KEY: ${{ steps.get-kv-secrets.outputs.SAUCE-LABS-ACCESS-KEY }} | ||
| run: | | ||
| saucectl storage upload $_TEST_APK_PATH | ||
| - name: Run tests on SauceLabs | ||
| run: saucectl run --config .sauce/config.yml | ||
| env: | ||
| SAUCE_USERNAME: ${{ steps.get-kv-secrets.outputs.SAUCE-LABS-USERNAME }} | ||
| SAUCE_ACCESS_KEY: ${{ steps.get-kv-secrets.outputs.SAUCE-LABS-ACCESS-KEY }} | ||
|
|
||
| - name: Upload SauceLabs test report | ||
| if: always() | ||
| uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 | ||
| with: | ||
| name: saucectl-report | ||
| path: saucectl-report.xml | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| apiVersion: v1alpha | ||
| kind: espresso | ||
| defaults: | ||
| timeout: 10m | ||
| sauce: | ||
| region: us-west-1 | ||
| # Controls how many suites are executed at the same time (sauce test env only). | ||
| concurrency: 1 | ||
| retries: 1 | ||
| visibility: team | ||
| metadata: | ||
| tags: | ||
| - Android | ||
| - sanity-e2e | ||
| build: Sanity check on Real devices | ||
| reporters: | ||
| junit: | ||
| enabled: true | ||
| filename: saucectl-report.xml | ||
| espresso: | ||
| app: storage:filename=com.x8bit.bitwarden.apk | ||
| testApp: storage:filename=com.x8bit.bitwarden-standard-release-androidTest.apk | ||
| suites: | ||
| - name: "Android - Sanity" | ||
| devices: | ||
| - name: "Google.*" | ||
| platformVersion: "^1[3456].*" | ||
| options: | ||
| deviceType: PHONE | ||
| testOptions: | ||
| package: e2e.tests | ||
| resigningEnabled: false |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -47,6 +47,9 @@ android { | |
| namespace = "com.x8bit.bitwarden" | ||
| compileSdk = libs.versions.compileSdk.get().toInt() | ||
|
|
||
| // Required for SauceLabs integration | ||
| testBuildType = "release" | ||
ifernandezdiaz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| room { | ||
| schemaDirectory("$projectDir/schemas") | ||
| } | ||
|
|
@@ -253,6 +256,10 @@ dependencies { | |
| implementation(libs.androidx.lifecycle.runtime.compose) | ||
| implementation(libs.androidx.lifecycle.runtime.ktx) | ||
| implementation(libs.androidx.navigation.compose) | ||
| implementation(libs.androidx.uiautomator) | ||
| implementation(libs.androidx.espresso.core) | ||
| implementation(libs.androidx.junit.ktx) | ||
| implementation(libs.androidx.ui.test.junit4.android) | ||
|
Comment on lines
+259
to
+262
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we remove these as
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For some reason, the build fails if I remove those dependencies ๐ค
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think he want's them to be an
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, but those deps are already present as
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ๐ค We do not want to ship with unnecessary dependencies like this. Is there a specific error you are seeing?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I couldn't find a way to build the required testApp without those deps ๐ซค
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe we need a new variant for this. |
||
| ksp(libs.androidx.room.compiler) | ||
| implementation(libs.androidx.room.ktx) | ||
| implementation(libs.androidx.room.runtime) | ||
|
|
@@ -288,7 +295,6 @@ dependencies { | |
| testImplementation(testFixtures(project(":network"))) | ||
| testImplementation(testFixtures(project(":ui"))) | ||
|
|
||
| testImplementation(libs.androidx.compose.ui.test) | ||
| testImplementation(libs.google.hilt.android.testing) | ||
| testImplementation(platform(libs.junit.bom)) | ||
| testRuntimeOnly(libs.junit.platform.launcher) | ||
|
|
@@ -298,6 +304,11 @@ dependencies { | |
| testImplementation(libs.mockk.mockk) | ||
| testImplementation(libs.robolectric.robolectric) | ||
| testImplementation(libs.square.turbine) | ||
| androidTestImplementation(libs.androidx.compose.ui.test) | ||
| androidTestImplementation(libs.androidx.espresso.core) | ||
| androidTestImplementation(libs.androidx.junit.ktx) | ||
| androidTestImplementation(libs.androidx.ui.test.junit4.android) | ||
| androidTestImplementation(libs.androidx.uiautomator) | ||
| } | ||
|
|
||
| tasks { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -121,3 +121,23 @@ | |
| -dontwarn com.google.errorprone.annotations.CheckReturnValue | ||
| -dontwarn com.google.errorprone.annotations.Immutable | ||
| -dontwarn com.google.errorprone.annotations.RestrictedApi | ||
|
|
||
| ################################################################################ | ||
| # AndroidX Test Runner | ||
| ################################################################################ | ||
|
|
||
| # Keep the test runner classes | ||
| -keep class androidx.test.runner.** { *; } | ||
| -keep class androidx.test.internal.runner.** { *; } | ||
| -keep class androidx.test.ext.junit.** { *; } | ||
| -keep class androidx.test.ext.** { *; } | ||
| -keep class androidx.test.** { *; } | ||
|
|
||
| # Keep Compose test classes | ||
| -keep class androidx.compose.ui.test.** { *; } | ||
| -keep class androidx.compose.ui.test.junit4.** { *; } | ||
|
|
||
| # Keep Kotlin standard library classes | ||
| -keep class kotlin.** { *; } | ||
| -keep class kotlinx.** { *; } | ||
| -keep class kotlin.io.** { *; } | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we need this? Are we obfuscating test code? |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| { | ||
| "baseUrl": "_", | ||
| "email": "_", | ||
| "password": "_" | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| package com.x8bit.bitwarden.data | ||
|
|
||
| import kotlinx.serialization.Serializable | ||
|
|
||
| @Serializable | ||
| data class TestData( | ||
| val baseUrl: String, | ||
| val email: String, | ||
| val password: String, | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| package com.x8bit.bitwarden.data | ||
|
|
||
| import androidx.test.platform.app.InstrumentationRegistry | ||
| import kotlinx.serialization.json.Json | ||
| import java.nio.charset.StandardCharsets | ||
|
|
||
| object TestDataReader { | ||
| fun getTestData(fileName: String): TestData { | ||
| val assets = InstrumentationRegistry.getInstrumentation().context.assets | ||
| val jsonString = assets | ||
| .open(fileName) | ||
| .use { inputStream -> | ||
| inputStream.bufferedReader(StandardCharsets.UTF_8) | ||
| .readText() | ||
| } | ||
| return Json.decodeFromString<TestData>(jsonString) | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this TODO and commented code still needed? If so, can we associate it to a ticket so it isn't forgotten?