Skip to content

Commit 4e8c3e6

Browse files
committed
Merge branch 'master' into dependabot/gradle/com.android.application-9.2.0
# Conflicts: # gradle/wrapper/gradle-wrapper.properties
2 parents 551f344 + 96cc05f commit 4e8c3e6

38 files changed

Lines changed: 998 additions & 164 deletions

.github/CODEOWNERS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# These owners will be the default owners for everything in the repo.
22
# Unless a later match takes precedence,
33
# these owners will be requested for review when someone opens a pull request.
4-
* @DenBond7 @ioanatflowcrypt
4+
* @DenBond7 @sosnovsky
55

66
# The following files will no have codeowners to allow dependabot auto-merge
77
# based on https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features

.idea/gradle.xml

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.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: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,15 @@ if (propertiesFile.exists()) {
3030
keystoreProperties.load(FileInputStream(propertiesFile))
3131
}
3232

33+
kotlin {
34+
jvmToolchain(21)
35+
36+
compilerOptions {
37+
jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_21)
38+
freeCompilerArgs.add("-opt-in=kotlin.RequiresOptIn")
39+
}
40+
}
41+
3342
android {
3443
compileSdk = rootProject.extra["compileSdkVersion"] as Int
3544
namespace = "com.flowcrypt.email"
@@ -392,20 +401,6 @@ easylauncher {
392401
}
393402
}
394403

