Skip to content

Commit

Permalink
Merge pull request #15608 from Expensify/Rory-RunE2ETestsImperatively
Browse files Browse the repository at this point in the history
[No QA] Run E2E performance tests imperatively
  • Loading branch information
luacmartins authored Mar 2, 2023
2 parents 7190ca2 + 14f9cfd commit 27e1951
Show file tree
Hide file tree
Showing 4 changed files with 211 additions and 122 deletions.
29 changes: 29 additions & 0 deletions .github/actions/composite/buildAndroidAPK/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Build an Android apk
description: Build an Android apk for an E2E test build and upload it as an artifact

inputs:
ARTIFACT_NAME:
description: The name of the workflow artifact where the APK should be uploaded
required: true

runs:
using: composite
steps:
- uses: Expensify/App/.github/actions/composite/setupNode@main

- uses: ruby/setup-ruby@eae47962baca661befdfd24e4d6c34ade04858f7
with:
ruby-version: '2.7'
bundler-cache: true

- uses: gradle/gradle-build-action@3fbe033aaae657f011f88f29be9e65ed26bd29ef

- name: Build APK
run: npm run android-build-e2e
shell: bash

- name: Upload APK
uses: actions/upload-artifact@65d862660abb392b8c4a3d1195a2108db131dd05
with:
name: ${{ inputs.ARTIFACT_NAME }}
path: android/app/build/outputs/apk/e2eRelease/app-e2eRelease.apk
2 changes: 1 addition & 1 deletion .github/scripts/validateActionsAndWorkflows.sh
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ for ((i=0; i < ${#WORKFLOWS[@]}; i++)); do
WORKFLOW=${WORKFLOWS[$i]}

# Skip linting e2e workflow due to bug here: https://github.com/SchemaStore/schemastore/issues/2579
if [[ "$WORKFLOW" == './workflows/preDeploy.yml' ]]; then
if [[ "$WORKFLOW" == './workflows/e2ePerformanceTests.yml' ]]; then
continue
fi

Expand Down
173 changes: 173 additions & 0 deletions .github/workflows/e2ePerformanceTests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
name: E2E Performance Tests

on:
workflow_call:
inputs:
PR_NUMBER:
description: A PR to run performance tests against. If already merged, the merge commit will be used. If not, the test merge commit will be used.
type: string
required: true

workflow_dispatch:
inputs:
PR_NUMBER:
description: A PR to run performance tests against. If already merged, the merge commit will be used. If not, the test merge commit will be used.
type: string
required: true

jobs:
prepare:
runs-on: ubuntu-latest
name: Prepare to run builds
outputs:
VERSION: ${{ steps.getMostRecentRelease.outputs.VERSION }}
DELTA_REF: ${{ steps.getMergeCommitSha.outputs.MERGE_COMMIT_SHA }}
steps:
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8

- name: Get most recent release version
id: getMostRecentRelease
run: echo "VERSION=$(gh release list --limit 1 | awk '{ print $1 }')" >> "$GITHUB_OUTPUT"
env:
GITHUB_TOKEN: ${{ github.token }}

- name: Get pull request details
id: getPullRequestDetails
uses: Expensify/App/.github/actions/javascript/getPullRequestDetails@main
with:
GITHUB_TOKEN: ${{ github.token }}
PULL_REQUEST_NUMBER: ${{ inputs.PR_NUMBER }}
user: ${{ github.actor }}

- name: Get merge commit sha for the pull request
id: getMergeCommitSha
run: echo "MERGE_COMMIT_SHA=${{ steps.getPullRequestDetails.outputs.MERGE_COMMIT_SHA }}" >> "$GITHUB_OUTPUT"
env:
GITHUB_TOKEN: ${{ github.token }}

buildBaseline:
runs-on: ubuntu-20.04-64core
needs: [prepare]
name: Build apk from latest release as a baseline
steps:
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8
with:
fetch-depth: 0

- name: Check if there's an existing artifact for this baseline
id: checkForExistingArtifact
uses: xSAVIKx/artifact-exists-action@3c5206b1411c0d2fc0840f56b7140646933d9d6a
with:
name: baseline-apk-${{ needs.prepare.outputs.VERSION }}

- name: Skip build if there's already an existing artifact for the baseline
if: ${{ fromJSON(steps.checkForExistingArtifact.outputs.exists) }}
run: echo 'APK for baseline ${{ needs.prepare.outputs.VERSION }} already exists, reusing existing build'

- name: Checkout "Baseline" commit (last release)
if: ${{ !fromJSON(steps.checkForExistingArtifact.outputs.exists) }}
run: git checkout ${{ needs.prepare.outputs.VERSION }}

- name: Build APK
if: ${{ !fromJSON(steps.checkForExistingArtifact.outputs.exists) }}
uses: Expensify/App/.github/actions/composite/buildAndroidAPK@main
with:
ARTIFACT_NAME: baseline-apk-${{ needs.prepare.outputs.VERSION }}

buildDelta:
runs-on: ubuntu-20.04-64core
needs: [prepare]
name: Build apk from delta ref
steps:
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8
with:
fetch-depth: 0

- name: Checkout "delta ref"
run: git checkout ${{ needs.prepare.outputs.DELTA_REF }}
env:
GITHUB_TOKEN: ${{ github.token }}

- name: Build APK
uses: Expensify/App/.github/actions/composite/buildAndroidAPK@main
with:
ARTIFACT_NAME: delta-apk-${{ needs.prepare.outputs.DELTA_REF }}

runTestsInAWS:
runs-on: ubuntu-20.04-64core
needs: [prepare, buildBaseline, buildDelta]
name: Run E2E tests in AWS device farm
steps:
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8
with:
ref: ${{ needs.prepare.outputs.DELTA_REF }}

- name: Make zip directory for everything to send to AWS Device Farm
run: mkdir zip

- name: Download baseline APK
uses: actions/download-artifact@e9ef242655d12993efdcda9058dee2db83a2cb9b
with:
name: baseline-apk-${{ needs.prepare.outputs.VERSION }}
path: zip

- name: Download delta APK
uses: actions/download-artifact@e9ef242655d12993efdcda9058dee2db83a2cb9b
with:
name: delta-apk-${{ needs.prepare.outputs.DELTA_REF }}
path: zip

- name: Copy e2e code into zip folder
run: cp -r tests/e2e zip

- name: Zip everything in the zip directory up
run: zip -qr App.zip ./zip

- name: Configure AWS Credentials
uses: Expensify/App/.github/actions/composite/configureAwsCredentials@main
with:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: us-west-2

- name: Schedule AWS Device Farm test run
uses: realm/aws-devicefarm/test-application@7b9a91236c456c97e28d384c9e476035d5ea686b
with:
name: App E2E Performance Regression Tests
project_arn: ${{ secrets.AWS_PROJECT_ARN }}
device_pool_arn: ${{ secrets.AWS_DEVICE_POOL_ARN }}
app_file: zip/app-e2eRelease-baseline.apk
app_type: ANDROID_APP
test_type: APPIUM_NODE
test_package_file: App.zip
test_package_type: APPIUM_NODE_TEST_PACKAGE
test_spec_file: tests/e2e/TestSpec.yml
test_spec_type: APPIUM_NODE_TEST_SPEC
remote_src: false
file_artifacts: CustomerArtifacts.zip
cleanup: true

- name: Unzip AWS Device Farm results
if: ${{ always() }}
run: unzip CustomerArtifacts.zip

- name: Print AWS Device Farm run results
if: ${{ always() }}
run: cat "./Host_Machine_Files/\$WORKING_DIRECTORY/output.md"

- name: Print AWS Device Farm verbose run results
if: ${{ always() && fromJSON(runner.debug) }}
run: cat "./Host_Machine_Files/\$WORKING_DIRECTORY/debug.log"

- name: Check if test failed, if so post the results and add the DeployBlocker label
if: ${{ github.event_name == 'workflow_call' }}
run: |
if grep -q '🔴' ./Host_Machine_Files/\$WORKING_DIRECTORY/output.md; then
gh pr edit ${{ inputs.PR_NUMBER }} --add-label DeployBlockerCash
gh pr comment ${{ inputs.PR_NUMBER }} -F ./Host_Machine_Files/\$WORKING_DIRECTORY/output.md
gh pr comment ${{ inputs.PR_NUMBER }} -b "@Expensify/mobile-deployers 📣 Please look into this performance regression as it's a deploy blocker."
else
echo '✅ no performance regression detected'
fi
env:
GITHUB_TOKEN: ${{ github.token }}
129 changes: 8 additions & 121 deletions .github/workflows/preDeploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -222,124 +222,11 @@ jobs:
So it might take a while before you're paid for your work, but we typically post multiple new jobs every day, so there's plenty of opportunity. I hope you've had a positive experience contributing to this repo! :blush:
e2e-tests:
name: "Run e2e performance regression tests"
runs-on: ubuntu-20.04-64core
steps:
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8
with:
fetch-depth: 0

- uses: Expensify/App/.github/actions/composite/setupNode@main

- uses: ruby/setup-ruby@eae47962baca661befdfd24e4d6c34ade04858f7
with:
ruby-version: '2.7'
bundler-cache: true

# Cache gradle to improve Android build time
- name: Gradle cache
uses: gradle/gradle-build-action@3fbe033aaae657f011f88f29be9e65ed26bd29ef

- name: Make zip directory for everything to send to AWS Device Farm
run: mkdir zip

- name: Checkout "Compare" commit
run: git checkout ${{ github.event.before }}

- name: Install node packages
uses: nick-invision/retry@0711ba3d7808574133d713a0d92d2941be03a350
with:
timeout_minutes: 10
max_attempts: 5
command: npm ci

- name: Build "Compare" APK
run: npm run android-build-e2e

- name: Copy "Compare" APK
run: cp android/app/build/outputs/apk/e2eRelease/app-e2eRelease.apk zip/app-e2eRelease-compare.apk

- name: Checkout "Baseline" commit (last release)
run: git checkout "$(gh release list --limit 1 | awk '{ print $1 }')"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Install node packages
uses: nick-invision/retry@0711ba3d7808574133d713a0d92d2941be03a350
with:
timeout_minutes: 10
max_attempts: 5
command: npm ci

- name: Build "Baseline" APK
run: npm run android-build-e2e

- name: Copy "Baseline" APK
run: cp android/app/build/outputs/apk/e2eRelease/app-e2eRelease.apk zip/app-e2eRelease-baseline.apk

- name: Checkout previous branch for source code to run on AWS Device farm
run: git checkout -

- name: Copy e2e code into zip folder
run: cp -r tests/e2e zip

- name: Zip everything in the zip directory up
run: zip -qr App.zip ./zip

- name: Configure AWS Credentials
uses: Expensify/App/.github/actions/composite/configureAwsCredentials@main
with:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: us-west-2

- name: Schedule AWS Device Farm test run
uses: realm/aws-devicefarm/test-application@7b9a91236c456c97e28d384c9e476035d5ea686b
with:
name: App E2E Performance Regression Tests
project_arn: ${{ secrets.AWS_PROJECT_ARN }}
device_pool_arn: ${{ secrets.AWS_DEVICE_POOL_ARN }}
app_file: zip/app-e2eRelease-baseline.apk
app_type: ANDROID_APP
test_type: APPIUM_NODE
test_package_file: App.zip
test_package_type: APPIUM_NODE_TEST_PACKAGE
test_spec_file: tests/e2e/TestSpec.yml
test_spec_type: APPIUM_NODE_TEST_SPEC
remote_src: false
file_artifacts: Customer Artifacts.zip
cleanup: true

- name: Unzip AWS Device Farm results
if: ${{ always() }}
run: unzip Customer\ Artifacts.zip

- name: Print AWS Device Farm run results
if: ${{ always() }}
run: cat "./Host_Machine_Files/\$WORKING_DIRECTORY/debug.log"

- name: Set output of AWS Device Farm into GitHub ENV
run: |
{ echo 'OUTPUT<<EOF'; cat ./Host_Machine_Files/\$WORKING_DIRECTORY/output.md; echo 'EOF'; } >> "$GITHUB_ENV"
- name: Get merged pull request
id: getMergedPullRequest
# TODO: Point back action actions-ecosystem after https://github.com/actions-ecosystem/action-get-merged-pull-request/pull/223 is merged
uses: roryabraham/action-get-merged-pull-request@7a7a194f6ff8f3eef58c822083695a97314ebec1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}

- name: Leave output of AWS Device Farm as a PR comment
run: |
gh pr comment ${{ steps.getMergedPullRequest.outputs.number }} -F ./Host_Machine_Files/\$WORKING_DIRECTORY/output.md
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Check if test failed, if so leave a deploy blocker label
if: ${{ contains(env.OUTPUT, '🔴') }}
run: |
gh pr edit ${{ steps.getMergedPullRequest.outputs.number }} --add-label 'DeployBlockerCash'
gh pr comment ${{ steps.getMergedPullRequest.outputs.number }} -b "@Expensify/mobile-deployers 📣 Please look into this performance regression as it's a deploy blocker."
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
e2ePerformanceTests:
needs: [chooseDeployActions]
if: ${{ needs.chooseDeployActions.outputs.SHOULD_DEPLOY }}
uses: Expensify/App/.github/workflows/e2ePerformanceTests.yml@main
secrets: inherit
with:
DELTA_REF: main
PR_NUMBER: ${{ needs.chooseDeployActions.outputs.MERGED_PR }}

0 comments on commit 27e1951

Please sign in to comment.