Skip to content

Commit 04bda68

Browse files
authored
Improved Semaphore CI configuration (#3210)
* Updated gradle to 9.5.0 * Updated CI scripts with --no-daemon, --build-cache, and --max-workers=2 flags * Refactored Semaphore CI caching strategy and separated checksums * wip * Refactored CI scripts for improved robustness and emulator handling - Updated shebangs to `#!/usr/bin/env bash` and added `set -euo pipefail` for better error handling. - Improved emulator setup in `ci-setup-and-run-emulator.sh` by ensuring a fresh AVD state and configuring hardware parameters like RAM and GPU. - Optimized `ci-wait-for-emulator.sh` with more reliable boot completion checks and a retry loop for internet connectivity. - Added existence checks for directories and files in artifact and test result publishing scripts to prevent errors when files are missing. - Cleaned up redundant script headers and refactored argument handling in instrumentation test scripts. * Removed --max-workers=2 from CI scripts and semaphore configuration * Removed native and redundant build caches from Semaphore configuration * Removed ninja-build installation from semaphore.yml * Configured emulator DNS server and added resolution checks in CI scripts * Replaced -dns-server flag with /etc/hosts entries in emulator CI scripts * Removed hosts file modifications and adb remount from ci-wait-for-emulator.sh * Updated ci-wait-for-emulator.sh to restart adb if root fails * Updated ci-setup-and-run-emulator.sh to use avdmanager for AVD deletion * Commented out debug logging in ci-setup-and-run-emulator.sh * Added DNS initialization check to ci-wait-for-emulator.sh * Updated ci-wait-for-emulator.sh to increase ping attempts and remove DNS property checks * Added network diagnostic logging and improved ping verification in ci-wait-for-emulator.sh * Enabled HTTP logging and updated CI configuration to run debug instrumentation tests * Refactored ci-wait-for-emulator.sh to improve network setup and verification * Added CI failure debug script and updated Semaphore configuration * Add Ubuntu 24.04 Docker image for Android emulator SDK environment * Refactor Android emulator setup into shared scripts * Refactoring * Slipped KVM for Docker image * Modified Dockerfile * Modified Dockerfile * Modified Dockerfile * Added docker/HttpsTestWebServer * Updated docker/TestEnvironment * ci(android): replace emulator iptables setup with /system/etc/hosts routing for flowcrypt.test domains * ci(semaphore): redirect local HTTPS traffic from 443 to mock server on 1212 for emulator UI tests * ci(semaphore): fix emulator routing by redirecting 10.0.2.2:443 to 1212 and add fes.flowcrypt.test host mapping * docker(https-test-webserver): run dnsmasq alongside nginx and expose host DNS for *.flowcrypt.test - install dnsmasq in HttpsTestWebServer image - add dnsmasq config mapping *.flowcrypt.test to 127.0.0.1 - add entrypoint to start dnsmasq and nginx in one container - switch run.sh to host networking with NET_ADMIN/NET_BIND_SERVICE - expose DNS ports (53 tcp/udp) and HTTPS (443) * Modified ci-after-fail-debug.sh * Restored some files * ci(android): force emulator DNS via host and harden 443->1212 redirect for flowcrypt.test tests * Improved ci-after-fail-debug.sh * Added ci-setup-DNS.sh * Fix ci-setup-DNS.sh usage on CI * Fixed ci-setup-DNS.sh * Modified ci-wait-for-emulator.sh * Modified ci-wait-for-emulator.sh and run-emulator.sh * wip * Restored ci-instrumentation-tests-flaky.sh * Restored build.gradle.kts * i(dns): align HttpsTestWebServer dnsmasq with CI DNS setup and add startup DNS checks * Restored some configurations in semaphore.yml * Updated gradle to 9.5.1 * Improved ci-wait-for-emulator.sh * docker(test-env): route emulator DNS via host dnsmasq and document host-network adb behavior * Temporary disabled ComposeScreenPasswordProtectedDisallowedTermsReFetchConfigurationFlowTest.kt * Improved ci-wait-for-emulator.sh * Updated docker/TestEnvironment/Dockerfile * docs(readme): align DNS test setup docs with ci-setup-DNS.sh Alternative: docs: replace manual dnsmasq steps with ci-setup-DNS.sh usage * docs(readme): fixed redundant git difference * switched to use -gpu auto for emulators on CI
1 parent 2509c32 commit 04bda68

31 files changed

Lines changed: 958 additions & 139 deletions

.semaphore/semaphore.yml

Lines changed: 12 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -25,47 +25,28 @@ global_job_config:
2525
value: /home/semaphore/Android/Sdk
2626
prologue:
2727
commands:
28-
# fix DNS to ping *.localhost and *.flowcrypt.test
2928
- sudo apt-get update
30-
- sudo apt install -y dnsmasq resolvconf
31-
- echo "#added by flowcrypt" | sudo tee -a /etc/dnsmasq.conf
32-
- echo "listen-address=127.0.0.1" | sudo tee -a /etc/dnsmasq.conf
33-
- echo "address=/test/127.0.0.1" | sudo tee -a /etc/dnsmasq.conf
34-
- echo "address=/localhost/127.0.0.1" | sudo tee -a /etc/dnsmasq.conf
35-
- echo "server=8.8.8.8" | sudo tee -a /etc/dnsmasq.conf
36-
# redirect the systemd-resolved to use the localhost as the primary nameserver
37-
- sudo sed -i '1inameserver 127.0.0.1\' /etc/resolv.conf
38-
- sudo systemctl restart dnsmasq
39-
# print some debug info
40-
- ping fel.localhost -c 1
41-
- ping fel.flowcrypt.test -c 1
4229
# use JAVA 21 by default
4330
- sem-version java 21
4431
# general settings
4532
- export PATH=${ANDROID_HOME}/emulator:${ANDROID_HOME}/cmdline-tools/latest/bin:${ANDROID_HOME}/platform-tools:${PATH}
4633
- sudo rm -rf ~/.rbenv ~/.phpbrew
4734
- checkout
35+
# fix DNS to ping *.localhost and *.flowcrypt.test
36+
- ./script/ci-setup-DNS.sh
4837
# init environment variables
49-
- export SUM=$(checksum build.gradle.kts)-$(checksum FlowCrypt/build.gradle.kts)-$(checksum ./script/ci-install-android-sdk.sh)
50-
- export APP_GRADLE_CACHE=gradle-cache-$SUM # per conf files hash
51-
- export ANDROID_SDK_CACHE=android-sdk-$SUM # per conf files hash
52-
- export BUILD_CXX_CACHE=build-cxx-cache-$SEMAPHORE_GIT_BRANCH-$SUM # per branch and conf files hash
53-
- export BUILD_NATIVE_CACHE=build-native-cache-$SEMAPHORE_GIT_BRANCH-$SUM # per branch and conf files hash
54-
- export BUILD_CACHE=build-cache-$SEMAPHORE_GIT_BRANCH-$SUM # per branch and conf files hash
38+
- export GRADLE_SUM=$(checksum build.gradle.kts)-$(checksum FlowCrypt/build.gradle.kts)
39+
- export SDK_SUM=$(checksum ./script/ci-install-android-sdk.sh)
40+
- export APP_GRADLE_CACHE=project-gradle-cache-$GRADLE_SUM # project .gradle cache, per Gradle config hash
41+
- export ANDROID_SDK_CACHE=android-sdk-$SDK_SUM # Android SDK cache, per SDK installer hash
5542
# restore app caches
5643
- cache restore $APP_GRADLE_CACHE
57-
- cache restore $BUILD_CXX_CACHE
58-
- cache restore $BUILD_NATIVE_CACHE
59-
- cache restore $BUILD_CACHE
6044
# restore global caches
6145
- cache restore $ANDROID_SDK_CACHE
6246
- cache restore gradle-wrapper
63-
- cache restore gradle-cache
64-
- cache restore android-build-cache
47+
- cache restore gradle-cache-$GRADLE_SUM
6548
# Install Android dependencies if needed
6649
- ./script/ci-install-android-sdk.sh
67-
# Install ninja
68-
- sudo apt install -y ninja-build
6950
blocks:
7051
- name: 'Build'
7152
execution_time_limit:
@@ -79,27 +60,20 @@ blocks:
7960
# print Java version
8061
- java -version
8162
# compile project
82-
- ./gradlew --console=plain assembleConsumerUiTests
63+
- ./gradlew --console=plain --no-daemon --build-cache assembleConsumerUiTests
8364
epilogue:
8465
on_pass:
8566
commands:
8667
# store app cache
8768
- echo "Store the app cache"
8869
- cache has_key $APP_GRADLE_CACHE || cache store $APP_GRADLE_CACHE .gradle
89-
- cache has_key $BUILD_CXX_CACHE || cache store $BUILD_CXX_CACHE FlowCrypt/.cxx
90-
- cache has_key $BUILD_NATIVE_CACHE || cache store $BUILD_NATIVE_CACHE FlowCrypt/.externalNativeBuild
91-
- cache has_key $BUILD_CACHE || cache store $BUILD_CACHE FlowCrypt/build
9270

9371
# clean and store global cache
9472
- echo "Store the global cache"
9573
- find ~/.gradle/caches/ -name "*.lock" -type f -delete # https://medium.com/cirruslabs/mastering-gradle-caching-and-incremental-builds-37eb1af7fcde
9674
- cache has_key $ANDROID_SDK_CACHE || cache store $ANDROID_SDK_CACHE $ANDROID_HOME
97-
- cache delete gradle-wrapper
98-
- cache delete gradle-cache
99-
- cache delete android-build-cache
100-
- cache store gradle-wrapper ~/.gradle/wrapper
101-
- cache store gradle-cache ~/.gradle/caches
102-
- cache store android-build-cache ~/.android/build-cache
75+
- cache has_key gradle-wrapper || cache store gradle-wrapper ~/.gradle/wrapper
76+
- cache has_key gradle-cache-$GRADLE_SUM || cache store gradle-cache-$GRADLE_SUM ~/.gradle/caches
10377

10478
- name: 'Testing'
10579
task:
@@ -188,6 +162,8 @@ blocks:
188162
commands:
189163
# collect and store debug info as artifacts
190164
- ./script/ci-get-and-publish-debug-info-as-artifact.sh
165+
# print debug info
166+
- ./script/ci-after-fail-debug.sh
191167

192168
after_pipeline:
193169
task:

FlowCrypt/build.gradle.kts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66

77
import com.android.build.api.artifact.SingleArtifact
88
import com.android.build.api.variant.ResValue
9-
import org.gradle.api.GradleException
10-
import java.io.File
119
import com.android.ddmlib.DdmPreferences
1210
import java.io.FileInputStream
1311
import java.text.SimpleDateFormat

FlowCrypt/src/androidTest/java/com/flowcrypt/email/ui/gmailapi/passwordprotected/ComposeScreenPasswordProtectedDisallowedTermsReFetchConfigurationFlowTest.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import okhttp3.mockwebserver.Dispatcher
4040
import okhttp3.mockwebserver.MockResponse
4141
import okhttp3.mockwebserver.RecordedRequest
4242
import org.hamcrest.Matchers.allOf
43+
import org.junit.Ignore
4344
import org.junit.Rule
4445
import org.junit.Test
4546
import org.junit.rules.RuleChain
@@ -63,6 +64,7 @@ import java.util.concurrent.TimeUnit
6364
subject = "",
6465
isNew = true
6566
)
67+
@Ignore("temporary disabled")
6668
class ComposeScreenPasswordProtectedDisallowedTermsReFetchConfigurationFlowTest :
6769
BaseComposeScreenPasswordProtectedDisallowedTermsTest(
6870
ACCOUNT_ENTITY_WITH_EXISTING_OPTIONAL_PARAMETERS

README.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,20 @@ This guide follows Google's recommendations for [testing apps on Android](https:
1515
Please follow these steps to setup your virtual or physical device:
1616

1717
- [Set up your test environment](https://developer.android.com/training/testing/espresso/setup#set-up-environment).
18-
- 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.
18+
- 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.
1919
- 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:
2020

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

25+
The script:
26+
- Installs `dnsmasq` and `dnsutils`.
27+
- Creates `/etc/dnsmasq.d/flowcrypt.conf` with local rules for `*.test` and `*.localhost`.
28+
- Sets `no-resolv` with upstream DNS servers (`8.8.8.8` and `1.1.1.1`).
29+
- Sets `/etc/resolv.conf` to `nameserver 127.0.0.1`.
30+
- Restarts `dnsmasq` and verifies resolution with `dig` and `ping`.
31+
3032
### ✔️ Test types
3133

3234
We have two types of tests:
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
FROM nginx:1.27-alpine
2+
3+
RUN apk add --no-cache dnsmasq bind-tools iputils
4+
5+
COPY docker/HttpsTestWebServer/nginx.conf /etc/nginx/conf.d/default.conf
6+
7+
COPY FlowCrypt/src/androidTest/resources/ssl/server_combined.pem \
8+
/etc/nginx/certs/server_combined.pem
9+
10+
COPY docker/HttpsTestWebServer/dnsmasq.conf /etc/dnsmasq.d/flowcrypt-test.conf
11+
COPY docker/HttpsTestWebServer/entrypoint.sh /entrypoint.sh
12+
13+
RUN chmod +x /entrypoint.sh
14+
15+
EXPOSE 53/udp 53/tcp 443
16+
17+
ENTRYPOINT ["/entrypoint.sh"]
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
bind-interfaces
2+
listen-address=127.0.0.1
3+
port=53
4+
5+
# Do not read /etc/resolv.conf to avoid recursive localhost DNS loops.
6+
no-resolv
7+
8+
# Upstream DNS for public domains.
9+
server=8.8.8.8
10+
server=1.1.1.1
11+
12+
# Local test domains.
13+
address=/test/127.0.0.1
14+
address=/localhost/127.0.0.1
15+
16+
log-queries
17+
log-facility=-
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#!/bin/sh
2+
3+
#
4+
# © 2016-present FlowCrypt a.s. Limitations apply. Contact human@flowcrypt.com
5+
# Contributors: denbond7
6+
#
7+
8+
set -e
9+
10+
dnsmasq --no-daemon --conf-file=/etc/dnsmasq.d/flowcrypt-test.conf --log-facility=- &
11+
12+
echo "Configuring resolver to use dnsmasq..."
13+
printf "nameserver 127.0.0.1\n" > /etc/resolv.conf
14+
15+
echo "Checking dnsmasq directly..."
16+
dig @127.0.0.1 fel.localhost +short
17+
dig @127.0.0.1 fel.flowcrypt.test +short
18+
dig @127.0.0.1 www.google.com +short
19+
20+
echo "Checking resolver..."
21+
ping -c 1 fel.localhost
22+
ping -c 1 fel.flowcrypt.test
23+
ping -c 1 www.google.com
24+
25+
exec nginx -g 'daemon off;'
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
server {
2+
listen 443 ssl;
3+
4+
server_name
5+
flowcrypt.test
6+
*.flowcrypt.test;
7+
8+
ssl_certificate /etc/nginx/certs/server_combined.pem;
9+
ssl_certificate_key /etc/nginx/certs/server_combined.pem;
10+
11+
location / {
12+
default_type text/plain;
13+
return 200 "hello from docker https mock server\n";
14+
}
15+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#!/usr/bin/env bash
2+
3+
#
4+
# © 2016-present FlowCrypt a.s. Limitations apply. Contact human@flowcrypt.com
5+
# Contributors: denbond7
6+
#
7+
8+
set -euo pipefail
9+
10+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11+
REPO_ROOT="$(realpath "$SCRIPT_DIR/../..")"
12+
13+
docker build \
14+
-t flowcrypt-https-test-server \
15+
-f "$SCRIPT_DIR/Dockerfile" \
16+
"$REPO_ROOT"

docker/HttpsTestWebServer/run.sh

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#!/usr/bin/env bash
2+
3+
#
4+
# © 2016-present FlowCrypt a.s. Limitations apply. Contact human@flowcrypt.com
5+
# Contributors: denbond7
6+
#
7+
8+
set -euo pipefail
9+
10+
docker rm -f flowcrypt-https-test-server 2>/dev/null || true
11+
12+
docker run --rm \
13+
--name flowcrypt-https-test-server \
14+
--network host \
15+
--cap-add NET_ADMIN \
16+
--cap-add NET_BIND_SERVICE \
17+
flowcrypt-https-test-server

0 commit comments

Comments
 (0)