395-
java {
396-
toolchain {
397-
languageVersion.set(JavaLanguageVersion.of(21))
398-
}
399-
}
400-
401-
402-
kotlin {
403-
compilerOptions {
404-
jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_21)
405-
freeCompilerArgs.add("-opt-in=kotlin.RequiresOptIn")
406-
}
407-
}
408-
409404
tasks.register("checkCorrectBranch") {
410405
if (!grgit.branch.current().name.equals("master")) {
411406
throw GradleException("Please use 'master' branch to generate a release build")
@@ -467,7 +462,7 @@ dependencies {
467462
androidTestImplementation("androidx.test.uiautomator:uiautomator:2.3.0")
468463
androidTestImplementation("androidx.room:room-testing:2.8.4")
469464
androidTestImplementation("androidx.arch.core:core-testing:2.2.0")
470-
androidTestImplementation("androidx.work:work-testing:2.11.0")
465+
androidTestImplementation("androidx.work:work-testing:2.11.2")
471466
androidTestImplementation("com.squareup.okhttp3:mockwebserver:5.3.2")
472467
androidTestImplementation("com.squareup.okhttp3:okhttp-tls:5.3.2")
473468
androidTestImplementation("com.athaydes.rawhttp:rawhttp-core:2.6.0")
@@ -489,7 +484,7 @@ dependencies {
489484
implementation("androidx.appcompat:appcompat:1.7.1")
490485
implementation("androidx.legacy:legacy-preference-v14:1.0.0")
491486
implementation("androidx.cardview:cardview:1.0.0")
492-
implementation("androidx.browser:browser:1.9.0")
487+
implementation("androidx.browser:browser:1.10.0")
493488
implementation("androidx.recyclerview:recyclerview:1.4.0")
494489
implementation("androidx.recyclerview:recyclerview-selection:1.2.0")
495490
implementation("androidx.constraintlayout:constraintlayout:2.2.1")
@@ -506,30 +501,30 @@ dependencies {
506501
//noinspection GradleDependency
507502
implementation("androidx.paging:paging-runtime-ktx:2.1.2")
508503
implementation("androidx.preference:preference-ktx:1.2.1")
509-
implementation("androidx.core:core-ktx:1.17.0")
504+
implementation("androidx.core:core-ktx:1.18.0")
510505
implementation("androidx.core:core-splashscreen:1.2.0")
511506
implementation("androidx.activity:activity-ktx:1.12.2")
512507
implementation("androidx.fragment:fragment-ktx:1.8.9")
513-
implementation("androidx.work:work-runtime-ktx:2.11.0")
514-
implementation("androidx.navigation:navigation-fragment-ktx:2.9.6")
515-
implementation("androidx.navigation:navigation-ui-ktx:2.9.6")
516-
implementation("androidx.navigation:navigation-runtime-ktx:2.9.6")
508+
implementation("androidx.work:work-runtime-ktx:2.11.2")
509+
implementation("androidx.navigation:navigation-fragment-ktx:2.9.8")
510+
implementation("androidx.navigation:navigation-ui-ktx:2.9.8")
511+
implementation("androidx.navigation:navigation-runtime-ktx:2.9.8")
517512
implementation("androidx.webkit:webkit:1.15.0")
518513

519514
implementation("com.google.android.gms:play-services-base:18.10.0")
520515
implementation("com.google.android.gms:play-services-auth:21.5.0")
521516
implementation("com.google.android.material:material:1.13.0")
522517
implementation("com.google.android.flexbox:flexbox:3.0.0")
523518
implementation("com.google.code.gson:gson:2.13.2")
524-
implementation("com.google.api-client:google-api-client-android:2.8.1")
519+
implementation("com.google.api-client:google-api-client-android:2.9.0")
525520
implementation("com.google.apis:google-api-services-gmail:v1-rev20251201-2.0.0")
526521
//ACRA needs the following dependency to use a custom report sender
527522
implementation("com.google.auto.service:auto-service-annotations:1.1.1")
528523

529524
implementation("com.squareup.retrofit2:retrofit:3.0.0")
530525
implementation("com.squareup.retrofit2:converter-gson:3.0.0")
531526
implementation("com.squareup.retrofit2:converter-scalars:3.0.0")
532-
implementation("com.squareup.okio:okio:3.16.4")
527+
implementation("com.squareup.okio:okio:3.17.0")
533528
implementation("com.squareup.okhttp3:logging-interceptor:5.3.2")
534529

535530
implementation("com.github.bumptech.glide:glide:5.0.7")
@@ -546,7 +541,7 @@ dependencies {
546541
implementation("org.pgpainless:pgpainless-core:2.0.2")
547542
implementation("org.eclipse.angus:angus-mail:2.0.5")
548543
implementation("org.eclipse.angus:gimap:2.0.5")
549-
implementation("commons-io:commons-io:2.21.0")
544+
implementation("commons-io:commons-io:2.22.0")
550545
implementation("net.openid:appauth:0.11.1")
551546
implementation("ch.acra:acra-http:5.13.1")
552547
implementation("io.github.everythingme:overscroll-decor-android:1.1.1")

FlowCrypt/src/androidTest/java/com/flowcrypt/email/ui/AddOtherAccountFlowTest.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import com.flowcrypt.email.util.AuthCredentialsManager
3131
import com.flowcrypt.email.util.TestGeneralUtil
3232
import org.hamcrest.Matchers.anyOf
3333
import org.hamcrest.Matchers.startsWith
34+
import org.junit.Ignore
3435
import org.junit.Rule
3536
import org.junit.Test
3637
import org.junit.rules.RuleChain
@@ -61,6 +62,7 @@ class AddOtherAccountFlowTest : AddOtherAccountBaseTest() {
6162
@Test
6263
//@Ignore("flaky 8")
6364
//RepeatableAndroidJUnit4ClassRunner 50 attempts passed
65+
@Ignore("flaky. Temporary disabled")
6466
fun testShowWarningIfAuthFail() {
6567
enableAdvancedMode()
6668
val credentials = AuthCredentialsManager.getAuthCredentials("user_with_not_existed_server.json")

FlowCrypt/src/androidTest/java/com/flowcrypt/email/ui/ComposeScreenFlowTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ class ComposeScreenFlowTest : BaseComposeScreenTest() {
140140
}
141141

142142
@Test
143+
@Ignore("flaky. Temporary disabled")
143144
fun testEmptyEmailSubject() {
144145
activeActivityRule?.launch(intent)
145146
waitForObjectWithText(

FlowCrypt/src/androidTest/java/com/flowcrypt/email/ui/fragment/isolation/incontainer/CheckCredentialsFragmentInIsolationTest.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import com.flowcrypt.email.rules.ScreenshotTestRule
2424
import com.flowcrypt.email.ui.activity.fragment.CheckCredentialsFragment
2525
import com.flowcrypt.email.ui.activity.fragment.CheckCredentialsFragmentArgs
2626
import org.junit.Assert.assertEquals
27+
import org.junit.Ignore
2728
import org.junit.Rule
2829
import org.junit.Test
2930
import org.junit.rules.RuleChain
@@ -49,6 +50,7 @@ class CheckCredentialsFragmentInIsolationTest : BaseTest() {
4950
.around(ScreenshotTestRule())
5051

5152
@Test
53+
@Ignore("flaky. Temporary disabled")
5254
fun testReturnExceptionForFailedAuthorization() {
5355
val requestKey = UUID.randomUUID().toString()
5456
val scenario = launchFragmentInContainer<CheckCredentialsFragment>(

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"]

0 commit comments

Comments
 (0)