Files
status-app/ci/Jenkinsfile.test-e2e.android
T
Mag. df6fc0f688 ci(e2e-android): provide the wallet test seed to the e2e job (#21482)
* ci(e2e-android): provide the wallet test seed to the e2e job

The wallet-send smoke (#21420) skips unless WALLET_TEST_USER_SEED is
set, and the Android job never sets it. Bind the existing
wallet-test-user-seed credential, as the desktop e2e jobs already do.

Assisted-by: Claude (Anthropic)
2026-07-14 11:29:39 +01:00

212 lines
6.2 KiB
Groovy

#!/usr/bin/env groovy
library 'status-jenkins-lib@v1.9.46'
pipeline {
agent {
dockerfile {
label 'linuxcontainer'
filename 'tests.Dockerfile'
dir 'ci'
args '--user jenkins'
}
}
parameters {
string(
name: 'CHANGE_ID',
description: 'Passed from PR CI Job, optional',
defaultValue: ''
)
string(
name: 'GIT_REF',
description: 'Git branch to checkout.',
defaultValue: 'master'
)
string(
name: 'BUILD_SOURCE',
description: 'URL to APK OR path to Jenkins build.',
defaultValue: ''
)
string(
name: 'BROWSERSTACK_APP_ID',
description: 'Existing BrowserStack app identifier (bs://...). Leave empty to upload from BUILD_SOURCE.',
defaultValue: ''
)
choice(
name: 'TEST_DEVICE_ID',
description: 'BrowserStack device id to run on (leave empty to use the environment default).',
choices: ['', 'galaxy_tab_s10p_android_15', 'pixel_8_android_14', 'pixel_7_android_13', 'samsung_s23_android_13']
)
string(
name: 'PYTEST_ARGS',
description: 'Pytest flags. Default runs gate tests for PRs. Use "-n=2 -m smoke tests" for nightly/full runs.',
defaultValue: '-n=2 -m gate tests'
)
}
options {
timestamps()
timeout(time: 120, unit: 'MINUTES')
buildDiscarder(logRotator(
daysToKeepStr: '30',
numToKeepStr: '30',
artifactNumToKeepStr: '30',
))
disableRestartFromStage()
}
environment {
PLATFORM = 'tests/e2e-android'
VIRTUAL_ENV = "${env.WORKSPACE_TMP}/venv-appium"
PYTHONUNBUFFERED = "1"
CHANGE_ID = "${params.CHANGE_ID}"
TEST_DEVICE_ID = "${params.TEST_DEVICE_ID}"
BROWSERSTACK_APP_ID = "${params.BROWSERSTACK_APP_ID?.trim() ?: ''}"
BROWSERSTACK_PROJECT_NAME = "Mobile E2E ${getBuildTypeFromUpstream()}"
}
stages {
stage('Prep') {
steps {
script {
setNewBuildName()
updateGitHubStatus()
}
}
}
stage('Setup Python environment') {
steps {
dir('test/e2e_appium') {
sh """#!/bin/bash
set -euo pipefail
python3 -m venv ${VIRTUAL_ENV}
source ${VIRTUAL_ENV}/bin/activate
pip install --upgrade pip
pip install -r requirements.txt
"""
}
}
}
/* Copies APK from Jenkins build job (skipped when BUILD_SOURCE is a URL) */
stage('Fetch APK from Build') {
when {
allOf {
expression { !params.BROWSERSTACK_APP_ID?.trim() }
expression { !params.BUILD_SOURCE?.startsWith('http') }
}
}
steps { timeout(5) { script { dir('test/e2e_appium') {
copyArtifacts(
projectName: params.BUILD_SOURCE,
filter: 'pkg/*.apk',
selector: lastWithArtifacts(),
target: './pkg/',
flatten: true
)
} } } }
}
/* Uploads local APK or passes URL for BrowserStack to download */
stage('Provide APK to BrowserStack') {
when {
expression { !params.BROWSERSTACK_APP_ID?.trim() }
}
steps {
script {
def autSource = params.BUILD_SOURCE?.startsWith('http') ?
params.BUILD_SOURCE : utils.findFile('test/e2e_appium/pkg/*.apk')
withCredentials([
usernamePassword(
credentialsId: 'browserstack-status-mobile-android',
usernameVariable: 'BROWSERSTACK_USERNAME',
passwordVariable: 'BROWSERSTACK_ACCESS_KEY'
)
]) {
def response = sh(
script: "./scripts/upload_browserstack_apk.sh '${autSource}'",
returnStdout: true
).trim()
def result = readJSON text: response
if (!result?.app_url) {
error("BrowserStack upload failed: ${response}")
}
env.UPLOADED_BROWSERSTACK_APP_ID = result.app_url
env.BROWSERSTACK_BUILD_NAME = result.custom_id
env.BROWSERSTACK_BUILD_IDENTIFIER = env.BUILD_NUMBER
}
}
}
}
stage('Run pytest suite') {
steps{
lock(resource: 'e2e-android') {
script {
env.E2E_RUN_ID = env.BUILD_TAG
def appId = env.UPLOADED_BROWSERSTACK_APP_ID ?: params.BROWSERSTACK_APP_ID
dir('test/e2e_appium') {
withCredentials([
usernamePassword(
credentialsId: 'browserstack-status-mobile-android',
usernameVariable: 'BROWSERSTACK_USERNAME',
passwordVariable: 'BROWSERSTACK_ACCESS_KEY'
),
string(
credentialsId: 'wallet-test-user-seed',
variable: 'WALLET_TEST_USER_SEED'
)
]) {
sh "BROWSERSTACK_APP_ID=${appId} ${VIRTUAL_ENV}/bin/python -m pytest --env browserstack ${params.PYTEST_ARGS?.trim() ?: ''}"
}
}
}
}
}
}
}
post {
always { script {
junit allowEmptyResults: true, testResults: "test/e2e_appium/reports/${env.BUILD_TAG}/pytest_results_*.xml"
archiveArtifacts artifacts: "test/e2e_appium/reports/${env.BUILD_TAG}/**/*", allowEmptyArchive: true
env.PKG_URL = "${env.BUILD_URL}testReport/"
updateGitHubStatus()
} }
success { script { github.notifyPR(true) } }
failure { script { github.notifyPR(false) } }
cleanup {
cleanWs(disableDeferredWipeout: true)
dir(env.WORKSPACE_TMP) { deleteDir() }
}
}
}
def setNewBuildName() {
if (utils.isPRBuild()) {
currentBuild.displayName = "PR${env.CHANGE_ID}"
}
}
def updateGitHubStatus() {
if (utils.isPRBuild()) {
github.statusUpdate(
context: 'jenkins/prs/tests/e2e-android',
commit: env.GIT_COMMIT,
repo_url: 'https://github.com/status-im/status-app'
)
}
}
def getBuildTypeFromUpstream() {
def upstream = currentBuild.upstreamBuilds?.getAt(0)
if (upstream) {
def upstreamJob = upstream.getFullProjectName()
if (upstreamJob.contains('/prs/')) return 'PR'
if (upstreamJob.contains('/nightly/')) return 'Nightly'
if (upstreamJob.contains('/release/')) return 'Release'
}
return 'Manual'
}