Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
72417cf
Updated gradle to 9.5.0
DenBond7 May 10, 2026
0c7473d
Updated CI scripts with --no-daemon, --build-cache, and --max-workers…
DenBond7 May 10, 2026
cd861b6
Refactored Semaphore CI caching strategy and separated checksums
DenBond7 May 10, 2026
bae1500
wip
DenBond7 May 10, 2026
5bcab0e
Refactored CI scripts for improved robustness and emulator handling
DenBond7 May 10, 2026
3ffc782
Removed --max-workers=2 from CI scripts and semaphore configuration
DenBond7 May 10, 2026
66a468b
Removed native and redundant build caches from Semaphore configuration
DenBond7 May 10, 2026
c3a92ab
Removed ninja-build installation from semaphore.yml
DenBond7 May 10, 2026
7b7ae48
Configured emulator DNS server and added resolution checks in CI scripts
DenBond7 May 10, 2026
b7704e1
Replaced -dns-server flag with /etc/hosts entries in emulator CI scripts
DenBond7 May 10, 2026
b1fbe04
Removed hosts file modifications and adb remount from ci-wait-for-emu…
DenBond7 May 10, 2026
50a6484
Updated ci-wait-for-emulator.sh to restart adb if root fails
DenBond7 May 10, 2026
affd17d
Updated ci-setup-and-run-emulator.sh to use avdmanager for AVD deletion
DenBond7 May 10, 2026
f60401a
Commented out debug logging in ci-setup-and-run-emulator.sh
DenBond7 May 10, 2026
2de6140
Added DNS initialization check to ci-wait-for-emulator.sh
DenBond7 May 10, 2026
3b48b9d
Updated ci-wait-for-emulator.sh to increase ping attempts and remove …
DenBond7 May 10, 2026
0352bb8
Added network diagnostic logging and improved ping verification in ci…
DenBond7 May 10, 2026
5117b2f
Enabled HTTP logging and updated CI configuration to run debug instru…
DenBond7 May 10, 2026
6c80d2e
Refactored ci-wait-for-emulator.sh to improve network setup and verif…
DenBond7 May 10, 2026
a2f4c81
Added CI failure debug script and updated Semaphore configuration
DenBond7 May 11, 2026
0d1b07f
Add Ubuntu 24.04 Docker image for Android emulator SDK environment
DenBond7 May 16, 2026
c7ae7df
Refactor Android emulator setup into shared scripts
DenBond7 May 16, 2026
758ed1e
Refactoring
DenBond7 May 16, 2026
5be136f
Slipped KVM for Docker image
DenBond7 May 16, 2026
23de806
Modified Dockerfile
DenBond7 May 16, 2026
725eb51
Modified Dockerfile
DenBond7 May 16, 2026
9ebb935
Modified Dockerfile
DenBond7 May 16, 2026
342fc6d
Added docker/HttpsTestWebServer
DenBond7 May 16, 2026
9edc6ee
Updated docker/TestEnvironment
DenBond7 May 16, 2026
9cf7f18
ci(android): replace emulator iptables setup with /system/etc/hosts r…
DenBond7 May 20, 2026
dc98698
ci(semaphore): redirect local HTTPS traffic from 443 to mock server o…
DenBond7 May 20, 2026
a1482e6
ci(semaphore): fix emulator routing by redirecting 10.0.2.2:443 to 12…
DenBond7 May 20, 2026
f3239ae
docker(https-test-webserver): run dnsmasq alongside nginx and expose …
DenBond7 May 21, 2026
32e6d71
Modified ci-after-fail-debug.sh
DenBond7 May 21, 2026
39fa9e2
Restored some files
DenBond7 May 21, 2026
f48ee1d
ci(android): force emulator DNS via host and harden 443->1212 redirec…
DenBond7 May 21, 2026
037be64
Improved ci-after-fail-debug.sh
DenBond7 May 21, 2026
ff8d20e
Added ci-setup-DNS.sh
DenBond7 May 21, 2026
318af19
Fix ci-setup-DNS.sh usage on CI
DenBond7 May 21, 2026
aeec4a0
Fixed ci-setup-DNS.sh
DenBond7 May 21, 2026
7a6e3d0
Modified ci-wait-for-emulator.sh
DenBond7 May 21, 2026
c562beb
Modified ci-wait-for-emulator.sh and run-emulator.sh
DenBond7 May 21, 2026
4a59a47
wip
DenBond7 May 21, 2026
4dc1083
Restored ci-instrumentation-tests-flaky.sh
DenBond7 May 21, 2026
1becded
Restored build.gradle.kts
DenBond7 May 21, 2026
d62a1aa
i(dns): align HttpsTestWebServer dnsmasq with CI DNS setup and add st…
DenBond7 May 21, 2026
6f069bd
Restored some configurations in semaphore.yml
DenBond7 May 21, 2026
f642175
Updated gradle to 9.5.1
DenBond7 May 21, 2026
da8fa23
Improved ci-wait-for-emulator.sh
DenBond7 May 21, 2026
039354e
docker(test-env): route emulator DNS via host dnsmasq and document ho…
DenBond7 May 21, 2026
575da34
Temporary disabled ComposeScreenPasswordProtectedDisallowedTermsReFet…
DenBond7 May 21, 2026
82ec651
Improved ci-wait-for-emulator.sh
DenBond7 May 21, 2026
e615d4d
Updated docker/TestEnvironment/Dockerfile
DenBond7 May 21, 2026
f2905bb
docs(readme): align DNS test setup docs with ci-setup-DNS.sh
DenBond7 May 21, 2026
63711c0
docs(readme): fixed redundant git difference
DenBond7 May 21, 2026
51a607b
switched to use -gpu auto for emulators on CI
DenBond7 May 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 12 additions & 36 deletions .semaphore/semaphore.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,47 +25,28 @@ global_job_config:
value: /home/semaphore/Android/Sdk
prologue:
commands:
# fix DNS to ping *.localhost and *.flowcrypt.test
- sudo apt-get update
- sudo apt install -y dnsmasq resolvconf
- echo "#added by flowcrypt" | sudo tee -a /etc/dnsmasq.conf
- echo "listen-address=127.0.0.1" | sudo tee -a /etc/dnsmasq.conf
- echo "address=/test/127.0.0.1" | sudo tee -a /etc/dnsmasq.conf
- echo "address=/localhost/127.0.0.1" | sudo tee -a /etc/dnsmasq.conf
- echo "server=8.8.8.8" | sudo tee -a /etc/dnsmasq.conf
# redirect the systemd-resolved to use the localhost as the primary nameserver
- sudo sed -i '1inameserver 127.0.0.1\' /etc/resolv.conf
- sudo systemctl restart dnsmasq
# print some debug info
- ping fel.localhost -c 1
- ping fel.flowcrypt.test -c 1
# use JAVA 21 by default
- sem-version java 21
# general settings
- export PATH=${ANDROID_HOME}/emulator:${ANDROID_HOME}/cmdline-tools/latest/bin:${ANDROID_HOME}/platform-tools:${PATH}
- sudo rm -rf ~/.rbenv ~/.phpbrew
- checkout
# fix DNS to ping *.localhost and *.flowcrypt.test
- ./script/ci-setup-DNS.sh
# 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:
Expand All @@ -79,27 +60,20 @@ 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:
Expand Down Expand Up @@ -188,6 +162,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:
Expand Down
2 changes: 0 additions & 2 deletions FlowCrypt/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import okhttp3.mockwebserver.Dispatcher
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.RecordedRequest
import org.hamcrest.Matchers.allOf
import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.rules.RuleChain
Expand All @@ -63,6 +64,7 @@ import java.util.concurrent.TimeUnit
subject = "",
isNew = true
)
@Ignore("temporary disabled")
class ComposeScreenPasswordProtectedDisallowedTermsReFetchConfigurationFlowTest :
BaseComposeScreenPasswordProtectedDisallowedTermsTest(
ACCOUNT_ENTITY_WITH_EXISTING_OPTIONAL_PARAMETERS
Expand Down
16 changes: 9 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,20 @@ This guide follows Google's recommendations for [testing apps on Android](https:
Please follow these steps to setup your virtual or physical device:

- [Set up your test environment](https://developer.android.com/training/testing/espresso/setup#set-up-environment).
- Some of the tests use [MockWebServer](https://github.com/square/okhttp/tree/master/mockwebserver). We run a local mock web server via [FlowCryptMockWebServerRule](https://github.com/FlowCrypt/flowcrypt-android/blob/master/FlowCrypt/src/androidTest/java/com/flowcrypt/email/rules/FlowCryptMockWebServerRule.kt). It uses [TestConstants.MOCK_WEB_SERVER_PORT](https://github.com/FlowCrypt/flowcrypt-android/blob/master/FlowCrypt/src/androidTest/java/com/flowcrypt/email/TestConstants.kt#L19) as a port. Unfortunately, the Android system doesn't allow us to use the `HTTPS 433` port by default to run a web server on the `localhost (127.0.0.1)`. That's why we have to run a mock web server on another port (for example, `1212`) and route all traffic from `127.0.0.1:433` to `127.0.0.1:1212`. For that purpose, you can use the [script/ci-wait-for-emulator.sh](https://github.com/FlowCrypt/flowcrypt-android/blob/master/script/ci-wait-for-emulator.sh#L13) script.
- Some of the tests use [MockWebServer](https://github.com/square/okhttp/tree/master/mockwebserver). We run a local mock web server via [FlowCryptMockWebServerRule](https://github.com/FlowCrypt/flowcrypt-android/blob/master/FlowCrypt/src/androidTest/java/com/flowcrypt/email/rules/FlowCryptMockWebServerRule.kt). It uses [TestConstants.MOCK_WEB_SERVER_PORT](https://github.com/FlowCrypt/flowcrypt-android/blob/master/FlowCrypt/src/androidTest/java/com/flowcrypt/email/TestConstants.kt#L19) as a port. Unfortunately, the Android system doesn't allow us to use the `HTTPS 443` port by default to run a web server on the `localhost (127.0.0.1)`. That's why we have to run a mock web server on another port (for example, `1212`) and route all traffic from `127.0.0.1:443` to `127.0.0.1:1212`. For that purpose, you can use the [script/ci-wait-for-emulator.sh](https://github.com/FlowCrypt/flowcrypt-android/blob/master/script/ci-wait-for-emulator.sh#L13) script.
- Additionally, the test environment should handle all requests to `*.flowcrypt.test`. All traffic to `*.flowcrypt.test` should be routed to `localhost (127.0.0.1)`. You can use a DNS server to do this. For example, using these commands:

```bash
1. sudo apt install -y dnsmasq resolvconf
2. echo "#added by flowcrypt" | sudo tee -a /etc/dnsmasq.conf
3. echo "listen-address=127.0.0.1" | sudo tee -a /etc/dnsmasq.conf
4. echo "address=/flowcrypt.test/127.0.0.1" | sudo tee -a /etc/dnsmasq.conf
5. echo "address=/localhost/127.0.0.1" | sudo tee -a /etc/dnsmasq.conf
6. sudo systemctl restart dnsmasq
./script/ci-setup-DNS.sh
```

The script:
- Installs `dnsmasq` and `dnsutils`.
- Creates `/etc/dnsmasq.d/flowcrypt.conf` with local rules for `*.test` and `*.localhost`.
- Sets `no-resolv` with upstream DNS servers (`8.8.8.8` and `1.1.1.1`).
- Sets `/etc/resolv.conf` to `nameserver 127.0.0.1`.
- Restarts `dnsmasq` and verifies resolution with `dig` and `ping`.

### ✔️ Test types

We have two types of tests:
Expand Down
17 changes: 17 additions & 0 deletions docker/HttpsTestWebServer/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
FROM nginx:1.27-alpine

RUN apk add --no-cache dnsmasq bind-tools iputils

COPY docker/HttpsTestWebServer/nginx.conf /etc/nginx/conf.d/default.conf

COPY FlowCrypt/src/androidTest/resources/ssl/server_combined.pem \
/etc/nginx/certs/server_combined.pem

COPY docker/HttpsTestWebServer/dnsmasq.conf /etc/dnsmasq.d/flowcrypt-test.conf
COPY docker/HttpsTestWebServer/entrypoint.sh /entrypoint.sh

RUN chmod +x /entrypoint.sh

EXPOSE 53/udp 53/tcp 443

ENTRYPOINT ["/entrypoint.sh"]
17 changes: 17 additions & 0 deletions docker/HttpsTestWebServer/dnsmasq.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
bind-interfaces
listen-address=127.0.0.1
port=53

# Do not read /etc/resolv.conf to avoid recursive localhost DNS loops.
no-resolv

# Upstream DNS for public domains.
server=8.8.8.8
server=1.1.1.1

# Local test domains.
address=/test/127.0.0.1
address=/localhost/127.0.0.1

log-queries
log-facility=-
25 changes: 25 additions & 0 deletions docker/HttpsTestWebServer/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/bin/sh

#
# © 2016-present FlowCrypt a.s. Limitations apply. Contact human@flowcrypt.com
# Contributors: denbond7
#

set -e

dnsmasq --no-daemon --conf-file=/etc/dnsmasq.d/flowcrypt-test.conf --log-facility=- &

echo "Configuring resolver to use dnsmasq..."
printf "nameserver 127.0.0.1\n" > /etc/resolv.conf

echo "Checking dnsmasq directly..."
dig @127.0.0.1 fel.localhost +short
dig @127.0.0.1 fel.flowcrypt.test +short
dig @127.0.0.1 www.google.com +short

echo "Checking resolver..."
ping -c 1 fel.localhost
ping -c 1 fel.flowcrypt.test
ping -c 1 www.google.com

exec nginx -g 'daemon off;'
15 changes: 15 additions & 0 deletions docker/HttpsTestWebServer/nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
server {
listen 443 ssl;

server_name
flowcrypt.test
*.flowcrypt.test;

ssl_certificate /etc/nginx/certs/server_combined.pem;
ssl_certificate_key /etc/nginx/certs/server_combined.pem;

location / {
default_type text/plain;
return 200 "hello from docker https mock server\n";
}
}
16 changes: 16 additions & 0 deletions docker/HttpsTestWebServer/rebuild.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/env bash

#
# © 2016-present FlowCrypt a.s. Limitations apply. Contact human@flowcrypt.com
# Contributors: denbond7
#

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(realpath "$SCRIPT_DIR/../..")"

docker build \
-t flowcrypt-https-test-server \
-f "$SCRIPT_DIR/Dockerfile" \
"$REPO_ROOT"
17 changes: 17 additions & 0 deletions docker/HttpsTestWebServer/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/usr/bin/env bash

#
# © 2016-present FlowCrypt a.s. Limitations apply. Contact human@flowcrypt.com
# Contributors: denbond7
#

set -euo pipefail

docker rm -f flowcrypt-https-test-server 2>/dev/null || true

docker run --rm \
--name flowcrypt-https-test-server \
--network host \
--cap-add NET_ADMIN \
--cap-add NET_BIND_SERVICE \
flowcrypt-https-test-server
47 changes: 47 additions & 0 deletions docker/TestEnvironment/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
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 \
iputils-ping \
dnsutils \
git \
sudo \
&& 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
COPY script/ci-wait-for-emulator.sh /opt/flowcrypt/scripts/ci-wait-for-emulator.sh
RUN chmod +x /opt/flowcrypt/scripts/create-avd.sh /opt/flowcrypt/scripts/run-emulator.sh /opt/flowcrypt/scripts/ci-wait-for-emulator.sh

WORKDIR /workspace

CMD ["/bin/bash"]
Loading
Loading