diff --git a/.github/workflows/android-app.yml b/.github/workflows/android-app.yml
index f6d56f318b37..1608bff1302b 100644
--- a/.github/workflows/android-app.yml
+++ b/.github/workflows/android-app.yml
@@ -201,7 +201,16 @@ jobs:
uses: burrunan/gradle-cache-action@v1
with:
job-id: jdk17
- arguments: testDebugUnitTest
+ arguments: testDebugUnitTest -x :test:arch:testDebugUnitTest
+ gradle-version: wrapper
+ build-root-directory: android
+ execution-only-caches: true
+
+ - name: Run arch tests
+ uses: burrunan/gradle-cache-action@v1
+ with:
+ job-id: jdk17
+ arguments: :test:arch:test
gradle-version: wrapper
build-root-directory: android
execution-only-caches: true
diff --git a/android/buildSrc/src/main/kotlin/Dependencies.kt b/android/buildSrc/src/main/kotlin/Dependencies.kt
index 2aa2db27d61e..80c33136835d 100644
--- a/android/buildSrc/src/main/kotlin/Dependencies.kt
+++ b/android/buildSrc/src/main/kotlin/Dependencies.kt
@@ -4,9 +4,10 @@ object Dependencies {
const val commonsValidator = "commons-validator:commons-validator:${Versions.commonsValidator}"
const val jodaTime = "joda-time:joda-time:${Versions.jodaTime}"
const val junit = "junit:junit:${Versions.junit}"
+ const val konsist = "com.lemonappdev:konsist:${Versions.konsist}"
const val leakCanary = "com.squareup.leakcanary:leakcanary-android:${Versions.leakCanary}"
- const val turbine = "app.cash.turbine:turbine:${Versions.turbine}"
const val mockkWebserver = "com.squareup.okhttp3:mockwebserver:${Versions.mockWebserver}"
+ const val turbine = "app.cash.turbine:turbine:${Versions.turbine}"
object AndroidX {
const val appcompat = "androidx.appcompat:appcompat:${Versions.AndroidX.appcompat}"
diff --git a/android/buildSrc/src/main/kotlin/Versions.kt b/android/buildSrc/src/main/kotlin/Versions.kt
index d10c7e252bab..553c952748e1 100644
--- a/android/buildSrc/src/main/kotlin/Versions.kt
+++ b/android/buildSrc/src/main/kotlin/Versions.kt
@@ -3,6 +3,7 @@ object Versions {
const val jodaTime = "2.12.5"
const val junit = "4.13.2"
const val jvmTarget = "17"
+ const val konsist = "0.11.0"
const val kotlin = "1.9.10"
const val kotlinCompilerExtensionVersion = "1.5.3"
const val kotlinx = "1.7.3"
diff --git a/android/gradle.properties b/android/gradle.properties
index 3f3bea5a6633..4233d36b8265 100644
--- a/android/gradle.properties
+++ b/android/gradle.properties
@@ -1,4 +1,3 @@
-android.enableJetifier=true
android.enableR8.fullMode=true
android.defaults.buildfeatures.buildconfig=true
android.nonTransitiveRClass=false
diff --git a/android/gradle/verification-metadata.xml b/android/gradle/verification-metadata.xml
index 98f3a9dd9452..6aca8d73fad0 100644
--- a/android/gradle/verification-metadata.xml
+++ b/android/gradle/verification-metadata.xml
@@ -2222,6 +2222,14 @@
+
+
+
+
+
+
+
+
@@ -3178,6 +3186,11 @@
+
+
+
+
+
@@ -3451,6 +3464,11 @@
+
+
+
+
+
@@ -3476,6 +3494,11 @@
+
+
+
+
+
@@ -3491,6 +3514,11 @@
+
+
+
+
+
@@ -3516,6 +3544,11 @@
+
+
+
+
+
@@ -3671,6 +3704,11 @@
+
+
+
+
+
diff --git a/android/settings.gradle.kts b/android/settings.gradle.kts
index 5df9c08f1e07..e47f3c08f950 100644
--- a/android/settings.gradle.kts
+++ b/android/settings.gradle.kts
@@ -1,5 +1,8 @@
-include(":app", ":service", ":tile")
-
+include(
+ ":app",
+ ":service",
+ ":tile"
+)
include(
":lib:common",
":lib:endpoint",
@@ -10,5 +13,10 @@ include(
":lib:theme",
":lib:common-test"
)
-
-include(":test", ":test:common", ":test:e2e", ":test:mockapi")
+include(
+ ":test",
+ ":test:arch",
+ ":test:common",
+ ":test:e2e",
+ ":test:mockapi"
+)
diff --git a/android/test/arch/build.gradle.kts b/android/test/arch/build.gradle.kts
new file mode 100644
index 000000000000..0a28fd2fab3c
--- /dev/null
+++ b/android/test/arch/build.gradle.kts
@@ -0,0 +1,42 @@
+plugins {
+ id(Dependencies.Plugin.androidLibraryId)
+ id(Dependencies.Plugin.kotlinAndroidId)
+}
+
+android {
+ namespace = "net.mullvad.mullvadvpn.test.arch"
+ compileSdk = Versions.Android.compileSdkVersion
+
+ defaultConfig {
+ minSdk = Versions.Android.minSdkVersion
+ }
+
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+ }
+
+ kotlinOptions {
+ jvmTarget = Versions.jvmTarget
+ }
+
+ lint {
+ lintConfig = file("${rootProject.projectDir}/config/lint.xml")
+ abortOnError = true
+ warningsAsErrors = true
+ }
+}
+
+androidComponents {
+ beforeVariants { variantBuilder ->
+ variantBuilder.apply {
+ enable = name != "release"
+ }
+ }
+}
+
+dependencies {
+ testImplementation(Dependencies.AndroidX.appcompat)
+ testImplementation(Dependencies.junit)
+ testImplementation(Dependencies.konsist)
+}
diff --git a/android/test/arch/src/test/AndroidManifest.xml b/android/test/arch/src/test/AndroidManifest.xml
new file mode 100644
index 000000000000..cc947c567995
--- /dev/null
+++ b/android/test/arch/src/test/AndroidManifest.xml
@@ -0,0 +1 @@
+
diff --git a/android/test/arch/src/test/kotlin/net/mullvad/mullvadvpn/test/arch/ViewModelTests.kt b/android/test/arch/src/test/kotlin/net/mullvad/mullvadvpn/test/arch/ViewModelTests.kt
new file mode 100644
index 000000000000..35ffe52c312d
--- /dev/null
+++ b/android/test/arch/src/test/kotlin/net/mullvad/mullvadvpn/test/arch/ViewModelTests.kt
@@ -0,0 +1,16 @@
+package net.mullvad.mullvadvpn.test.arch
+
+import androidx.lifecycle.ViewModel
+import com.lemonappdev.konsist.api.Konsist
+import com.lemonappdev.konsist.api.ext.list.withAllParentsOf
+import com.lemonappdev.konsist.api.verify.assert
+import org.junit.Test
+
+class ViewModelTests {
+ @Test
+ fun ensureViewModelsHaveViewModelSuffix() {
+ Konsist.scopeFromProject().classes().withAllParentsOf(ViewModel::class).assert {
+ it.name.endsWith("ViewModel")
+ }
+ }
+}