Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
16 changes: 9 additions & 7 deletions .github/workflows/build-kalium-unified.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:

jvm-tests:
if: inputs.run-quality-checks
needs: [detekt]
needs: [ detekt ]
runs-on: ubuntu-latest
steps:
- name: Checkout
Expand All @@ -50,11 +50,13 @@ jobs:

android-tests:
if: inputs.run-quality-checks
needs: [detekt]
needs: [ detekt ]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0

- name: Setup Java and Gradle
uses: ./.github/actions/setup-java-gradle
Expand All @@ -65,15 +67,15 @@ jobs:
env:
GITHUB_USER: ${{ github.actor }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: ./gradlew testAndroidHostTest -x :core:cryptography:testAndroidHostTest
run: ./gradlew runAndroidUnitTests

android-connected-tests:
if: inputs.run-quality-checks
needs: [detekt]
needs: [ detekt ]
runs-on: ubuntu-latest
strategy:
matrix:
api-level: [31]
api-level: [ 31 ]
steps:
- name: Checkout
uses: actions/checkout@v6
Expand Down Expand Up @@ -130,7 +132,7 @@ jobs:

ios-tests:
if: inputs.run-quality-checks
needs: [detekt]
needs: [ detekt ]
runs-on: macos-15
steps:
- name: Setup Xcode
Expand All @@ -153,7 +155,7 @@ jobs:
# ── Build Matrix ───────────────────────────────────────────────
build:
name: "Build ${{ matrix.platform }}"
needs: [jvm-tests, android-tests, android-connected-tests, ios-tests]
needs: [ jvm-tests, android-tests, android-connected-tests, ios-tests ]
# When quality checks are skipped, run immediately
if: |
always() &&
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/gradle-android-unit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,15 @@ jobs:
with:
name: test-results
path: |
./**/build/test-results/testDebugUnitTest/**/*.xml
./**/build/test-results/testAndroidHostTest/**/*.xml
./**/build/test-results/**/*.xml

- name: Publish Unit Test Results
uses: EnricoMi/publish-unit-test-result-action/linux@v2
if: ${{ always() }}
with:
files: |
**/build/test-results/testDebugUnitTest/**/*.xml
**/build/test-results/testAndroidHostTest/**/*.xml
**/build/test-results/**/*.xml

- name: Cleanup Gradle Cache
Expand Down
23 changes: 16 additions & 7 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -190,16 +190,25 @@ moduleGraphConfig {
showFullPath.set(true)
}

tasks.register("runAllUnitTests") {
val runAndroidUnitTests = tasks.register("runAndroidUnitTests") {
description = "Runs Android Unit Tests for all subprojects, excluding :core:cryptography."
}

val runAllUnitTests = tasks.register("runAllUnitTests") {
description = "Runs all Unit Tests."
}

rootProject.subprojects {
tasks.findByName("testDebugUnitTest")?.let {
dependsOn(it)
gradle.projectsEvaluated {
rootProject.subprojects.forEach { sub ->
sub.tasks.findByName("testAndroidHostTest")?.let { testTask ->
if (sub.name != "cryptography") {
runAndroidUnitTests.configure { dependsOn(testTask) }
}
runAllUnitTests.configure { dependsOn(testTask) }
}
if (name != "cryptography") {
tasks.findByName("jvmTest")?.let {
dependsOn(it)
if (sub.name != "cryptography") {
sub.tasks.findByName("jvmTest")?.let { jvmTestTask ->
runAllUnitTests.configure { dependsOn(jvmTestTask) }
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion buildSrc/src/main/kotlin/OnlyAffectedTestTask.kt
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ open class OnlyAffectedTestTask : DefaultTask() {
*/
enum class TestTaskConfiguration(val taskName: String, val testTarget: String, val ignoredModules: List<String> = emptyList()) {
ANDROID_INSTRUMENTED_TEST_TASK("connectedAndroidOnlyAffectedTest", "connectedAndroidTest", IGNORED_MODULES),
ANDROID_UNIT_TEST_TASK("androidUnitOnlyAffectedTest", "testDebugUnitTest", IGNORED_MODULES),
ANDROID_UNIT_TEST_TASK("androidUnitOnlyAffectedTest", "testAndroidHostTest", IGNORED_MODULES),
IOS_TEST_TASK("iOSOnlyAffectedTest", "iosSimulatorArm64Test", IGNORED_MODULES);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ fun KotlinMultiplatformAndroidLibraryExtension.commonAndroidLibConfig(
}
withHostTestBuilder {
sourceSetTreeName = "test"
}.configure {
isIncludeAndroidResources = true
}

if (project.file("consumer-proguard-rules.pro").exists()) {
Expand Down
8 changes: 8 additions & 0 deletions core/cryptography/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,14 @@ kotlin {
}
}

tasks.withType<Test>().matching { it.name == "testAndroidHostTest" }.configureEach {
// These tests require CoreCrypto native libraries (loaded via JNA) that are not
// available in the Android host test environment. They run in jvmTest instead.
exclude("**/E2EIClientTest.class")
exclude("**/MLSClientTest.class")
exclude("**/ProteusClientTest.class")
}

project.appleTargets().forEach {
registerCopyTestResourcesTask(it)
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@
*/
package com.wire.kalium.cryptography

@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
actual annotation class IgnoreJvm()
import org.junit.Ignore

actual typealias IgnoreJvm = Ignore
1 change: 1 addition & 0 deletions data/persistence-test/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ kotlin {
implementation(libs.androidtest.runner)
implementation(libs.androidtest.rules)
implementation(libs.androidtest.core)
implementation(libs.robolectric)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Wire
* Copyright (C) 2024 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.wire.kalium.persistence

import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner

/**
* On Android host tests, Robolectric is required to provide the Android
* framework environment (Context, ApplicationProvider, etc.).
*
* JUnit 4 inherits `@RunWith` annotations, so any commonTest class that
* extends this class will automatically use RobolectricTestRunner.
*/
@RunWith(RobolectricTestRunner::class)
actual open class RobolectricTest
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,24 @@ import android.content.Context
import androidx.test.core.app.ApplicationProvider
import com.wire.kalium.persistence.dao.UserIDEntity
import com.wire.kalium.persistence.db.GlobalDatabaseBuilder
import com.wire.kalium.persistence.db.GlobalDatabaseSecret
import com.wire.kalium.persistence.db.PlatformDatabaseData
import com.wire.kalium.persistence.db.UserDatabaseBuilder
import com.wire.kalium.persistence.db.globalDatabaseProvider
import com.wire.kalium.persistence.db.inMemoryDatabase
import com.wire.kalium.persistence.db.userDatabaseBuilder
import com.wire.kalium.persistence.util.FileNameUtil
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestDispatcher

internal actual fun createTestDatabase(userId: UserIDEntity, dispatcher: TestDispatcher): UserDatabaseBuilder {
return inMemoryDatabase(
ApplicationProvider.getApplicationContext(),
userId,
dispatcher = dispatcher
// passphrase is forced to null on host tests because SQLCipher
// native libraries are not available in the Robolectric environment.
return userDatabaseBuilder(
platformDatabaseData = PlatformDatabaseData(ApplicationProvider.getApplicationContext()),
userId = userId,
passphrase = null,
dispatcher = dispatcher,
enableWAL = true,
dbInvalidationControlEnabled = false
)
}

Expand All @@ -45,9 +49,11 @@ internal actual fun deleteTestDatabase(userId: UserIDEntity) {
}

internal actual fun createTestGlobalDatabase(): GlobalDatabaseBuilder {
// passphrase is forced to null on host tests because SQLCipher
// native libraries are not available in the Robolectric environment.
return globalDatabaseProvider(
platformDatabaseData = PlatformDatabaseData(ApplicationProvider.getApplicationContext()),
passphrase = GlobalDatabaseSecret("test_db_secret".toByteArray()),
passphrase = null,
enableWAL = true,
queriesContext = StandardTestDispatcher()
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Wire
* Copyright (C) 2024 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.wire.kalium.persistence

actual open class RobolectricTest
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Wire
* Copyright (C) 2024 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.wire.kalium.persistence

/**
* Base class for tests that need Android framework APIs (e.g., database access via
* [TestUserDatabase] or [TestGlobalDatabase]).
*
* On Android host tests this resolves to an actual class annotated with
* `@RunWith(RobolectricTestRunner::class)`, ensuring the Android environment is
* available. On all other platforms it is an empty open class.
*/
expect open class RobolectricTest()
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Wire
* Copyright (C) 2024 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.wire.kalium.persistence

actual open class RobolectricTest
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Wire
* Copyright (C) 2024 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.wire.kalium.persistence

actual open class RobolectricTest
11 changes: 11 additions & 0 deletions data/persistence/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,21 @@ kotlin {
implementation(libs.sql.android.cipher)
}
}
val androidHostTest by getting {
dependencies {
implementation(libs.robolectric)
implementation(libs.core.ktx)
}
}
val appleMain by getting {
dependencies {
implementation(libs.sqldelight.nativeDriver)
}
}
}
}

tasks.withType<Test>().matching { it.name == "testAndroidHostTest" }.configureEach {
exclude("**/BaseDatabaseTest.class")
exclude("**/BaseMessageTest.class")
}
Loading
Loading