diff --git a/.semaphore/semaphore.yml b/.semaphore/semaphore.yml index f80cd11f2..ec0b65446 100644 --- a/.semaphore/semaphore.yml +++ b/.semaphore/semaphore.yml @@ -46,26 +46,18 @@ global_job_config: - sudo rm -rf ~/.rbenv ~/.phpbrew - checkout # init environment variables - - export SUM=$(checksum build.gradle.kts)-$(checksum FlowCrypt/build.gradle.kts)-$(checksum ./script/ci-install-android-sdk.sh) - - export APP_GRADLE_CACHE=gradle-cache-$SUM # per conf files hash - - export ANDROID_SDK_CACHE=android-sdk-$SUM # per conf files hash - - export BUILD_CXX_CACHE=build-cxx-cache-$SEMAPHORE_GIT_BRANCH-$SUM # per branch and conf files hash - - export BUILD_NATIVE_CACHE=build-native-cache-$SEMAPHORE_GIT_BRANCH-$SUM # per branch and conf files hash - - export BUILD_CACHE=build-cache-$SEMAPHORE_GIT_BRANCH-$SUM # per branch and conf files hash + - export GRADLE_SUM=$(checksum build.gradle.kts)-$(checksum FlowCrypt/build.gradle.kts) + - export SDK_SUM=$(checksum ./script/ci-install-android-sdk.sh) + - export APP_GRADLE_CACHE=project-gradle-cache-$GRADLE_SUM # project .gradle cache, per Gradle config hash + - export ANDROID_SDK_CACHE=android-sdk-$SDK_SUM # Android SDK cache, per SDK installer hash # restore app caches - cache restore $APP_GRADLE_CACHE - - cache restore $BUILD_CXX_CACHE - - cache restore $BUILD_NATIVE_CACHE - - cache restore $BUILD_CACHE # restore global caches - cache restore $ANDROID_SDK_CACHE - cache restore gradle-wrapper - - cache restore gradle-cache - - cache restore android-build-cache + - cache restore gradle-cache-$GRADLE_SUM # Install Android dependencies if needed - ./script/ci-install-android-sdk.sh - # Install ninja - - sudo apt install -y ninja-build blocks: - name: 'Build' execution_time_limit: @@ -79,90 +71,25 @@ blocks: # print Java version - java -version # compile project - - ./gradlew --console=plain assembleConsumerUiTests + - ./gradlew --console=plain --no-daemon --build-cache assembleConsumerUiTests epilogue: on_pass: commands: # store app cache - echo "Store the app cache" - cache has_key $APP_GRADLE_CACHE || cache store $APP_GRADLE_CACHE .gradle - - cache has_key $BUILD_CXX_CACHE || cache store $BUILD_CXX_CACHE FlowCrypt/.cxx - - cache has_key $BUILD_NATIVE_CACHE || cache store $BUILD_NATIVE_CACHE FlowCrypt/.externalNativeBuild - - cache has_key $BUILD_CACHE || cache store $BUILD_CACHE FlowCrypt/build # clean and store global cache - echo "Store the global cache" - find ~/.gradle/caches/ -name "*.lock" -type f -delete # https://medium.com/cirruslabs/mastering-gradle-caching-and-incremental-builds-37eb1af7fcde - cache has_key $ANDROID_SDK_CACHE || cache store $ANDROID_SDK_CACHE $ANDROID_HOME - - cache delete gradle-wrapper - - cache delete gradle-cache - - cache delete android-build-cache - - cache store gradle-wrapper ~/.gradle/wrapper - - cache store gradle-cache ~/.gradle/caches - - cache store android-build-cache ~/.android/build-cache + - cache has_key gradle-wrapper || cache store gradle-wrapper ~/.gradle/wrapper + - cache has_key gradle-cache-$GRADLE_SUM || cache store gradle-cache-$GRADLE_SUM ~/.gradle/caches - name: 'Testing' task: jobs: - - name: 'Lint(structural quality)' - execution_time_limit: - minutes: 15 - commands: - # run Lint checks - - ./script/ci-lint-checks.sh - - - name: 'JUnit tests' - execution_time_limit: - minutes: 15 - commands: - # run JUnit tests - - ./script/ci-junit-tests.sh - - - name: 'Instrumentation tests(No email server)' - execution_time_limit: - minutes: 60 - matrix: - - env_var: EMULATOR - values: [ "0", "1", "2", "3" ] - commands: - # Setup and run an emulator - - ./script/ci-setup-and-run-emulator.sh - # wait until ready - - ./script/ci-wait-for-emulator.sh - # Run filtered logging for TestRunner - - adb logcat -v color TestRunner:V *:S > ~/logcat_log.txt & - # Run instrumentation tests - - ./script/ci-instrumentation-tests-without-mailserver.sh 4 $EMULATOR - - - name: 'Instrumentation tests(with email server)' - execution_time_limit: - minutes: 60 - commands: - # Run an email server - - cd docker-mailserver && ./run_email_server.sh && cd - - # Setup and run an emulator - - ./script/ci-setup-and-run-emulator.sh - #wait until ready - - ./script/ci-wait-for-emulator.sh - # Run filtered logging for TestRunner - - adb logcat -v color TestRunner:V *:S > ~/logcat_log.txt & - # Run instrumentation tests - - ./script/ci-instrumentation-tests-with-mailserver.sh - - - name: 'Instrumentation tests(enterprise)' - execution_time_limit: - minutes: 60 - commands: - # Setup and run an emulator - - ./script/ci-setup-and-run-emulator.sh - #wait until ready - - ./script/ci-wait-for-emulator.sh - # Run filtered logging for TestRunner - - adb logcat -v color TestRunner:V *:S > ~/logcat_log.txt & - # Run instrumentation tests - - ./script/ci-instrumentation-tests-enterprise.sh - - - name: 'Instrumentation tests(flaky)' + - name: 'Instrumentation tests(debug)' execution_time_limit: minutes: 60 commands: @@ -188,6 +115,8 @@ blocks: commands: # collect and store debug info as artifacts - ./script/ci-get-and-publish-debug-info-as-artifact.sh + # print debug info + - ./script/ci-after-fail-debug.sh after_pipeline: task: diff --git a/FlowCrypt/build.gradle.kts b/FlowCrypt/build.gradle.kts index e8179f29a..6f37c4d0f 100644 --- a/FlowCrypt/build.gradle.kts +++ b/FlowCrypt/build.gradle.kts @@ -6,8 +6,6 @@ import com.android.build.api.artifact.SingleArtifact import com.android.build.api.variant.ResValue -import org.gradle.api.GradleException -import java.io.File import com.android.ddmlib.DdmPreferences import java.io.FileInputStream import java.text.SimpleDateFormat @@ -127,10 +125,10 @@ android { "SHARED_TENANT_FES_URL", "\"https://flowcrypt.test/shared-tenant-fes/\"" ) - buildConfigField("boolean", "IS_HTTP_LOG_ENABLED", "false") - buildConfigField("String", "HTTP_LOG_LEVEL", "\"NONE\"") - resValue("string", "gradle_is_http_log_enabled", "false") - resValue("string", "gradle_http_log_level", "NONE") + buildConfigField("boolean", "IS_HTTP_LOG_ENABLED", "true") + buildConfigField("String", "HTTP_LOG_LEVEL", "\"BODY\"") + resValue("string", "gradle_is_http_log_enabled", "true") + resValue("string", "gradle_http_log_level", "BODY") } } diff --git a/FlowCrypt/src/androidTest/java/com/flowcrypt/email/ui/gmailapi/SearchMessagesGmailApiFlowTest.kt b/FlowCrypt/src/androidTest/java/com/flowcrypt/email/ui/gmailapi/SearchMessagesGmailApiFlowTest.kt index cc7ff3377..9b3cd5895 100644 --- a/FlowCrypt/src/androidTest/java/com/flowcrypt/email/ui/gmailapi/SearchMessagesGmailApiFlowTest.kt +++ b/FlowCrypt/src/androidTest/java/com/flowcrypt/email/ui/gmailapi/SearchMessagesGmailApiFlowTest.kt @@ -20,6 +20,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.MediumTest import com.flowcrypt.email.R import com.flowcrypt.email.TestConstants +import com.flowcrypt.email.junit.annotations.DebugTest import com.flowcrypt.email.junit.annotations.FlowCryptTestSettings import com.flowcrypt.email.matchers.CustomMatchers.Companion.withRecyclerViewItemCount import com.flowcrypt.email.rules.ClearAppSettingsRule @@ -49,6 +50,7 @@ import java.util.concurrent.TimeUnit @MediumTest @RunWith(AndroidJUnit4::class) @FlowCryptTestSettings(useCommonIdling = false) +@DebugTest class SearchMessagesGmailApiFlowTest : BaseGmailApiTest() { override val mockWebServerRule = diff --git a/docker/TestEnvironment/Dockerfile b/docker/TestEnvironment/Dockerfile new file mode 100644 index 000000000..a5311736d --- /dev/null +++ b/docker/TestEnvironment/Dockerfile @@ -0,0 +1,42 @@ +FROM ubuntu:24.04 + +ARG DEBIAN_FRONTEND=noninteractive +ARG ANDROID_PLATFORM=android-36 +ARG ANDROID_SYSTEM_IMAGE=system-images;android-36;google_apis;x86_64 +ARG ANDROID_BUILD_TOOLS=36.0.0 + +ENV JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64 +ENV ANDROID_HOME=/opt/android-sdk +ENV ANDROID_SDK_ROOT=/opt/android-sdk +ENV ANDROID_AVD_HOME=/opt/android-avd +ENV PATH=/opt/android-sdk/emulator:/opt/android-sdk/platform-tools:/opt/android-sdk/cmdline-tools/latest/bin:/usr/lib/jvm/java-21-openjdk-amd64/bin:${PATH} + +RUN apt-get update && apt-get install -y --no-install-recommends \ + bash \ + ca-certificates \ + curl \ + openjdk-21-jdk \ + unzip \ + wget \ + && rm -rf /var/lib/apt/lists/* + +COPY script/ci-install-android-sdk.sh /tmp/ci-install-android-sdk.sh +RUN chmod +x /tmp/ci-install-android-sdk.sh \ + && mkdir -p "${ANDROID_AVD_HOME}" \ + && ANDROID_PLATFORM="${ANDROID_PLATFORM}" \ + ANDROID_SYSTEM_IMAGE="${ANDROID_SYSTEM_IMAGE}" \ + ANDROID_BUILD_TOOLS="${ANDROID_BUILD_TOOLS}" \ + INSTALL_KVM_DEPS=0 \ + RUN_KVM_CHECK=0 \ + /tmp/ci-install-android-sdk.sh \ + && sdkmanager --list_installed \ + && rm -f /tmp/ci-install-android-sdk.sh + +RUN mkdir -p /opt/flowcrypt/scripts +COPY script/create-avd.sh /opt/flowcrypt/scripts/create-avd.sh +COPY script/run-emulator.sh /opt/flowcrypt/scripts/run-emulator.sh +RUN chmod +x /opt/flowcrypt/scripts/create-avd.sh /opt/flowcrypt/scripts/run-emulator.sh + +WORKDIR /workspace + +CMD ["/bin/bash"] diff --git a/docker/TestEnvironment/README.md b/docker/TestEnvironment/README.md new file mode 100644 index 000000000..99549f43a --- /dev/null +++ b/docker/TestEnvironment/README.md @@ -0,0 +1,54 @@ +# Test Environment Docker Image + +This directory contains a Docker context for a headless Android test environment based on +`ubuntu:24.04`. + +The image installs: + +- OpenJDK 21 +- Android SDK command-line tools +- `platform-tools` +- Android Emulator +- Android platform `android-36` +- Build tools `36.0.0` +- System image `system-images;android-36;google_apis;x86_64` + +## Build + +```bash +docker build -t flowcrypt/android-test-env -f docker/TestEnvironment/Dockerfile . +``` + +## Create an AVD inside the container + +```bash +docker run --rm -it flowcrypt/android-test-env /opt/flowcrypt/scripts/create-avd.sh +``` + +## Run the emulator inside the container + +The container includes reusable helpers: + +- `/opt/flowcrypt/scripts/create-avd.sh` +- `/opt/flowcrypt/scripts/run-emulator.sh` + +The container includes the emulator binaries, but actual emulator launch usually needs: + +- `/dev/kvm` passed through to the container +- additional Docker flags such as `--device /dev/kvm` + +Example: + +```bash +docker run --rm -it \ + --device /dev/kvm \ + flowcrypt/android-test-env \ + bash +``` + +Then inside the container: + +```bash +/opt/flowcrypt/scripts/create-avd.sh +/opt/flowcrypt/scripts/run-emulator.sh +``` diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index c61a118f7..24ac9f37b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,11 @@ +# +# © 2016-present FlowCrypt a.s. Limitations apply. Contact human@flowcrypt.com +# Contributors: denbond7 +# + distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/script/ci-after-fail-debug.sh b/script/ci-after-fail-debug.sh new file mode 100755 index 000000000..5d6b49676 --- /dev/null +++ b/script/ci-after-fail-debug.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash + +# +# © 2016-present FlowCrypt a.s. Limitations apply. Contact human@flowcrypt.com +# Contributors: denbond7 +# + +set -euo pipefail +set -o xtrace + +check_ping_or_fail() { + local host="$1" + local label="$2" + + for attempt in {1..30}; do + if adb shell "ping -c 1 ${host}"; then + return 0 + fi + + if [[ "$attempt" -eq 30 ]]; then + echo "Failed to ping ${host}: ${label}" + exit 1 + fi + + sleep 2 + done +} + +################################################################################################### +check_ping_or_fail "www.google.com" "internet connection" +check_ping_or_fail "fes.flowcrypt.test" "flowcrypt.test forwarding" + +set +o xtrace \ No newline at end of file diff --git a/script/ci-after-success-actions-for-instrumentation-tests.sh b/script/ci-after-success-actions-for-instrumentation-tests.sh index 599b26f38..c1a1552c5 100755 --- a/script/ci-after-success-actions-for-instrumentation-tests.sh +++ b/script/ci-after-success-actions-for-instrumentation-tests.sh @@ -1,18 +1,30 @@ -#!/bin/bash +#!/usr/bin/env bash + +# +# © 2016-present FlowCrypt a.s. Limitations apply. Contact human@flowcrypt.com +# Contributors: denbond7 +# + +set -euo pipefail if [[ "$SEMAPHORE_JOB_NAME" =~ ^Instrumentation.* ]]; then # print debug info about connected device echo "Print connected devices" adb devices - # store logcat log + if [[ -f "$HOME/logcat_log.txt" ]]; then echo "Store logcat log" - artifact push job ~/logcat_log.txt + artifact push job "$HOME/logcat_log.txt" + else + echo "No logcat_log.txt found, skipping" + fi - # store screenshots - echo "Store screenshots" - adb pull "/sdcard/Pictures" - adb shell ls /sdcard/Pictures + echo "Store screenshots" + if adb shell test -d /sdcard/Pictures; then + rm -rf Pictures + adb pull "/sdcard/Pictures" Pictures artifact push job Pictures + else + echo "No /sdcard/Pictures directory found, skipping" + fi fi - diff --git a/script/ci-get-and-publish-debug-info-as-artifact.sh b/script/ci-get-and-publish-debug-info-as-artifact.sh index bf51181f9..1088399f1 100755 --- a/script/ci-get-and-publish-debug-info-as-artifact.sh +++ b/script/ci-get-and-publish-debug-info-as-artifact.sh @@ -1,23 +1,39 @@ -#!/bin/bash +#!/usr/bin/env bash + +# +# © 2016-present FlowCrypt a.s. Limitations apply. Contact human@flowcrypt.com +# Contributors: denbond7 +# + +set -euo pipefail if [[ "$SEMAPHORE_JOB_NAME" =~ ^Lint.* ]]; then - # don't do any things for 'Lint(structural quality)' job - exit 0 + # Do nothing for 'Lint(structural quality)' job. + exit 0 fi -echo "Store tests results for $SEMAPHORE_JOB_NAME" -artifact push job FlowCrypt/build/reports/ +reports_dir="FlowCrypt/build/reports/" +if [[ -d "$reports_dir" ]]; then + echo "Store test reports for $SEMAPHORE_JOB_NAME" + artifact push job "$reports_dir" +else + echo "Reports directory does not exist: $reports_dir" +fi if [[ "$SEMAPHORE_JOB_NAME" =~ ^Instrumentation.* ]]; then - # store full logcat log - echo "Collect logcat logs as logcat.txt.gz for $SEMAPHORE_JOB_NAME" - adb logcat -d | gzip > ~/logcat.txt.gz - artifact push job ~/logcat.txt.gz + # store full logcat log + echo "Collect logcat logs as logcat.txt.gz for $SEMAPHORE_JOB_NAME" + adb logcat -d | gzip > "$HOME/logcat.txt.gz" + artifact push job "$HOME/logcat.txt.gz" - # store the device's screenshot. it may help to debug a failure - echo "Store the device's screenshot for $SEMAPHORE_JOB_NAME" - adb shell screencap -p /sdcard/screencap.png - adb pull "/sdcard/screencap.png" - artifact push job screencap.png + echo "Store the device's screenshot for $SEMAPHORE_JOB_NAME" + if adb shell screencap -p /sdcard/screencap.png; then + if adb pull "/sdcard/screencap.png"; then + artifact push job screencap.png + else + echo "Could not pull screencap.png" + fi + else + echo "Could not create screencap.png" + fi fi - diff --git a/script/ci-install-android-sdk.sh b/script/ci-install-android-sdk.sh index 084866507..605cbaddc 100755 --- a/script/ci-install-android-sdk.sh +++ b/script/ci-install-android-sdk.sh @@ -22,11 +22,16 @@ fi # ----------------------------- export ANDROID_HOME="${ANDROID_HOME:-$HOME/Android/Sdk}" export ANDROID_SDK_ROOT="${ANDROID_SDK_ROOT:-$ANDROID_HOME}" +INSTALL_KVM_DEPS="${INSTALL_KVM_DEPS:-1}" +RUN_KVM_CHECK="${RUN_KVM_CHECK:-1}" +ANDROID_PLATFORM="${ANDROID_PLATFORM:-android-36}" +ANDROID_SYSTEM_IMAGE="${ANDROID_SYSTEM_IMAGE:-system-images;android-36;google_apis;x86_64}" +ANDROID_BUILD_TOOLS="${ANDROID_BUILD_TOOLS:-}" # ----------------------------- # Pin cmdline-tools archive here # ----------------------------- -SDK_ARCHIVE="commandlinetools-linux-14742923_latest.zip" +SDK_ARCHIVE="${SDK_ARCHIVE:-commandlinetools-linux-14742923_latest.zip}" # ------------------------------------------------------------ # Check that SDK_ARCHIVE is the latest Android cmdline-tools @@ -86,16 +91,20 @@ check_cmdline_tools_latest_or_fail # ----------------------------- # KVM deps (as in your script) # ----------------------------- -sudo apt-get -qq install qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils > /dev/null -sudo kvm-ok +if [[ "$INSTALL_KVM_DEPS" == "1" ]]; then + sudo apt-get -qq install qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils > /dev/null +fi +if [[ "$RUN_KVM_CHECK" == "1" ]]; then + sudo kvm-ok +fi # ----------------------------- # Install SDK if ~/Android doesn't exist (as in your script) # ----------------------------- -if [[ -d "$HOME/Android" ]]; then - echo "$HOME/Android already exists, skipping installation" +if [[ -x "$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager" ]]; then + echo "$ANDROID_HOME already exists, skipping installation" else - echo "$HOME/Android does not exist, installing" + echo "$ANDROID_HOME does not exist, installing" mkdir -p "$ANDROID_HOME" # download, unpack and remove sdk archive @@ -122,10 +131,13 @@ else # Install Android SDK (echo "yes" | "${ANDROID_HOME}/cmdline-tools/latest/bin/sdkmanager" --licenses > /dev/null | grep -v = || true) - ( sleep 5; echo "y" ) | ("${ANDROID_HOME}/cmdline-tools/latest/bin/sdkmanager" "platforms;android-36" > /dev/null | grep -v = || true) + ( sleep 5; echo "y" ) | ("${ANDROID_HOME}/cmdline-tools/latest/bin/sdkmanager" "platforms;${ANDROID_PLATFORM}" > /dev/null | grep -v = || true) ("${ANDROID_HOME}/cmdline-tools/latest/bin/sdkmanager" "platform-tools" | grep -v = || true) ("${ANDROID_HOME}/cmdline-tools/latest/bin/sdkmanager" "emulator" | grep -v = || true) - (echo "y" | "${ANDROID_HOME}/cmdline-tools/latest/bin/sdkmanager" "system-images;android-36;google_apis;x86_64" > /dev/null | grep -v = || true) + if [[ -n "$ANDROID_BUILD_TOOLS" ]]; then + ("${ANDROID_HOME}/cmdline-tools/latest/bin/sdkmanager" "build-tools;${ANDROID_BUILD_TOOLS}" | grep -v = || true) + fi + (echo "y" | "${ANDROID_HOME}/cmdline-tools/latest/bin/sdkmanager" "${ANDROID_SYSTEM_IMAGE}" > /dev/null | grep -v = || true) fi # Uncomment this for debug diff --git a/script/ci-instrumentation-tests-enterprise.sh b/script/ci-instrumentation-tests-enterprise.sh index b197fcb09..ff179352e 100755 --- a/script/ci-instrumentation-tests-enterprise.sh +++ b/script/ci-instrumentation-tests-enterprise.sh @@ -1,4 +1,11 @@ -#!/bin/bash +#!/usr/bin/env bash -./gradlew --console=plain :FlowCrypt:connectedEnterpriseUiTestsAndroidTest \ +# +# © 2016-present FlowCrypt a.s. Limitations apply. Contact human@flowcrypt.com +# Contributors: denbond7 +# + +set -euo pipefail + +./gradlew --console=plain --no-daemon --build-cache :FlowCrypt:connectedEnterpriseUiTestsAndroidTest \ -Pandroid.testInstrumentationRunnerArguments.filter=com.flowcrypt.email.junit.filters.EnterpriseTestsFilter diff --git a/script/ci-instrumentation-tests-flaky.sh b/script/ci-instrumentation-tests-flaky.sh index 706d3f24b..328a437db 100755 --- a/script/ci-instrumentation-tests-flaky.sh +++ b/script/ci-instrumentation-tests-flaky.sh @@ -1,4 +1,11 @@ -#!/bin/bash +#!/usr/bin/env bash -./gradlew --console=plain :FlowCrypt:connectedEnterpriseUiTestsAndroidTest \ - -Pandroid.testInstrumentationRunnerArguments.filter=com.flowcrypt.email.junit.filters.ReadyForCIAndFlakyFilter +# +# © 2016-present FlowCrypt a.s. Limitations apply. Contact human@flowcrypt.com +# Contributors: denbond7 +# + +set -euo pipefail + +./gradlew --console=plain --no-daemon --build-cache :FlowCrypt:connectedEnterpriseUiTestsAndroidTest \ + -Pandroid.testInstrumentationRunnerArguments.filter=com.flowcrypt.email.junit.filters.DebugTestsFilter diff --git a/script/ci-instrumentation-tests-with-mailserver.sh b/script/ci-instrumentation-tests-with-mailserver.sh index 41da56141..64f0d2998 100755 --- a/script/ci-instrumentation-tests-with-mailserver.sh +++ b/script/ci-instrumentation-tests-with-mailserver.sh @@ -1,4 +1,11 @@ -#!/bin/bash +#!/usr/bin/env bash + +# +# © 2016-present FlowCrypt a.s. Limitations apply. Contact human@flowcrypt.com +# Contributors: denbond7 +# + +set -euo pipefail #print test names #adb shell am instrument -r -w \ @@ -6,5 +13,5 @@ # -e log true \ # com.flowcrypt.email.debug.test/androidx.test.runner.AndroidJUnitRunner -./gradlew --console=plain :FlowCrypt:connectedConsumerUiTestsAndroidTest \ +./gradlew --console=plain --no-daemon --build-cache :FlowCrypt:connectedConsumerUiTestsAndroidTest \ -Pandroid.testInstrumentationRunnerArguments.filter=com.flowcrypt.email.junit.filters.DependsOnMailServerFilter diff --git a/script/ci-instrumentation-tests-without-mailserver.sh b/script/ci-instrumentation-tests-without-mailserver.sh index 778887d21..b904c77ac 100755 --- a/script/ci-instrumentation-tests-without-mailserver.sh +++ b/script/ci-instrumentation-tests-without-mailserver.sh @@ -1,35 +1,39 @@ -#!/bin/bash +#!/usr/bin/env bash -if [[ -z "$1" ]]; - then +# +# © 2016-present FlowCrypt a.s. Limitations apply. Contact human@flowcrypt.com +# Contributors: denbond7 +# + +set -euo pipefail + +if [[ -z "${1:-}" ]]; then echo "numShards is unset or set to the empty string" exit 1 - else - varNumShards=$1 fi -if [[ -z "$2" ]]; - then +if [[ -z "${2:-}" ]]; then echo "shardIndex is unset or set to the empty string" exit 1 - else - varShardIndex=$2 fi -if [[ ${varShardIndex} -ge ${varNumShards} ]] - then +numShards="$1" +shardIndex="$2" + +if (( shardIndex >= numShards )); then echo "shardIndex should be lower than numShards" - else - #print test names - #adb shell am instrument -w \ - # -e filter com.flowcrypt.email.junit.filters.DoesNotNeedMailServerFilter \ - # -e numShards 3 \ - # -e shardIndex 1 \ - # -e log true \ - # com.flowcrypt.email.debug.test/androidx.test.runner.AndroidJUnitRunner - - ./gradlew --console=plain :FlowCrypt:connectedConsumerUiTestsAndroidTest \ - -Pandroid.testInstrumentationRunnerArguments.filter=com.flowcrypt.email.junit.filters.DoesNotNeedMailServerFilter \ - -Pandroid.testInstrumentationRunnerArguments.numShards="${varNumShards}" \ - -Pandroid.testInstrumentationRunnerArguments.shardIndex="${varShardIndex}" + exit 1 fi + +#print test names +#adb shell am instrument -w \ +# -e filter com.flowcrypt.email.junit.filters.DoesNotNeedMailServerFilter \ +# -e numShards 3 \ +# -e shardIndex 1 \ +# -e log true \ +# com.flowcrypt.email.debug.test/androidx.test.runner.AndroidJUnitRunner + +./gradlew --console=plain --no-daemon --build-cache :FlowCrypt:connectedConsumerUiTestsAndroidTest \ + -Pandroid.testInstrumentationRunnerArguments.filter=com.flowcrypt.email.junit.filters.DoesNotNeedMailServerFilter \ + -Pandroid.testInstrumentationRunnerArguments.numShards="${numShards}" \ + -Pandroid.testInstrumentationRunnerArguments.shardIndex="${shardIndex}" diff --git a/script/ci-junit-tests.sh b/script/ci-junit-tests.sh index dfdcb6a2e..31b13e0b7 100755 --- a/script/ci-junit-tests.sh +++ b/script/ci-junit-tests.sh @@ -1,3 +1,10 @@ -#!/bin/bash +#!/usr/bin/env bash -./gradlew --console=plain :FlowCrypt:testConsumerUiTestsUnitTest +# +# © 2016-present FlowCrypt a.s. Limitations apply. Contact human@flowcrypt.com +# Contributors: denbond7 +# + +set -euo pipefail + +./gradlew --console=plain --no-daemon --build-cache :FlowCrypt:testConsumerUiTestsUnitTest diff --git a/script/ci-lint-checks.sh b/script/ci-lint-checks.sh index cdd01071a..dab6d43eb 100755 --- a/script/ci-lint-checks.sh +++ b/script/ci-lint-checks.sh @@ -1,3 +1,10 @@ -#!/bin/bash +#!/usr/bin/env bash -./gradlew --console=plain :FlowCrypt:lintConsumerUiTests +# +# © 2016-present FlowCrypt a.s. Limitations apply. Contact human@flowcrypt.com +# Contributors: denbond7 +# + +set -euo pipefail + +./gradlew --console=plain --no-daemon --build-cache :FlowCrypt:lintConsumerUiTests diff --git a/script/ci-publish-test-results.sh b/script/ci-publish-test-results.sh index 4c6622657..d5c21df8c 100755 --- a/script/ci-publish-test-results.sh +++ b/script/ci-publish-test-results.sh @@ -1,12 +1,26 @@ -#!/bin/bash +#!/usr/bin/env bash + +# +# © 2016-present FlowCrypt a.s. Limitations apply. Contact human@flowcrypt.com +# Contributors: denbond7 +# + +set -euo pipefail if [[ "$SEMAPHORE_JOB_NAME" =~ ^Instrumentation.* ]]; then - # publish test results for Instrumentation tests - test-results publish ~/git/flowcrypt-android/FlowCrypt/build/outputs/androidTest-results/connected/ --name "$SEMAPHORE_JOB_NAME" + results_dir="$HOME/git/flowcrypt-android/FlowCrypt/build/outputs/androidTest-results/connected/" + if [[ -d "$results_dir" ]]; then + test-results publish "$results_dir" --name "$SEMAPHORE_JOB_NAME" + else + echo "Instrumentation test results directory does not exist: $results_dir" + fi fi if [[ "$SEMAPHORE_JOB_NAME" =~ ^JUnit.* ]]; then - # publish test results for JUnit tests - test-results publish ~/git/flowcrypt-android/FlowCrypt/build/test-results/ --name "$SEMAPHORE_JOB_NAME" + results_dir="$HOME/git/flowcrypt-android/FlowCrypt/build/test-results/" + if [[ -d "$results_dir" ]]; then + test-results publish "$results_dir" --name "$SEMAPHORE_JOB_NAME" + else + echo "JUnit test results directory does not exist: $results_dir" + fi fi - diff --git a/script/ci-setup-and-run-emulator.sh b/script/ci-setup-and-run-emulator.sh index 6df16d71f..dbdff025b 100755 --- a/script/ci-setup-and-run-emulator.sh +++ b/script/ci-setup-and-run-emulator.sh @@ -1,15 +1,14 @@ -#!/bin/bash +#!/usr/bin/env bash # # © 2016-present FlowCrypt a.s. Limitations apply. Contact human@flowcrypt.com # Contributors: denbond7 # -"$ANDROID_HOME/emulator/emulator" -accel-check -avdmanager list devices #debug -echo -ne '\n' | avdmanager -v create avd --name ci-emulator --package "system-images;android-36;google_apis;x86_64" --device 'pixel_9' --abi 'google_apis/x86_64' -cat ~/.android/avd/ci-emulator.avd/config.ini -# echo "hw.ramSize=3064" >> ~/.android/avd/ci-emulator.avd/config.ini -# cat ~/.android/avd/ci-emulator.avd/config.ini -"$ANDROID_HOME/emulator/emulator" -list-avds #debug -"$ANDROID_HOME/emulator/emulator" -avd ci-emulator -no-snapshot -no-window -no-boot-anim -no-audio -gpu auto -read-only -no-metrics & +set -euo pipefail + +AVD_RAM_SIZE=2048 ./script/create-avd.sh +EMULATOR_GPU_MODE=swiftshader_indirect \ +EMULATOR_READ_ONLY=1 \ +EMULATOR_WIPE_DATA=1 \ +./script/run-emulator.sh diff --git a/script/ci-wait-for-emulator.sh b/script/ci-wait-for-emulator.sh index 6e622f643..69fbdf567 100755 --- a/script/ci-wait-for-emulator.sh +++ b/script/ci-wait-for-emulator.sh @@ -1,35 +1,101 @@ -#!/bin/bash +#!/usr/bin/env bash + # # © 2016-present FlowCrypt a.s. Limitations apply. Contact human@flowcrypt.com # Contributors: denbond7 # +set -euo pipefail set -o xtrace -adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed) ]]; do sleep 1; done;' -adb shell wm dismiss-keyguard -sleep 1 + +wait_for_boot_completed() { + adb wait-for-device + + # shellcheck disable=SC2016 + adb shell 'while [[ "$(getprop sys.boot_completed)" != "1" ]]; do sleep 1; done;' +} + +check_ping_or_fail() { + local host="$1" + local label="$2" + + for attempt in {1..30}; do + if adb shell "ping -c 1 ${host}"; then + return 0 + fi + + if [[ "$attempt" -eq 30 ]]; then + echo "Failed to ping ${host}: ${label}" + exit 1 + fi + + sleep 2 + done +} + +check_iptables_rule_or_fail() { + local chain="$1" + local expected_rule="$2" + + if ! adb shell "iptables -t nat -S ${chain}" | grep -F -- "${expected_rule}"; then + echo "iptables rule was not applied:" + echo "${expected_rule}" + exit 1 + fi +} + +wait_for_boot_completed + +adb shell wm dismiss-keyguard || true + adb shell settings put global window_animation_scale 0 adb shell settings put global transition_animation_scale 0 adb shell settings put global animator_duration_scale 0 ################################################################################################### -# to test WKD we need to route all traffic for localhost:443 to localhost:1212 +# To test WKD we need to route all traffic for localhost:443 to localhost:1212 # as we can't use 443 directly for a mock web server. -adb root -# Need wait for the root environment -sleep 20 +################################################################################################### +if adb root; then + echo "adb root succeeded" +else + echo "adb root failed, restarting adb and waiting for emulator..." + + adb kill-server || true + adb start-server +fi + +wait_for_boot_completed + adb shell "echo 1 > /proc/sys/net/ipv4/ip_forward" -adb shell "iptables -t nat -A PREROUTING -s 127.0.0.1 -p tcp --dport 443 -j REDIRECT --to 1212" -adb shell "iptables -t nat -A OUTPUT -s 127.0.0.1 -p tcp --dport 443 -j REDIRECT --to 1212" + +adb shell "iptables -t nat -D OUTPUT -s 127.0.0.1/32 -p tcp -m tcp --dport 443 -j REDIRECT --to-ports 1212" || true +adb shell "iptables -t nat -D PREROUTING -s 127.0.0.1/32 -p tcp -m tcp --dport 443 -j REDIRECT --to-ports 1212" || true + +adb shell "iptables -t nat -A PREROUTING -s 127.0.0.1 -p tcp --dport 443 -j REDIRECT --to-ports 1212" +adb shell "iptables -t nat -A OUTPUT -s 127.0.0.1 -p tcp --dport 443 -j REDIRECT --to-ports 1212" + +check_iptables_rule_or_fail \ + "PREROUTING" \ + "-A PREROUTING -s 127.0.0.1/32 -p tcp -m tcp --dport 443 -j REDIRECT --to-ports 1212" + +check_iptables_rule_or_fail \ + "OUTPUT" \ + "-A OUTPUT -s 127.0.0.1/32 -p tcp -m tcp --dport 443 -j REDIRECT --to-ports 1212" ################################################################################################### # https://developer.android.com/tools/adb#forwardports -# forwards requests on a specific host port to a different port on a device. +# Forwards requests on a specific host port to a different port on a device. # It can be helpful for debugging a mock web server +adb forward --remove tcp:1212 || true adb forward tcp:1212 tcp:1212 +if ! adb forward --list | grep -F -- "tcp:1212 tcp:1212"; then + echo "adb forward was not applied: tcp:1212 tcp:1212" + exit 1 +fi -#check the emulator has internet connection -adb shell "ping -c 1 www.google.com" +################################################################################################### +check_ping_or_fail "www.google.com" "internet connection" echo "Emulator is ready" -set +o xtrace +set +o xtrace \ No newline at end of file diff --git a/script/create-avd.sh b/script/create-avd.sh new file mode 100755 index 000000000..a15982cad --- /dev/null +++ b/script/create-avd.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash + +# +# © 2016-present FlowCrypt a.s. Limitations apply. Contact human@flowcrypt.com +# Contributors: denbond7 +# + +set -euo pipefail + +AVD_NAME="${AVD_NAME:-ci-emulator}" +SYSTEM_IMAGE="${SYSTEM_IMAGE:-system-images;android-36;google_apis;x86_64}" +DEVICE_NAME="${DEVICE_NAME:-pixel_9}" +ABI="${ABI:-google_apis/x86_64}" +AVD_DIR="${ANDROID_AVD_HOME:-$HOME/.android/avd}" +AVD_RAM_SIZE="${AVD_RAM_SIZE:-}" + +mkdir -p "$AVD_DIR" "$HOME/.android" +touch "$HOME/.android/repositories.cfg" + +if avdmanager list avd | grep -q "Name: ${AVD_NAME}"; then + echo "Removing existing AVD: ${AVD_NAME}" + avdmanager delete avd --name "$AVD_NAME" || true +fi + +rm -rf \ + "${AVD_DIR}/${AVD_NAME}.avd" \ + "${AVD_DIR}/${AVD_NAME}.ini" + +echo -ne '\n' | avdmanager -v create avd \ + --force \ + --name "$AVD_NAME" \ + --package "$SYSTEM_IMAGE" \ + --device "$DEVICE_NAME" \ + --abi "$ABI" + +if [[ -n "$AVD_RAM_SIZE" ]]; then + echo "hw.ramSize=${AVD_RAM_SIZE}" >> "${AVD_DIR}/${AVD_NAME}.avd/config.ini" +fi + +echo "Created AVD ${AVD_NAME}" diff --git a/script/run-emulator.sh b/script/run-emulator.sh new file mode 100755 index 000000000..7ecb67791 --- /dev/null +++ b/script/run-emulator.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash + +# +# © 2016-present FlowCrypt a.s. Limitations apply. Contact human@flowcrypt.com +# Contributors: denbond7 +# + +set -euo pipefail + +AVD_NAME="${AVD_NAME:-ci-emulator}" +EMULATOR_GPU_MODE="${EMULATOR_GPU_MODE:-swiftshader_indirect}" +EMULATOR_READ_ONLY="${EMULATOR_READ_ONLY:-1}" +EMULATOR_WIPE_DATA="${EMULATOR_WIPE_DATA:-1}" + +"$ANDROID_HOME/emulator/emulator" -accel-check + +emulator_args=( + -avd "$AVD_NAME" + -no-window + -no-boot-anim + -no-audio + -no-snapshot + -no-snapshot-load + -no-snapshot-save + -gpu "$EMULATOR_GPU_MODE" + -no-metrics +) + +if [[ "$EMULATOR_WIPE_DATA" == "1" ]]; then + emulator_args+=(-wipe-data) +fi + +if [[ "$EMULATOR_READ_ONLY" == "1" ]]; then + emulator_args+=(-read-only) +fi + +"$ANDROID_HOME/emulator/emulator" "${emulator_args[@]}" &