diff --git a/.github/actions/setup_test_action/action.yml b/.github/actions/setup_test_action/action.yml new file mode 100644 index 000000000..1b18c9db4 --- /dev/null +++ b/.github/actions/setup_test_action/action.yml @@ -0,0 +1,30 @@ +name: 'Setup Tests' +description: 'Prepares to run tests on Firebase emulator' + +runs: + using: "composite" + steps: + - name: Set up JDK + uses: actions/setup-java@v3 + with: + distribution: 'zulu' + java-version: '17' + cache: gradle + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '21.x' + - name: Upgrade packages + shell: bash + run: npm update + - name: Gradle cache + uses: gradle/gradle-build-action@v2 + - name: Grant execute permission for gradlew + shell: bash + run: chmod +x gradlew + - name: Install Firebase tools + shell: bash + run: npm install -g firebase-tools + - name: Start Firebase emulator + shell: bash + run: "firebase emulators:start --config=./test/firebase.json &" \ No newline at end of file diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 39b29643f..88b178bb4 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -8,56 +8,20 @@ on: branches: [ master, prerelease ] jobs: - build: - runs-on: macos-13 + build-android: + runs-on: 4-core-ubuntu strategy: matrix: api-level: [ 34 ] steps: - uses: actions/checkout@v3 - - name: Cocoapods cache - uses: actions/cache@v3 - id: cocoapods-cache - with: - path: | - ~/.cocoapods - ~/Library/Caches/CocoaPods - */build/cocoapods - */build/classes - key: cocoapods-cache - - name: Set up JDK - uses: actions/setup-java@v3 - with: - distribution: 'zulu' - java-version: '17' - cache: gradle - - name: Gradle cache - uses: gradle/gradle-build-action@v2 - - name: Grant execute permission for gradlew - run: chmod +x gradlew - - name: Install Firebase tools - run: npm install -g firebase-tools - - name: Start Firebase emulator - run: "firebase emulators:start --config=./test/firebase.json &" - - name: Run JS Tests - run: ./gradlew cleanTest jsTest - - name: Upload JS test artifact - uses: actions/upload-artifact@v3 - if: failure() - with: - name: "JS Test Report HTML" - path: | - **/build/reports/tests/jsTest/ - **/build/reports/tests/jsBrowserTest/ - **/build/reports/tests/jsNodeTest/ - - name: Run iOS Tests - run: ./gradlew cleanTest iosX64Test - - name: Upload iOS test artifact - uses: actions/upload-artifact@v3 - if: failure() - with: - name: "iOS Test Report HTML" - path: "**/build/reports/tests/iosX64Test/" + - name: Enable KVM group perms + run: | + echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules + sudo udevadm control --reload-rules + sudo udevadm trigger --name-match=kvm + - name: Setup test environment + uses: ./.github/actions/setup_test_action - name: AVD cache uses: actions/cache@v3 id: avd-cache @@ -65,7 +29,7 @@ jobs: path: | ~/.android/avd/* ~/.android/adb* - key: avd-${{ matrix.api-level }} + key: avd-${{ matrix.api-level }}-${{ runner.os }}-${{ runner.arch }} - name: create AVD and generate snapshot for caching if: steps.avd-cache.outputs.cache-hit != 'true' uses: reactivecircus/android-emulator-runner@v2 @@ -73,6 +37,7 @@ jobs: api-level: ${{ matrix.api-level }} arch: x86_64 target: google_apis + avd-name: pixel6_API${{ matrix.api-level }} force-avd-creation: false emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none disable-animations: false @@ -83,6 +48,7 @@ jobs: api-level: ${{ matrix.api-level }} arch: x86_64 target: google_apis + avd-name: pixel6_API${{ matrix.api-level }} force-avd-creation: false emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none disable-animations: true @@ -99,4 +65,57 @@ jobs: with: name: "Firebase Debug Log" path: "**/firebase-debug.log" + build-js: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Setup test environment + uses: ./.github/actions/setup_test_action + - name: Run JS Tests + run: ./gradlew cleanTest jsTest + - name: Upload JS test artifact + uses: actions/upload-artifact@v3 + if: failure() + with: + name: "JS Test Report HTML" + path: | + **/build/reports/tests/jsTest/ + **/build/reports/tests/jsBrowserTest/ + **/build/reports/tests/jsNodeTest/ + - name: Upload Firebase Debug Log + uses: actions/upload-artifact@v3 + if: failure() + with: + name: "Firebase Debug Log" + path: "**/firebase-debug.log" + build-ios: + runs-on: macos-13 + steps: + - uses: actions/checkout@v3 + - name: Cocoapods cache + uses: actions/cache@v3 + id: cocoapods-cache + with: + path: | + ~/.cocoapods + ~/Library/Caches/CocoaPods + */build/cocoapods + */build/classes + key: cocoapods-cache + - name: Setup test environment + uses: ./.github/actions/setup_test_action + - name: Run iOS Tests + run: ./gradlew cleanTest iosX64Test + - name: Upload iOS test artifact + uses: actions/upload-artifact@v3 + if: failure() + with: + name: "iOS Test Report HTML" + path: "**/build/reports/tests/iosX64Test/" + - name: Upload Firebase Debug Log + uses: actions/upload-artifact@v3 + if: failure() + with: + name: "Firebase Debug Log" + path: "**/firebase-debug.log" diff --git a/README.md b/README.md index 117567d1d..b7f2b17f2 100644 --- a/README.md +++ b/README.md @@ -16,16 +16,16 @@ The following libraries are available for the various Firebase products. | Service or Product | Gradle Dependency | API Coverage | |---------------------------------------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| [Authentication](https://firebase.google.com/docs/auth) | [`dev.gitlive:firebase-auth:1.10.0`](https://search.maven.org/artifact/dev.gitlive/firebase-auth/1.10.0/pom) | [![80%](https://img.shields.io/badge/-80%25-green?style=flat-square)](/firebase-auth/src/commonMain/kotlin/dev/gitlive/firebase/auth/auth.kt) | -| [Realtime Database](https://firebase.google.com/docs/database) | [`dev.gitlive:firebase-database:1.10.0`](https://search.maven.org/artifact/dev.gitlive/firebase-database/1.10.0/pom) | [![70%](https://img.shields.io/badge/-70%25-orange?style=flat-square)](/firebase-database/src/commonMain/kotlin/dev/gitlive/firebase/database/database.kt) | -| [Cloud Firestore](https://firebase.google.com/docs/firestore) | [`dev.gitlive:firebase-firestore:1.10.0`](https://search.maven.org/artifact/dev.gitlive/firebase-firestore/1.10.0/pom) | [![60%](https://img.shields.io/badge/-60%25-orange?style=flat-square)](/firebase-firestore/src/commonMain/kotlin/dev/gitlive/firebase/firestore/firestore.kt) | -| [Cloud Functions](https://firebase.google.com/docs/functions) | [`dev.gitlive:firebase-functions:1.10.0`](https://search.maven.org/artifact/dev.gitlive/firebase-functions/1.10.0/pom) | [![80%](https://img.shields.io/badge/-80%25-green?style=flat-square)](/firebase-functions/src/commonMain/kotlin/dev/gitlive/firebase/functions/functions.kt) | -| [Cloud Messaging](https://firebase.google.com/docs/cloud-messaging) | [`dev.gitlive:firebase-messaging:1.10.0`](https://search.maven.org/artifact/dev.gitlive/firebase-messaging/1.10.0/pom) | ![0%](https://img.shields.io/badge/-0%25-lightgrey?style=flat-square) | -| [Cloud Storage](https://firebase.google.com/docs/storage) | [`dev.gitlive:firebase-storage:1.10.0`](https://search.maven.org/artifact/dev.gitlive/firebase-storage/1.10.0/pom) | [![40%](https://img.shields.io/badge/-40%25-orange?style=flat-square)](/firebase-storage/src/commonMain/kotlin/dev/gitlive/firebase/storage/storage.kt) | -| [Installations](https://firebase.google.com/docs/projects/manage-installations) | [`dev.gitlive:firebase-installations:1.10.0`](https://search.maven.org/artifact/dev.gitlive/firebase-installations/1.10.0/pom) | [![90%](https://img.shields.io/badge/-90%25-green?style=flat-square)](/firebase-installations/src/commonMain/kotlin/dev/gitlive/firebase/installations/installations.kt) | -| [Remote Config](https://firebase.google.com/docs/remote-config) | [`dev.gitlive:firebase-config:1.10.0`](https://search.maven.org/artifact/dev.gitlive/firebase-config/1.10.0/pom) | [![20%](https://img.shields.io/badge/-20%25-orange?style=flat-square)](/firebase-config/src/commonMain/kotlin/dev/gitlive/firebase/remoteconfig/FirebaseRemoteConfig.kt) | -| [Performance](https://firebase.google.com/docs/perf-mon) | [`dev.gitlive:firebase-perf:1.10.0`](https://search.maven.org/artifact/dev.gitlive/firebase-perf/1.10.0/pom) | [![1%](https://img.shields.io/badge/-1%25-orange?style=flat-square)](/firebase-perf/src/commonMain/kotlin/dev/gitlive/firebase/perf/performance.kt) | -| [Crashlytics](https://firebase.google.com/docs/crashlytics) | [`dev.gitlive:firebase-crashlytics:1.10.0`](https://search.maven.org/artifact/dev.gitlive/firebase-crashlytics/1.10.0/pom) | [![80%](https://img.shields.io/badge/-1%25-orange?style=flat-square)](/firebase-crashlytics/src/commonMain/kotlin/dev/gitlive/firebase/crashlytics/crashlytics.kt) | +| [Authentication](https://firebase.google.com/docs/auth) | [`dev.gitlive:firebase-auth:1.10.4`](https://search.maven.org/artifact/dev.gitlive/firebase-auth/1.10.4/pom) | [![80%](https://img.shields.io/badge/-80%25-green?style=flat-square)](/firebase-auth/src/commonMain/kotlin/dev/gitlive/firebase/auth/auth.kt) | +| [Realtime Database](https://firebase.google.com/docs/database) | [`dev.gitlive:firebase-database:1.10.4`](https://search.maven.org/artifact/dev.gitlive/firebase-database/1.10.4/pom) | [![70%](https://img.shields.io/badge/-70%25-orange?style=flat-square)](/firebase-database/src/commonMain/kotlin/dev/gitlive/firebase/database/database.kt) | +| [Cloud Firestore](https://firebase.google.com/docs/firestore) | [`dev.gitlive:firebase-firestore:1.10.4`](https://search.maven.org/artifact/dev.gitlive/firebase-firestore/1.10.4/pom) | [![60%](https://img.shields.io/badge/-60%25-orange?style=flat-square)](/firebase-firestore/src/commonMain/kotlin/dev/gitlive/firebase/firestore/firestore.kt) | +| [Cloud Functions](https://firebase.google.com/docs/functions) | [`dev.gitlive:firebase-functions:1.10.4`](https://search.maven.org/artifact/dev.gitlive/firebase-functions/1.10.4/pom) | [![80%](https://img.shields.io/badge/-80%25-green?style=flat-square)](/firebase-functions/src/commonMain/kotlin/dev/gitlive/firebase/functions/functions.kt) | +| [Cloud Messaging](https://firebase.google.com/docs/cloud-messaging) | [`dev.gitlive:firebase-messaging:1.10.4`](https://search.maven.org/artifact/dev.gitlive/firebase-messaging/1.10.4/pom) | ![0%](https://img.shields.io/badge/-0%25-lightgrey?style=flat-square) | +| [Cloud Storage](https://firebase.google.com/docs/storage) | [`dev.gitlive:firebase-storage:1.10.4`](https://search.maven.org/artifact/dev.gitlive/firebase-storage/1.10.4/pom) | [![40%](https://img.shields.io/badge/-40%25-orange?style=flat-square)](/firebase-storage/src/commonMain/kotlin/dev/gitlive/firebase/storage/storage.kt) | +| [Installations](https://firebase.google.com/docs/projects/manage-installations) | [`dev.gitlive:firebase-installations:1.10.4`](https://search.maven.org/artifact/dev.gitlive/firebase-installations/1.10.4/pom) | [![90%](https://img.shields.io/badge/-90%25-green?style=flat-square)](/firebase-installations/src/commonMain/kotlin/dev/gitlive/firebase/installations/installations.kt) | +| [Remote Config](https://firebase.google.com/docs/remote-config) | [`dev.gitlive:firebase-config:1.10.4`](https://search.maven.org/artifact/dev.gitlive/firebase-config/1.10.4/pom) | [![20%](https://img.shields.io/badge/-20%25-orange?style=flat-square)](/firebase-config/src/commonMain/kotlin/dev/gitlive/firebase/remoteconfig/FirebaseRemoteConfig.kt) | +| [Performance](https://firebase.google.com/docs/perf-mon) | [`dev.gitlive:firebase-perf:1.10.4`](https://search.maven.org/artifact/dev.gitlive/firebase-perf/1.10.4/pom) | [![1%](https://img.shields.io/badge/-1%25-orange?style=flat-square)](/firebase-perf/src/commonMain/kotlin/dev/gitlive/firebase/perf/performance.kt) | +| [Crashlytics](https://firebase.google.com/docs/crashlytics) | [`dev.gitlive:firebase-crashlytics:1.10.4`](https://search.maven.org/artifact/dev.gitlive/firebase-crashlytics/1.10.4/pom) | [![80%](https://img.shields.io/badge/-1%25-orange?style=flat-square)](/firebase-crashlytics/src/commonMain/kotlin/dev/gitlive/firebase/crashlytics/crashlytics.kt) | Is the Firebase library or API you need missing? [Create an issue](https://github.com/GitLiveApp/firebase-kotlin-sdk/issues/new?labels=API+coverage&template=increase-api-coverage.md&title=Add+%5Bclass+name%5D.%5Bfunction+name%5D+to+%5Blibrary+name%5D+for+%5Bplatform+names%5D) to request additional API coverage or be awesome and [submit a PR](https://github.com/GitLiveApp/firebase-kotlin-sdk/fork) diff --git a/build.gradle.kts b/build.gradle.kts index 8b90dc6a3..fff5eeafc 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,6 @@ import org.gradle.api.tasks.testing.logging.TestExceptionFormat import org.gradle.api.tasks.testing.logging.TestLogEvent +import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask repositories { google() @@ -120,7 +121,7 @@ subprojects { "commonTestImplementation"("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion") "commonTestImplementation"("org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesVersion") if (this@afterEvaluate.name != "firebase-crashlytics") { - "jvmMainApi"("dev.gitlive:firebase-java-sdk:0.1.1") + "jvmMainApi"("dev.gitlive:firebase-java-sdk:0.1.2") "jvmMainApi"("org.jetbrains.kotlinx:kotlinx-coroutines-play-services:$coroutinesVersion") { exclude("com.google.android.gms") } @@ -152,7 +153,7 @@ subprojects { maven { //// do not upstream //// this.name = "snapshot" - url = uri("https://oss.sonatype.org/content/repositories/snapshots/") + url = uri("https://s01.oss.sonatype.org/content/repositories/snapshots/") //// /////////////// //// credentials { diff --git a/firebase-app/build.gradle.kts b/firebase-app/build.gradle.kts index f420c7771..084431b7e 100644 --- a/firebase-app/build.gradle.kts +++ b/firebase-app/build.gradle.kts @@ -1,3 +1,6 @@ +import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions +import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSetTree + /* * Copyright (c) 2020 GitLive Ltd. Use of this source code is governed by the Apache 2.0 license. */ @@ -46,7 +49,16 @@ val supportIosTarget = project.property("skipIosTarget") != "true" kotlin { + targets.configureEach { + compilations.configureEach { + kotlinOptions.freeCompilerArgs += "-Xexpect-actual-classes" + } + } + + @Suppress("OPT_IN_USAGE") androidTarget { + instrumentedTestVariant.sourceSetTree.set(KotlinSourceSetTree.test) + unitTestVariant.sourceSetTree.set(KotlinSourceSetTree.test) publishAllLibraryVariants() compilations.configureEach { kotlinOptions { @@ -64,7 +76,8 @@ kotlin { } if (supportIosTarget) { - ios() + iosArm64() + iosX64() iosSimulatorArm64() cocoapods { @@ -109,6 +122,9 @@ kotlin { this.apiVersion = apiVersion this.languageVersion = languageVersion progressiveMode = true + if (name.lowercase().contains("ios")) { + optIn("kotlinx.cinterop.ExperimentalForeignApi") + } } } @@ -118,7 +134,7 @@ kotlin { } } - val commonTest by getting { + getByName("commonTest") { dependencies { implementation(project(":test-utils")) } @@ -130,24 +146,9 @@ kotlin { } } - getByName("androidInstrumentedTest") { - dependencies { - dependsOn(commonTest) - } - } - getByName("jvmMain") { kotlin.srcDir("src/androidMain/kotlin") } - - if (supportIosTarget) { - val iosMain by getting - val iosSimulatorArm64Main by getting - iosSimulatorArm64Main.dependsOn(iosMain) - val iosTest by sourceSets.getting - val iosSimulatorArm64Test by getting - iosSimulatorArm64Test.dependsOn(iosTest) - } } } diff --git a/firebase-app/package.json b/firebase-app/package.json index cf14f4f55..7725a328d 100644 --- a/firebase-app/package.json +++ b/firebase-app/package.json @@ -1,6 +1,6 @@ { "name": "@gitlive/firebase-app", - "version": "1.10.1-SNAPSHOT", + "version": "1.10.4", "description": "Wrapper around firebase for usage in Kotlin Multiplatform projects", "main": "firebase-app.js", "scripts": { @@ -23,7 +23,7 @@ }, "homepage": "https://github.com/GitLiveApp/firebase-kotlin-sdk", "dependencies": { - "@gitlive/firebase-common": "1.10.1-SNAPSHOT", + "@gitlive/firebase-common": "1.10.4", "firebase": "9.19.1", "kotlin": "1.8.20", "kotlinx-coroutines-core": "1.6.4" diff --git a/firebase-app/src/androidInstrumentedTest/kotlin/dev/gitlive/firebase/firebase.kt b/firebase-app/src/androidInstrumentedTest/kotlin/dev/gitlive/firebase/firebase.kt index 5af3ac4f7..bdc3f7e6c 100644 --- a/firebase-app/src/androidInstrumentedTest/kotlin/dev/gitlive/firebase/firebase.kt +++ b/firebase-app/src/androidInstrumentedTest/kotlin/dev/gitlive/firebase/firebase.kt @@ -9,6 +9,5 @@ import androidx.test.platform.app.InstrumentationRegistry actual val context: Any = InstrumentationRegistry.getInstrumentation().targetContext -actual fun runTest(test: suspend () -> Unit) = kotlinx.coroutines.test.runTest { test() } @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) actual annotation class IgnoreForAndroidUnitTest diff --git a/firebase-app/src/androidMain/kotlin/dev/gitlive/firebase/firebase.kt b/firebase-app/src/androidMain/kotlin/dev/gitlive/firebase/firebase.kt index 8d025d635..d007e6f0c 100644 --- a/firebase-app/src/androidMain/kotlin/dev/gitlive/firebase/firebase.kt +++ b/firebase-app/src/androidMain/kotlin/dev/gitlive/firebase/firebase.kt @@ -35,7 +35,9 @@ actual data class FirebaseApp internal constructor(val android: com.google.fireb actual val options: FirebaseOptions get() = android.options.run { FirebaseOptions(applicationId, apiKey, databaseUrl, gaTrackingId, storageBucket, projectId, gcmSenderId) } - actual suspend fun delete() = android.delete() + actual suspend fun delete() { + android.delete() + } } actual fun Firebase.apps(context: Any?) = com.google.firebase.FirebaseApp.getApps(context as Context) diff --git a/firebase-app/src/androidUnitTest/kotlin/firebase/firebase.kt b/firebase-app/src/androidUnitTest/kotlin/firebase/firebase.kt index 59f908323..9810ef6a8 100644 --- a/firebase-app/src/androidUnitTest/kotlin/firebase/firebase.kt +++ b/firebase-app/src/androidUnitTest/kotlin/firebase/firebase.kt @@ -9,5 +9,4 @@ import org.junit.Ignore actual val context: Any = "" -actual fun runTest(test: suspend () -> Unit) = kotlinx.coroutines.test.runTest { test() } actual typealias IgnoreForAndroidUnitTest = Ignore diff --git a/firebase-app/src/commonTest/kotlin/dev/gitlive/firebase/firebase.kt b/firebase-app/src/commonTest/kotlin/dev/gitlive/firebase/firebase.kt index d1fa1fcb8..5c82a6f18 100644 --- a/firebase-app/src/commonTest/kotlin/dev/gitlive/firebase/firebase.kt +++ b/firebase-app/src/commonTest/kotlin/dev/gitlive/firebase/firebase.kt @@ -1,16 +1,16 @@ package dev.gitlive.firebase import kotlin.test.Test +import kotlin.test.assertEquals expect val context: Any -expect fun runTest(test: suspend () -> Unit) expect annotation class IgnoreForAndroidUnitTest() class FirebaseAppTest { @IgnoreForAndroidUnitTest @Test - fun testInitialize() { + fun testInitialize() = runTest { Firebase.initialize( context, FirebaseOptions( @@ -22,6 +22,12 @@ class FirebaseAppTest { gcmSenderId = "846484016111" ) ) + + assertEquals(1, Firebase.apps(context).size) + + Firebase.apps(context).forEach { + it.delete() + } } } \ No newline at end of file diff --git a/firebase-app/src/iosTest/kotlin/dev/gitlive/firebase/firebase.kt b/firebase-app/src/iosTest/kotlin/dev/gitlive/firebase/firebase.kt index 5992a56d7..c56fadc7d 100644 --- a/firebase-app/src/iosTest/kotlin/dev/gitlive/firebase/firebase.kt +++ b/firebase-app/src/iosTest/kotlin/dev/gitlive/firebase/firebase.kt @@ -4,28 +4,7 @@ package dev.gitlive.firebase -import kotlinx.coroutines.MainScope -import kotlinx.coroutines.async -import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.yield -import platform.Foundation.NSDate -import platform.Foundation.NSDefaultRunLoopMode -import platform.Foundation.NSRunLoop -import platform.Foundation.create -import platform.Foundation.runMode - actual val context: Any = Unit -actual fun runTest(test: suspend () -> Unit) = runBlocking { - val testRun = MainScope().async { test() } - while (testRun.isActive) { - NSRunLoop.mainRunLoop.runMode( - NSDefaultRunLoopMode, - beforeDate = NSDate.create(timeInterval = 1.0, sinceDate = NSDate()) - ) - yield() - } - testRun.await() -} @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) actual annotation class IgnoreForAndroidUnitTest diff --git a/firebase-app/src/jsTest/kotlin/dev/gitlive/firebase/firebase.kt b/firebase-app/src/jsTest/kotlin/dev/gitlive/firebase/firebase.kt index 243b3e8cc..c56fadc7d 100644 --- a/firebase-app/src/jsTest/kotlin/dev/gitlive/firebase/firebase.kt +++ b/firebase-app/src/jsTest/kotlin/dev/gitlive/firebase/firebase.kt @@ -4,13 +4,7 @@ package dev.gitlive.firebase -import kotlinx.coroutines.test.runTest -import kotlin.time.Duration.Companion.minutes - actual val context: Any = Unit -actual fun runTest(test: suspend () -> Unit) { - runTest(timeout = 5.minutes) { test() } -} @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) actual annotation class IgnoreForAndroidUnitTest diff --git a/firebase-app/src/jvmTest/kotlin/dev/gitlive/firebase/firebase.kt b/firebase-app/src/jvmTest/kotlin/dev/gitlive/firebase/firebase.kt index 5fe48b793..4bdd21eac 100644 --- a/firebase-app/src/jvmTest/kotlin/dev/gitlive/firebase/firebase.kt +++ b/firebase-app/src/jvmTest/kotlin/dev/gitlive/firebase/firebase.kt @@ -7,6 +7,5 @@ package dev.gitlive.firebase actual val context: Any = Unit -actual fun runTest(test: suspend () -> Unit) = kotlinx.coroutines.test.runTest { test() } @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) actual annotation class IgnoreForAndroidUnitTest diff --git a/firebase-auth/build.gradle.kts b/firebase-auth/build.gradle.kts index e55bb0e77..07f2f9fce 100644 --- a/firebase-auth/build.gradle.kts +++ b/firebase-auth/build.gradle.kts @@ -1,3 +1,5 @@ +import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSetTree + /* * Copyright (c) 2020 GitLive Ltd. Use of this source code is governed by the Apache 2.0 license. */ @@ -60,7 +62,16 @@ val supportIosTarget = project.property("skipIosTarget") != "true" kotlin { + targets.configureEach { + compilations.configureEach { + kotlinOptions.freeCompilerArgs += "-Xexpect-actual-classes" + } + } + + @Suppress("OPT_IN_USAGE") androidTarget { + instrumentedTestVariant.sourceSetTree.set(KotlinSourceSetTree.test) + unitTestVariant.sourceSetTree.set(KotlinSourceSetTree.test) publishAllLibraryVariants() compilations.configureEach { kotlinOptions { @@ -70,7 +81,8 @@ kotlin { } if (supportIosTarget) { - ios() + iosArm64() + iosX64() iosSimulatorArm64() cocoapods { ios.deploymentTarget = "11.0" @@ -137,7 +149,7 @@ kotlin { } } - val commonTest by getting { + getByName("commonTest") { dependencies { implementation(project(":test-utils")) } @@ -148,21 +160,6 @@ kotlin { api("com.google.firebase:firebase-auth-ktx") } } - - getByName("androidInstrumentedTest") { - dependencies { - dependsOn(commonTest) - } - } - - if (supportIosTarget) { - val iosMain by getting - val iosSimulatorArm64Main by getting - iosSimulatorArm64Main.dependsOn(iosMain) - val iosTest by sourceSets.getting - val iosSimulatorArm64Test by getting - iosSimulatorArm64Test.dependsOn(iosTest) - } } } diff --git a/firebase-auth/package.json b/firebase-auth/package.json index 3fa0ce49c..8f9f047e8 100644 --- a/firebase-auth/package.json +++ b/firebase-auth/package.json @@ -1,6 +1,6 @@ { "name": "@gitlive/firebase-auth", - "version": "1.10.1-SNAPSHOT", + "version": "1.10.4", "description": "Wrapper around firebase for usage in Kotlin Multiplatform projects", "main": "firebase-auth.js", "scripts": { @@ -23,7 +23,7 @@ }, "homepage": "https://github.com/GitLiveApp/firebase-kotlin-sdk", "dependencies": { - "@gitlive/firebase-app": "1.10.1-SNAPSHOT", + "@gitlive/firebase-app": "1.10.4", "firebase": "9.19.1", "kotlin": "1.8.20", "kotlinx-coroutines-core": "1.6.4" diff --git a/firebase-auth/src/androidInstrumentedTest/kotlin/dev/gitlive/firebase/auth/auth.kt b/firebase-auth/src/androidInstrumentedTest/kotlin/dev/gitlive/firebase/auth/auth.kt index 34ce51a86..0d4d18e96 100644 --- a/firebase-auth/src/androidInstrumentedTest/kotlin/dev/gitlive/firebase/auth/auth.kt +++ b/firebase-auth/src/androidInstrumentedTest/kotlin/dev/gitlive/firebase/auth/auth.kt @@ -11,6 +11,5 @@ actual val emulatorHost: String = "10.0.2.2" actual val context: Any = InstrumentationRegistry.getInstrumentation().targetContext -actual fun runTest(test: suspend () -> Unit) = kotlinx.coroutines.test.runTest { test() } @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) actual annotation class IgnoreForAndroidUnitTest diff --git a/firebase-auth/src/androidUnitTest/kotlin/dev/gitlive/firebase/auth/auth.kt b/firebase-auth/src/androidUnitTest/kotlin/dev/gitlive/firebase/auth/auth.kt index 22ceb8270..ee76642f0 100644 --- a/firebase-auth/src/androidUnitTest/kotlin/dev/gitlive/firebase/auth/auth.kt +++ b/firebase-auth/src/androidUnitTest/kotlin/dev/gitlive/firebase/auth/auth.kt @@ -11,5 +11,4 @@ actual val emulatorHost: String = "10.0.2.2" actual val context: Any = "" -actual fun runTest(test: suspend () -> Unit) = kotlinx.coroutines.test.runTest { test() } actual typealias IgnoreForAndroidUnitTest = Ignore \ No newline at end of file diff --git a/firebase-auth/src/commonTest/kotlin/dev/gitlive/firebase/auth/auth.kt b/firebase-auth/src/commonTest/kotlin/dev/gitlive/firebase/auth/auth.kt index 9dd68b31a..d0fe6a2aa 100644 --- a/firebase-auth/src/commonTest/kotlin/dev/gitlive/firebase/auth/auth.kt +++ b/firebase-auth/src/commonTest/kotlin/dev/gitlive/firebase/auth/auth.kt @@ -11,49 +11,56 @@ import kotlin.test.* expect val emulatorHost: String expect val context: Any -expect fun runTest(test: suspend () -> Unit): TestResult expect annotation class IgnoreForAndroidUnitTest() @IgnoreForAndroidUnitTest class FirebaseAuthTest { + lateinit var auth: FirebaseAuth + @BeforeTest fun initializeFirebase() { - Firebase - .takeIf { Firebase.apps(context).isEmpty() } - ?.apply { - initialize( - context, - FirebaseOptions( - applicationId = "1:846484016111:ios:dd1f6688bad7af768c841a", - apiKey = "AIzaSyCK87dcMFhzCz_kJVs2cT2AVlqOTLuyWV0", - databaseUrl = "https://fir-kotlin-sdk.firebaseio.com", - storageBucket = "fir-kotlin-sdk.appspot.com", - projectId = "fir-kotlin-sdk", - gcmSenderId = "846484016111" - ) - ) - Firebase.auth.useEmulator(emulatorHost, 9099) - } + val app = Firebase.apps(context).firstOrNull() ?: Firebase.initialize( + context, + FirebaseOptions( + applicationId = "1:846484016111:ios:dd1f6688bad7af768c841a", + apiKey = "AIzaSyCK87dcMFhzCz_kJVs2cT2AVlqOTLuyWV0", + databaseUrl = "https://fir-kotlin-sdk.firebaseio.com", + storageBucket = "fir-kotlin-sdk.appspot.com", + projectId = "fir-kotlin-sdk", + gcmSenderId = "846484016111" + ) + ) + + auth = Firebase.auth(app).apply { + useEmulator(emulatorHost, 9099) + } + } + + @AfterTest + fun deinitializeFirebase() = runBlockingTest { + Firebase.apps(context).forEach { + it.delete() + } } @Test fun testSignInWithUsernameAndPassword() = runTest { val uid = getTestUid("test@test.com", "test123") - val result = Firebase.auth.signInWithEmailAndPassword("test@test.com", "test123") + val result = auth.signInWithEmailAndPassword("test@test.com", "test123") assertEquals(uid, result.user!!.uid) } @Test fun testCreateUserWithEmailAndPassword() = runTest { val email = "test+${Random.nextInt(100000)}@test.com" - val createResult = Firebase.auth.createUserWithEmailAndPassword(email, "test123") + val createResult = auth.createUserWithEmailAndPassword(email, "test123") assertNotEquals(null, createResult.user?.uid) assertEquals(null, createResult.user?.displayName) assertEquals(null, createResult.user?.phoneNumber) assertEquals(email, createResult.user?.email) - val signInResult = Firebase.auth.signInWithEmailAndPassword(email, "test123") + val signInResult = auth.signInWithEmailAndPassword(email, "test123") assertEquals(createResult.user?.uid, signInResult.user?.uid) signInResult.user!!.delete() @@ -62,19 +69,19 @@ class FirebaseAuthTest { @Test fun testFetchSignInMethods() = runTest { val email = "test+${Random.nextInt(100000)}@test.com" - var signInMethodResult = Firebase.auth.fetchSignInMethodsForEmail(email) + var signInMethodResult = auth.fetchSignInMethodsForEmail(email) assertEquals(emptyList(), signInMethodResult) - Firebase.auth.createUserWithEmailAndPassword(email, "test123") - signInMethodResult = Firebase.auth.fetchSignInMethodsForEmail(email) + auth.createUserWithEmailAndPassword(email, "test123") + signInMethodResult = auth.fetchSignInMethodsForEmail(email) assertEquals(listOf("password"), signInMethodResult) - Firebase.auth.signInWithEmailAndPassword(email, "test123").user!!.delete() + auth.signInWithEmailAndPassword(email, "test123").user!!.delete() } @Test fun testSendEmailVerification() = runTest { val email = "test+${Random.nextInt(100000)}@test.com" - val createResult = Firebase.auth.createUserWithEmailAndPassword(email, "test123") + val createResult = auth.createUserWithEmailAndPassword(email, "test123") assertNotEquals(null, createResult.user?.uid) createResult.user!!.sendEmailVerification() @@ -84,10 +91,10 @@ class FirebaseAuthTest { @Test fun sendPasswordResetEmail() = runTest { val email = "test+${Random.nextInt(100000)}@test.com" - val createResult = Firebase.auth.createUserWithEmailAndPassword(email, "test123") + val createResult = auth.createUserWithEmailAndPassword(email, "test123") assertNotEquals(null, createResult.user?.uid) - Firebase.auth.sendPasswordResetEmail(email) + auth.sendPasswordResetEmail(email) createResult.user!!.delete() } @@ -96,7 +103,7 @@ class FirebaseAuthTest { fun testSignInWithCredential() = runTest { val uid = getTestUid("test@test.com", "test123") val credential = EmailAuthProvider.credential("test@test.com", "test123") - val result = Firebase.auth.signInWithCredential(credential) + val result = auth.signInWithCredential(credential) assertEquals(uid, result.user!!.uid) } @@ -104,8 +111,8 @@ class FirebaseAuthTest { fun testIsSignInWithEmailLink() { val validLink = "http://localhost:9099/emulator/action?mode=signIn&lang=en&oobCode=_vr0QcFcxcVeLZbrcU-GpTaZiuxlHquqdC8MSy0YM_vzWCTAQgV9Jq&apiKey=fake-api-key&continueUrl=https%3A%2F%2Fexample.com%2Fsignin" val invalidLink = "http://localhost:9099/emulator/action?mode=signIn&lang=en&&apiKey=fake-api-key&continueUrl=https%3A%2F%2Fexample.com%2Fsignin" - assertTrue(Firebase.auth.isSignInWithEmailLink(validLink)) - assertFalse(Firebase.auth.isSignInWithEmailLink(invalidLink)) + assertTrue(auth.isSignInWithEmailLink(validLink)) + assertFalse(auth.isSignInWithEmailLink(invalidLink)) } @Test @@ -117,7 +124,7 @@ class FirebaseAuthTest { } private suspend fun getTestUid(email: String, password: String): String { - val uid = Firebase.auth.let { + val uid = auth.let { val user = try { it.createUserWithEmailAndPassword(email, password).user } catch (e: FirebaseAuthUserCollisionException) { @@ -127,9 +134,9 @@ class FirebaseAuthTest { user!!.uid } - check(Firebase.auth.currentUser != null) - Firebase.auth.signOut() - check(Firebase.auth.currentUser == null) + check(auth.currentUser != null) + auth.signOut() + check(auth.currentUser == null) return uid } diff --git a/firebase-auth/src/iosMain/kotlin/dev/gitlive/firebase/auth/auth.kt b/firebase-auth/src/iosMain/kotlin/dev/gitlive/firebase/auth/auth.kt index c563f26be..04a743c86 100644 --- a/firebase-auth/src/iosMain/kotlin/dev/gitlive/firebase/auth/auth.kt +++ b/firebase-auth/src/iosMain/kotlin/dev/gitlive/firebase/auth/auth.kt @@ -192,6 +192,7 @@ private fun NSError.toException() = when(domain) { FIRAuthErrorCodeInvalidVerificationCode, FIRAuthErrorCodeMissingVerificationID, FIRAuthErrorCodeMissingVerificationCode, + FIRAuthErrorCodeUserTokenExpired, FIRAuthErrorCodeInvalidCredential -> FirebaseAuthInvalidCredentialsException(toString()) FIRAuthErrorCodeWeakPassword -> FirebaseAuthWeakPasswordException(toString()) diff --git a/firebase-auth/src/iosTest/kotlin/dev/gitlive/firebase/auth/auth.kt b/firebase-auth/src/iosTest/kotlin/dev/gitlive/firebase/auth/auth.kt index d188b4c90..84c4fcca7 100644 --- a/firebase-auth/src/iosTest/kotlin/dev/gitlive/firebase/auth/auth.kt +++ b/firebase-auth/src/iosTest/kotlin/dev/gitlive/firebase/auth/auth.kt @@ -4,23 +4,9 @@ package dev.gitlive.firebase.auth -import kotlinx.coroutines.* -import platform.Foundation.* - actual val emulatorHost: String = "localhost" actual val context: Any = Unit -actual fun runTest(test: suspend () -> Unit) = runBlocking { - val testRun = MainScope().async { test() } - while (testRun.isActive) { - NSRunLoop.mainRunLoop.runMode( - NSDefaultRunLoopMode, - beforeDate = NSDate.create(timeInterval = 1.0, sinceDate = NSDate()) - ) - yield() - } - testRun.await() -} @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) actual annotation class IgnoreForAndroidUnitTest diff --git a/firebase-auth/src/jsTest/kotlin/dev/gitlive/firebase/auth/auth.kt b/firebase-auth/src/jsTest/kotlin/dev/gitlive/firebase/auth/auth.kt index 6a5057f49..832712901 100644 --- a/firebase-auth/src/jsTest/kotlin/dev/gitlive/firebase/auth/auth.kt +++ b/firebase-auth/src/jsTest/kotlin/dev/gitlive/firebase/auth/auth.kt @@ -4,14 +4,10 @@ package dev.gitlive.firebase.auth -import kotlin.time.Duration.Companion.minutes - actual val emulatorHost: String = "localhost" actual val context: Any = Unit -actual fun runTest(test: suspend () -> Unit) = kotlinx.coroutines.test.runTest(timeout = 5.minutes) { test() } - @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) actual annotation class IgnoreForAndroidUnitTest diff --git a/firebase-auth/src/jvmTest/kotlin/dev/gitlive/firebase/auth/auth.kt b/firebase-auth/src/jvmTest/kotlin/dev/gitlive/firebase/auth/auth.kt index 4b99639f5..b84c4b10d 100644 --- a/firebase-auth/src/jvmTest/kotlin/dev/gitlive/firebase/auth/auth.kt +++ b/firebase-auth/src/jvmTest/kotlin/dev/gitlive/firebase/auth/auth.kt @@ -8,5 +8,3 @@ package dev.gitlive.firebase.auth actual val emulatorHost: String = "10.0.2.2" actual val context: Any = Unit - -actual fun runTest(test: suspend () -> Unit) = kotlinx.coroutines.test.runTest { test() } diff --git a/firebase-common/build.gradle.kts b/firebase-common/build.gradle.kts index c6b799551..0586bfd3f 100644 --- a/firebase-common/build.gradle.kts +++ b/firebase-common/build.gradle.kts @@ -1,3 +1,5 @@ +import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSetTree + /* * Copyright (c) 2020 GitLive Ltd. Use of this source code is governed by the Apache 2.0 license. */ @@ -44,7 +46,16 @@ android { kotlin { + targets.configureEach { + compilations.configureEach { + kotlinOptions.freeCompilerArgs += "-Xexpect-actual-classes" + } + } + + @Suppress("OPT_IN_USAGE") androidTarget { + instrumentedTestVariant.sourceSetTree.set(KotlinSourceSetTree.test) + unitTestVariant.sourceSetTree.set(KotlinSourceSetTree.test) publishAllLibraryVariants() compilations.configureEach { kotlinOptions { @@ -69,7 +80,8 @@ kotlin { val supportIosTarget = project.property("skipIosTarget") != "true" if (supportIosTarget) { - ios() + iosArm64() + iosX64() iosSimulatorArm64() } @@ -117,7 +129,7 @@ kotlin { } } - val commonTest by getting { + getByName("commonTest") { dependencies { implementation(project(":test-utils")) } @@ -129,24 +141,9 @@ kotlin { } } - getByName("androidInstrumentedTest") { - dependencies { - dependsOn(commonTest) - } - } - - if (supportIosTarget) { - val iosMain by getting - val iosSimulatorArm64Main by getting - iosSimulatorArm64Main.dependsOn(iosMain) - val iosTest by sourceSets.getting - val iosSimulatorArm64Test by getting - iosSimulatorArm64Test.dependsOn(iosTest) - } - getByName("jsMain") { dependencies { - api(npm("firebase", "10.4.0")) + api(npm("firebase", "10.6.0")) } } @@ -154,7 +151,7 @@ kotlin { kotlin.srcDir("src/androidMain/kotlin") } - val jvmTest by getting { + getByName("jvmTest") { dependencies { implementation(kotlin("test-junit")) } diff --git a/firebase-common/package.json b/firebase-common/package.json index 8cfbb6605..163d7ec0f 100644 --- a/firebase-common/package.json +++ b/firebase-common/package.json @@ -1,6 +1,6 @@ { "name": "@gitlive/firebase-common", - "version": "1.10.1-SNAPSHOT", + "version": "1.10.4", "description": "Wrapper around firebase for usage in Kotlin Multiplatform projects", "main": "firebase-common.js", "scripts": { diff --git a/firebase-config/build.gradle.kts b/firebase-config/build.gradle.kts index 4290f8cbd..e933e165f 100644 --- a/firebase-config/build.gradle.kts +++ b/firebase-config/build.gradle.kts @@ -1,3 +1,5 @@ +import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSetTree + /* * Copyright (c) 2020 GitLive Ltd. Use of this source code is governed by the Apache 2.0 license. */ @@ -60,7 +62,16 @@ val supportIosTarget = project.property("skipIosTarget") != "true" kotlin { + targets.configureEach { + compilations.configureEach { + kotlinOptions.freeCompilerArgs += "-Xexpect-actual-classes" + } + } + + @Suppress("OPT_IN_USAGE") androidTarget { + instrumentedTestVariant.sourceSetTree.set(KotlinSourceSetTree.test) + unitTestVariant.sourceSetTree.set(KotlinSourceSetTree.test) publishAllLibraryVariants() compilations.configureEach { kotlinOptions { @@ -83,7 +94,8 @@ kotlin { } if (supportIosTarget) { - ios() + iosArm64() + iosX64() iosSimulatorArm64() cocoapods { ios.deploymentTarget = "11.0" @@ -132,7 +144,7 @@ kotlin { } } - val commonTest by getting { + getByName("commonTest") { dependencies { implementation(project(":test-utils")) } @@ -144,24 +156,9 @@ kotlin { } } - getByName("androidInstrumentedTest") { - dependencies { - dependsOn(commonTest) - } - } - getByName("jvmMain") { kotlin.srcDir("src/androidMain/kotlin") } - - if (supportIosTarget) { - val iosMain by getting - val iosSimulatorArm64Main by getting - iosSimulatorArm64Main.dependsOn(iosMain) - val iosTest by sourceSets.getting - val iosSimulatorArm64Test by getting - iosSimulatorArm64Test.dependsOn(iosTest) - } } } diff --git a/firebase-config/package.json b/firebase-config/package.json index 5147032c3..78d6c9b43 100644 --- a/firebase-config/package.json +++ b/firebase-config/package.json @@ -1,6 +1,6 @@ { "name": "@gitlive/firebase-config", - "version": "1.10.1-SNAPSHOT", + "version": "1.10.4", "description": "Wrapper around firebase for usage in Kotlin Multiplatform projects", "main": "firebase-config.js", "scripts": { @@ -23,7 +23,7 @@ }, "homepage": "https://github.com/GitLiveApp/firebase-kotlin-sdk", "dependencies": { - "@gitlive/firebase-app": "1.10.1-SNAPSHOT", + "@gitlive/firebase-app": "1.10.4", "firebase": "9.19.1", "kotlin": "1.8.20", "kotlinx-coroutines-core": "1.6.4" diff --git a/firebase-config/src/androidInstrumentedTest/kotlin/dev/gitlive/firebase/remoteconfig/RemoteConfig.kt b/firebase-config/src/androidInstrumentedTest/kotlin/dev/gitlive/firebase/remoteconfig/RemoteConfig.kt index 5e7fa4d08..492af89bc 100644 --- a/firebase-config/src/androidInstrumentedTest/kotlin/dev/gitlive/firebase/remoteconfig/RemoteConfig.kt +++ b/firebase-config/src/androidInstrumentedTest/kotlin/dev/gitlive/firebase/remoteconfig/RemoteConfig.kt @@ -9,6 +9,5 @@ import androidx.test.platform.app.InstrumentationRegistry actual val context: Any = InstrumentationRegistry.getInstrumentation().targetContext -actual fun runTest(test: suspend () -> Unit) = kotlinx.coroutines.test.runTest { test() } @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) actual annotation class IgnoreForAndroidUnitTest diff --git a/firebase-config/src/androidUnitTest/kotlin/dev/gitlive/firebase/config/RemoteConfig.kt b/firebase-config/src/androidUnitTest/kotlin/dev/gitlive/firebase/config/RemoteConfig.kt index ab949f028..19d69bba3 100644 --- a/firebase-config/src/androidUnitTest/kotlin/dev/gitlive/firebase/config/RemoteConfig.kt +++ b/firebase-config/src/androidUnitTest/kotlin/dev/gitlive/firebase/config/RemoteConfig.kt @@ -9,5 +9,4 @@ import org.junit.Ignore actual val context: Any = "" -actual fun runTest(test: suspend () -> Unit) = kotlinx.coroutines.test.runTest { test() } actual typealias IgnoreForAndroidUnitTest = Ignore diff --git a/firebase-config/src/commonTest/kotlin/dev/gitlive/firebase/remoteconfig/FirebaseRemoteConfig.kt b/firebase-config/src/commonTest/kotlin/dev/gitlive/firebase/remoteconfig/FirebaseRemoteConfig.kt index 2e54c1d13..426a7f23e 100644 --- a/firebase-config/src/commonTest/kotlin/dev/gitlive/firebase/remoteconfig/FirebaseRemoteConfig.kt +++ b/firebase-config/src/commonTest/kotlin/dev/gitlive/firebase/remoteconfig/FirebaseRemoteConfig.kt @@ -8,7 +8,7 @@ import dev.gitlive.firebase.Firebase import dev.gitlive.firebase.FirebaseOptions import dev.gitlive.firebase.apps import dev.gitlive.firebase.initialize -import kotlinx.coroutines.test.TestResult +import dev.gitlive.firebase.runTest import kotlin.test.AfterTest import kotlin.test.BeforeTest import kotlin.test.Ignore @@ -16,7 +16,6 @@ import kotlin.test.Test import kotlin.test.assertEquals expect val context: Any -expect fun runTest(test: suspend () -> Unit): TestResult expect annotation class IgnoreForAndroidUnitTest() @IgnoreForAndroidUnitTest @@ -28,33 +27,35 @@ class FirebaseRemoteConfigTest { "test_default_string" to "Hello World", ) + lateinit var remoteConfig: FirebaseRemoteConfig + @BeforeTest fun initializeFirebase() { - Firebase - .takeIf { Firebase.apps(context).isEmpty() } - ?.apply { - initialize( - context, - FirebaseOptions( - applicationId = "1:846484016111:ios:dd1f6688bad7af768c841a", - apiKey = "AIzaSyCK87dcMFhzCz_kJVs2cT2AVlqOTLuyWV0", - databaseUrl = "https://fir-kotlin-sdk.firebaseio.com", - storageBucket = "fir-kotlin-sdk.appspot.com", - projectId = "fir-kotlin-sdk", - gcmSenderId = "846484016111" - ) - ) - } + val app = Firebase.apps(context).firstOrNull() ?: Firebase.initialize( + context, + FirebaseOptions( + applicationId = "1:846484016111:ios:dd1f6688bad7af768c841a", + apiKey = "AIzaSyCK87dcMFhzCz_kJVs2cT2AVlqOTLuyWV0", + databaseUrl = "https://fir-kotlin-sdk.firebaseio.com", + storageBucket = "fir-kotlin-sdk.appspot.com", + projectId = "fir-kotlin-sdk", + gcmSenderId = "846484016111" + ) + ) + + remoteConfig = Firebase.remoteConfig(app) } @AfterTest fun tearDown() = runTest { - Firebase.remoteConfig.reset() + remoteConfig.reset() + Firebase.apps(context).forEach { + it.delete() + } } @Test fun testGettingValues() = runTest { - val remoteConfig = Firebase.remoteConfig remoteConfig.setDefaults(*defaults) assertEquals(true, remoteConfig["test_default_boolean"]) @@ -71,8 +72,8 @@ class FirebaseRemoteConfigTest { @Test fun testGetAll() = runTest { - Firebase.remoteConfig.setDefaults(*defaults) - val all = Firebase.remoteConfig.all + remoteConfig.setDefaults(*defaults) + val all = remoteConfig.all assertEquals(true, all["test_default_boolean"]?.asBoolean()) assertEquals(42.0, all["test_default_double"]?.asDouble()) assertEquals(42L, all["test_default_long"]?.asLong()) @@ -82,8 +83,8 @@ class FirebaseRemoteConfigTest { @Test fun testGetKeysByPrefix() = runTest { - Firebase.remoteConfig.setDefaults(*defaults) - val keys = Firebase.remoteConfig.getKeysByPrefix("test_default") + remoteConfig.setDefaults(*defaults) + val keys = remoteConfig.getKeysByPrefix("test_default") assertEquals( setOf( "test_default_boolean", @@ -103,17 +104,17 @@ class FirebaseRemoteConfigTest { fetchTimeMillis = -1, lastFetchStatus = FetchStatus.NoFetchYet ).toString(), - Firebase.remoteConfig.info.toString() + remoteConfig.info.toString() ) } @Test fun testSetConfigSettings() = runTest { - Firebase.remoteConfig.settings { + remoteConfig.settings { fetchTimeoutInSeconds = 42 minimumFetchIntervalInSeconds = 42 } - val info = Firebase.remoteConfig.info + val info = remoteConfig.info assertEquals(42, info.configSettings.fetchTimeoutInSeconds) assertEquals(42, info.configSettings.minimumFetchIntervalInSeconds) } @@ -124,7 +125,6 @@ class FirebaseRemoteConfigTest { @Test @Ignore fun testFetch() = runTest { - val remoteConfig = Firebase.remoteConfig remoteConfig.settings { minimumFetchIntervalInSeconds = 60 } @@ -140,7 +140,6 @@ class FirebaseRemoteConfigTest { @Test @Ignore fun testFetchAndActivate() = runTest { - val remoteConfig = Firebase.remoteConfig remoteConfig.settings { minimumFetchIntervalInSeconds = 60 } diff --git a/firebase-config/src/iosTest/kotlin/dev/gitlive/firebase/remoteconfig/RemoteConfig.kt b/firebase-config/src/iosTest/kotlin/dev/gitlive/firebase/remoteconfig/RemoteConfig.kt index d61567bab..70ce2965b 100644 --- a/firebase-config/src/iosTest/kotlin/dev/gitlive/firebase/remoteconfig/RemoteConfig.kt +++ b/firebase-config/src/iosTest/kotlin/dev/gitlive/firebase/remoteconfig/RemoteConfig.kt @@ -4,21 +4,7 @@ package dev.gitlive.firebase.remoteconfig -import kotlinx.coroutines.* -import platform.Foundation.* - actual val context: Any = Unit -actual fun runTest(test: suspend () -> Unit) = runBlocking { - val testRun = MainScope().async { test() } - while (testRun.isActive) { - NSRunLoop.mainRunLoop.runMode( - NSDefaultRunLoopMode, - beforeDate = NSDate.create(timeInterval = 1.0, sinceDate = NSDate()) - ) - yield() - } - testRun.await() -} @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) actual annotation class IgnoreForAndroidUnitTest diff --git a/firebase-config/src/jsTest/kotlin/dev/gitlive/firebase/remoteconfig/FirebaseRemoteConfig.kt b/firebase-config/src/jsTest/kotlin/dev/gitlive/firebase/remoteconfig/FirebaseRemoteConfig.kt index 31ed60491..c6b4ef606 100644 --- a/firebase-config/src/jsTest/kotlin/dev/gitlive/firebase/remoteconfig/FirebaseRemoteConfig.kt +++ b/firebase-config/src/jsTest/kotlin/dev/gitlive/firebase/remoteconfig/FirebaseRemoteConfig.kt @@ -1,11 +1,6 @@ package dev.gitlive.firebase.remoteconfig -import kotlin.time.Duration.Companion.minutes - - actual val context: Any = Unit -actual fun runTest(test: suspend () -> Unit) = kotlinx.coroutines.test.runTest(timeout = 5.minutes) { test() } - @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) actual annotation class IgnoreForAndroidUnitTest diff --git a/firebase-config/src/jvmTest/kotlin/dev/gitlive/firebase/remoteconfig/RemoteConfig.kt b/firebase-config/src/jvmTest/kotlin/dev/gitlive/firebase/remoteconfig/RemoteConfig.kt index efb50bde7..5a0333346 100644 --- a/firebase-config/src/jvmTest/kotlin/dev/gitlive/firebase/remoteconfig/RemoteConfig.kt +++ b/firebase-config/src/jvmTest/kotlin/dev/gitlive/firebase/remoteconfig/RemoteConfig.kt @@ -7,6 +7,5 @@ package dev.gitlive.firebase.remoteconfig actual val context: Any = Unit -actual fun runTest(test: suspend () -> Unit) = kotlinx.coroutines.test.runTest { test() } @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) actual annotation class IgnoreForAndroidUnitTest diff --git a/firebase-crashlytics/build.gradle.kts b/firebase-crashlytics/build.gradle.kts index 0a6d57bef..f2ce134ee 100644 --- a/firebase-crashlytics/build.gradle.kts +++ b/firebase-crashlytics/build.gradle.kts @@ -1,3 +1,5 @@ +import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSetTree + /* * Copyright (c) 2020 GitLive Ltd. Use of this source code is governed by the Apache 2.0 license. */ @@ -47,7 +49,16 @@ val supportIosTarget = project.property("skipIosTarget") != "true" kotlin { + targets.configureEach { + compilations.configureEach { + kotlinOptions.freeCompilerArgs += "-Xexpect-actual-classes" + } + } + + @Suppress("OPT_IN_USAGE") androidTarget { + instrumentedTestVariant.sourceSetTree.set(KotlinSourceSetTree.test) + unitTestVariant.sourceSetTree.set(KotlinSourceSetTree.test) publishAllLibraryVariants() compilations.configureEach { kotlinOptions { @@ -70,7 +81,8 @@ kotlin { // } if (supportIosTarget) { - ios() + iosArm64() + iosX64() iosSimulatorArm64() cocoapods { ios.deploymentTarget = "11.0" @@ -93,6 +105,9 @@ kotlin { this.languageVersion = languageVersion progressiveMode = true optIn("kotlinx.coroutines.ExperimentalCoroutinesApi") + if (name.lowercase().contains("ios")) { + optIn("kotlinx.cinterop.ExperimentalForeignApi") + } } } @@ -103,7 +118,7 @@ kotlin { } } - val commonTest by getting { + getByName("commonTest") { dependencies { implementation(project(":test-utils")) } @@ -115,25 +130,9 @@ kotlin { } } - getByName("androidInstrumentedTest") { - dependencies { - dependsOn(commonTest) - } - } - // getByName("jvmMain") { // kotlin.srcDir("src/androidMain/kotlin") // } - - if (supportIosTarget) { - val iosMain by getting - val iosSimulatorArm64Main by getting - iosSimulatorArm64Main.dependsOn(iosMain) - - val iosTest by sourceSets.getting - val iosSimulatorArm64Test by sourceSets.getting - iosSimulatorArm64Test.dependsOn(iosTest) - } } } diff --git a/firebase-crashlytics/package.json b/firebase-crashlytics/package.json index 8ebb0f3c7..845bef8a8 100644 --- a/firebase-crashlytics/package.json +++ b/firebase-crashlytics/package.json @@ -1,6 +1,6 @@ { "name": "@gitlive/firebase-crashlytics", - "version": "1.10.1-SNAPSHOT", + "version": "1.10.4", "description": "Wrapper around firebase for usage in Kotlin Multiplatform projects", "main": "firebase-crashlytics.js", "scripts": { @@ -23,7 +23,7 @@ }, "homepage": "https://github.com/GitLiveApp/firebase-kotlin-sdk", "dependencies": { - "@gitlive/firebase-app": "1.10.1-SNAPSHOT", + "@gitlive/firebase-app": "1.10.4", "firebase": "9.19.1", "kotlin": "1.6.10", "kotlinx-coroutines-core": "1.6.1-native-mt" diff --git a/firebase-crashlytics/src/androidInstrumentedTest/kotlin/dev/gitlive/firebase/crashlytics/crashlytics.kt b/firebase-crashlytics/src/androidInstrumentedTest/kotlin/dev/gitlive/firebase/crashlytics/crashlytics.kt index 170188310..a4b396d51 100644 --- a/firebase-crashlytics/src/androidInstrumentedTest/kotlin/dev/gitlive/firebase/crashlytics/crashlytics.kt +++ b/firebase-crashlytics/src/androidInstrumentedTest/kotlin/dev/gitlive/firebase/crashlytics/crashlytics.kt @@ -12,6 +12,5 @@ actual val emulatorHost: String = "10.0.2.2" actual val context: Any = InstrumentationRegistry.getInstrumentation().targetContext -actual fun runTest(test: suspend CoroutineScope.() -> Unit) = kotlinx.coroutines.test.runTest { test() } @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) actual annotation class IgnoreForAndroidUnitTest diff --git a/firebase-crashlytics/src/androidUnitTest/kotlin/dev/gitlive/firebase/crashlytics/crashlytics.kt b/firebase-crashlytics/src/androidUnitTest/kotlin/dev/gitlive/firebase/crashlytics/crashlytics.kt index 4a1511c95..8008be669 100644 --- a/firebase-crashlytics/src/androidUnitTest/kotlin/dev/gitlive/firebase/crashlytics/crashlytics.kt +++ b/firebase-crashlytics/src/androidUnitTest/kotlin/dev/gitlive/firebase/crashlytics/crashlytics.kt @@ -12,5 +12,4 @@ actual val emulatorHost: String = "10.0.2.2" actual val context: Any = "" -actual fun runTest(test: suspend CoroutineScope.() -> Unit) = kotlinx.coroutines.test.runTest { test() } actual typealias IgnoreForAndroidUnitTest = Ignore diff --git a/firebase-crashlytics/src/commonTest/kotlin/dev/gitlive/firebase/crashlytics/crashlytics.kt b/firebase-crashlytics/src/commonTest/kotlin/dev/gitlive/firebase/crashlytics/crashlytics.kt index 78188aebd..8c1933846 100644 --- a/firebase-crashlytics/src/commonTest/kotlin/dev/gitlive/firebase/crashlytics/crashlytics.kt +++ b/firebase-crashlytics/src/commonTest/kotlin/dev/gitlive/firebase/crashlytics/crashlytics.kt @@ -8,90 +8,80 @@ import dev.gitlive.firebase.Firebase import dev.gitlive.firebase.FirebaseOptions import dev.gitlive.firebase.apps import dev.gitlive.firebase.initialize -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.test.TestResult +import dev.gitlive.firebase.runBlockingTest +import dev.gitlive.firebase.runTest +import kotlin.test.AfterTest import kotlin.test.BeforeTest import kotlin.test.Test import kotlin.test.assertFalse expect val emulatorHost: String expect val context: Any -expect fun runTest(test: suspend CoroutineScope.() -> Unit): TestResult expect annotation class IgnoreForAndroidUnitTest() @IgnoreForAndroidUnitTest class FirebaseCrashlyticsTest { + lateinit var crashlytics: FirebaseCrashlytics + @BeforeTest fun initializeFirebase() { - Firebase - .takeIf { Firebase.apps(context).isEmpty() } - ?.apply { - initialize( - context, - FirebaseOptions( - applicationId = "1:846484016111:ios:dd1f6688bad7af768c841a", - apiKey = "AIzaSyCK87dcMFhzCz_kJVs2cT2AVlqOTLuyWV0", - databaseUrl = "https://fir-kotlin-sdk.firebaseio.com", - storageBucket = "fir-kotlin-sdk.appspot.com", - projectId = "fir-kotlin-sdk", - gcmSenderId = "846484016111" - ) - ) - } + val app = Firebase.apps(context).firstOrNull() ?: Firebase.initialize( + context, + FirebaseOptions( + applicationId = "1:846484016111:ios:dd1f6688bad7af768c841a", + apiKey = "AIzaSyCK87dcMFhzCz_kJVs2cT2AVlqOTLuyWV0", + databaseUrl = "https://fir-kotlin-sdk.firebaseio.com", + storageBucket = "fir-kotlin-sdk.appspot.com", + projectId = "fir-kotlin-sdk", + gcmSenderId = "846484016111" + ) + ) + + crashlytics = Firebase.crashlytics(app) + } + + @AfterTest + fun deinitializeFirebase() = runBlockingTest { + Firebase.apps(context).forEach { + it.delete() + } } @Test fun testRecordException() = runTest { - - val crashlytics = Firebase.crashlytics crashlytics.recordException(Exception("Test Exception")) } @Test fun testLog() = runTest { - - val crashlytics = Firebase.crashlytics crashlytics.log("Test Log") } @Test fun testSetUserId() = runTest { - - val crashlytics = Firebase.crashlytics crashlytics.setUserId("Test User Id") } @Test fun testSendUnsentReports() = runTest { - - val crashlytics = Firebase.crashlytics crashlytics.sendUnsentReports() - } @Test fun testDeleteUnsentReports() = runTest { - - val crashlytics = Firebase.crashlytics crashlytics.deleteUnsentReports() - } @Test fun testDidCrashOnPreviousExecution() = runTest { - - val crashlytics = Firebase.crashlytics val didCrash = crashlytics.didCrashOnPreviousExecution() assertFalse { didCrash } } @Test fun testSetCrashlyticsCollectionEnabled() = runTest { - - val crashlytics = Firebase.crashlytics crashlytics.setCrashlyticsCollectionEnabled(true) - } } diff --git a/firebase-crashlytics/src/iosTest/kotlin/dev/gitlive/firebase/crashlytics/crashlytics.kt b/firebase-crashlytics/src/iosTest/kotlin/dev/gitlive/firebase/crashlytics/crashlytics.kt index 6fbbae46a..602cd1be6 100644 --- a/firebase-crashlytics/src/iosTest/kotlin/dev/gitlive/firebase/crashlytics/crashlytics.kt +++ b/firebase-crashlytics/src/iosTest/kotlin/dev/gitlive/firebase/crashlytics/crashlytics.kt @@ -4,23 +4,9 @@ package dev.gitlive.firebase.crashlytics -import kotlinx.coroutines.* -import platform.Foundation.* - actual val emulatorHost: String = "localhost" actual val context: Any = Unit -actual fun runTest(test: suspend CoroutineScope.() -> Unit) = runBlocking { - val testRun = MainScope().async { test() } - while (testRun.isActive) { - NSRunLoop.mainRunLoop.runMode( - NSDefaultRunLoopMode, - beforeDate = NSDate.create(timeInterval = 1.0, sinceDate = NSDate()) - ) - yield() - } - testRun.await() -} @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) actual annotation class IgnoreForAndroidUnitTest diff --git a/firebase-crashlytics/src/jvmMain/kotlin/dev/gitlive/firebase/crashlytics/crashlytics.jvm.kt b/firebase-crashlytics/src/jvmMain/kotlin/dev/gitlive/firebase/crashlytics/crashlytics.jvm.kt index 36d363bba..92aba8ea9 100644 --- a/firebase-crashlytics/src/jvmMain/kotlin/dev/gitlive/firebase/crashlytics/crashlytics.jvm.kt +++ b/firebase-crashlytics/src/jvmMain/kotlin/dev/gitlive/firebase/crashlytics/crashlytics.jvm.kt @@ -58,4 +58,4 @@ actual class FirebaseCrashlytics { } } -actual open class FirebaseCrashlyticsException : FirebaseException() \ No newline at end of file +actual open class FirebaseCrashlyticsException internal constructor(message: String) : FirebaseException(message) \ No newline at end of file diff --git a/firebase-database/build.gradle.kts b/firebase-database/build.gradle.kts index 526bbb90c..0477b63e3 100644 --- a/firebase-database/build.gradle.kts +++ b/firebase-database/build.gradle.kts @@ -1,3 +1,5 @@ +import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSetTree + /* * Copyright (c) 2020 GitLive Ltd. Use of this source code is governed by the Apache 2.0 license. */ @@ -52,7 +54,16 @@ val supportIosTarget = project.property("skipIosTarget") != "true" kotlin { + targets.configureEach { + compilations.configureEach { + kotlinOptions.freeCompilerArgs += "-Xexpect-actual-classes" + } + } + + @Suppress("OPT_IN_USAGE") androidTarget { + instrumentedTestVariant.sourceSetTree.set(KotlinSourceSetTree.test) + unitTestVariant.sourceSetTree.set(KotlinSourceSetTree.test) publishAllLibraryVariants() compilations.configureEach { kotlinOptions { @@ -75,7 +86,8 @@ kotlin { } if (supportIosTarget) { - ios() + iosArm64() + iosX64() iosSimulatorArm64() cocoapods { ios.deploymentTarget = "11.0" @@ -122,6 +134,9 @@ kotlin { optIn("kotlinx.coroutines.ExperimentalCoroutinesApi") optIn("kotlinx.coroutines.FlowPreview") optIn("kotlinx.serialization.InternalSerializationApi") + if (name.lowercase().contains("ios")) { + optIn("kotlinx.cinterop.ExperimentalForeignApi") + } } } @@ -132,7 +147,7 @@ kotlin { } } - val commonTest by getting { + getByName("commonTest") { dependencies { implementation(project(":test-utils")) } @@ -146,21 +161,6 @@ kotlin { getByName("jvmMain") { kotlin.srcDir("src/androidMain/kotlin") } - - getByName("androidInstrumentedTest") { - dependencies { - dependsOn(commonTest) - } - } - - if (supportIosTarget) { - val iosMain by getting - val iosSimulatorArm64Main by getting - iosSimulatorArm64Main.dependsOn(iosMain) - val iosTest by sourceSets.getting - val iosSimulatorArm64Test by getting - iosSimulatorArm64Test.dependsOn(iosTest) - } } } diff --git a/firebase-database/package.json b/firebase-database/package.json index 33c2bccc5..2251ea0f5 100644 --- a/firebase-database/package.json +++ b/firebase-database/package.json @@ -1,6 +1,6 @@ { "name": "@gitlive/firebase-database", - "version": "1.10.1-SNAPSHOT", + "version": "1.10.4", "description": "Wrapper around firebase for usage in Kotlin Multiplatform projects", "main": "firebase-database.js", "scripts": { @@ -23,7 +23,7 @@ }, "homepage": "https://github.com/GitLiveApp/firebase-kotlin-sdk", "dependencies": { - "@gitlive/firebase-app": "1.10.1-SNAPSHOT", + "@gitlive/firebase-app": "1.10.4", "firebase": "9.19.1", "kotlin": "1.8.20", "kotlinx-coroutines-core": "1.6.4" diff --git a/firebase-database/src/androidInstrumentedTest/kotlin/dev/gitlive/firebase/database/database.kt b/firebase-database/src/androidInstrumentedTest/kotlin/dev/gitlive/firebase/database/database.kt index 5c4f015c9..0ecd0dc35 100644 --- a/firebase-database/src/androidInstrumentedTest/kotlin/dev/gitlive/firebase/database/database.kt +++ b/firebase-database/src/androidInstrumentedTest/kotlin/dev/gitlive/firebase/database/database.kt @@ -11,6 +11,5 @@ import kotlinx.coroutines.test.TestResult actual val emulatorHost: String = "10.0.2.2" actual val context: Any = InstrumentationRegistry.getInstrumentation().targetContext -actual fun runTest(test: suspend () -> Unit) = kotlinx.coroutines.test.runTest { test() } @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) actual annotation class IgnoreForAndroidUnitTest diff --git a/firebase-database/src/androidMain/kotlin/dev/gitlive/firebase/database/database.kt b/firebase-database/src/androidMain/kotlin/dev/gitlive/firebase/database/database.kt index bdc6aa398..086087c4c 100644 --- a/firebase-database/src/androidMain/kotlin/dev/gitlive/firebase/database/database.kt +++ b/firebase-database/src/androidMain/kotlin/dev/gitlive/firebase/database/database.kt @@ -38,7 +38,7 @@ suspend fun Task.awaitWhileOnline(database: FirebaseDatabase): T = .reference(".info/connected") .valueEvents .debounce(2.seconds) - .filter { !it.value() } + .filterNot { it.value() } .map { throw DatabaseException("Database not connected", null) } ) .first() diff --git a/firebase-database/src/androidUnitTest/kotlin/dev/gitlive/firebase/database/database.kt b/firebase-database/src/androidUnitTest/kotlin/dev/gitlive/firebase/database/database.kt index cb443b3d0..42f4e85d4 100644 --- a/firebase-database/src/androidUnitTest/kotlin/dev/gitlive/firebase/database/database.kt +++ b/firebase-database/src/androidUnitTest/kotlin/dev/gitlive/firebase/database/database.kt @@ -9,5 +9,4 @@ import org.junit.Ignore actual val emulatorHost: String = "10.0.2.2" actual val context: Any = "" -actual fun runTest(test: suspend () -> Unit) = kotlinx.coroutines.test.runTest { test() } actual typealias IgnoreForAndroidUnitTest = Ignore diff --git a/firebase-database/src/commonTest/kotlin/dev/gitlive/firebase/database/database.kt b/firebase-database/src/commonTest/kotlin/dev/gitlive/firebase/database/database.kt index 43b79ed16..4c94209a2 100644 --- a/firebase-database/src/commonTest/kotlin/dev/gitlive/firebase/database/database.kt +++ b/firebase-database/src/commonTest/kotlin/dev/gitlive/firebase/database/database.kt @@ -1,19 +1,24 @@ package dev.gitlive.firebase.database import dev.gitlive.firebase.* +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.first -import kotlinx.coroutines.test.TestResult -import kotlinx.serialization.* +import kotlinx.coroutines.withContext +import kotlinx.coroutines.withTimeout +import kotlinx.serialization.Serializable +import kotlinx.serialization.SerializationStrategy import kotlin.test.* +import kotlin.time.Duration.Companion.minutes expect val emulatorHost: String expect val context: Any -expect fun runTest(test: suspend () -> Unit): TestResult expect annotation class IgnoreForAndroidUnitTest() @IgnoreForAndroidUnitTest class FirebaseDatabaseTest { + lateinit var database: FirebaseDatabase + @Serializable data class FirebaseDatabaseChildTest(val prop1: String? = null, val time: Double = 0.0) @@ -22,29 +27,36 @@ class FirebaseDatabaseTest { @BeforeTest fun initializeFirebase() { - Firebase - .takeIf { Firebase.apps(context).isEmpty() } - ?.apply { - initialize( - context, - FirebaseOptions( - applicationId = "1:846484016111:ios:dd1f6688bad7af768c841a", - apiKey = "AIzaSyCK87dcMFhzCz_kJVs2cT2AVlqOTLuyWV0", - databaseUrl = "http://fir-kotlin-sdk.firebaseio.com", - storageBucket = "fir-kotlin-sdk.appspot.com", - projectId = "fir-kotlin-sdk", - gcmSenderId = "846484016111" - ) - ) - Firebase.database.useEmulator(emulatorHost, 9000) - Firebase.database.setSettings(createFirebaseDatabaseTestSettings()) - } + val app = Firebase.apps(context).firstOrNull() ?: Firebase.initialize( + context, + FirebaseOptions( + applicationId = "1:846484016111:ios:dd1f6688bad7af768c841a", + apiKey = "AIzaSyCK87dcMFhzCz_kJVs2cT2AVlqOTLuyWV0", + databaseUrl = "https://fir-kotlin-sdk.firebaseio.com", + storageBucket = "fir-kotlin-sdk.appspot.com", + projectId = "fir-kotlin-sdk", + gcmSenderId = "846484016111" + ) + ) + + database = Firebase.database(app).apply { + useEmulator(emulatorHost, 9000) + } + } + + @AfterTest + fun deinitializeFirebase() = runBlockingTest { + Firebase.apps(context).forEach { + it.delete() + } } @Test fun testSetValue() = runTest { + ensureDatabaseConnected() val testValue = "test" - val testReference = Firebase.database.reference("testPath") + val testReference = database.reference("testPath") + testReference.setValue(testValue) val testReferenceValue = testReference @@ -58,7 +70,7 @@ class FirebaseDatabaseTest { @Test fun testChildCount() = runTest { setupRealtimeData() - val dataSnapshot = Firebase.database + val dataSnapshot = database .reference("FirebaseRealtimeDatabaseTest") .valueEvents .first() @@ -93,7 +105,7 @@ class FirebaseDatabaseTest { // @Test // fun testBasicDecrementTransaction() = runTest { // val data = DatabaseTest("PostTwo", 2) -// val userRef = Firebase.database.reference("users/user_1/post_id_2") +// val userRef = database.reference("users/user_1/post_id_2") // setupDatabase(userRef, data, DatabaseTest.serializer()) // // // Check database before transaction @@ -115,7 +127,8 @@ class FirebaseDatabaseTest { @Test fun testSetServerTimestamp() = runTest { - val testReference = Firebase.database.reference("testSetServerTimestamp") + ensureDatabaseConnected() + val testReference = database.reference("testSetServerTimestamp") testReference.setValue(ServerValue.TIMESTAMP) @@ -129,7 +142,8 @@ class FirebaseDatabaseTest { @Test fun testIncrement() = runTest { - val testReference = Firebase.database.reference("testIncrement") + ensureDatabaseConnected() + val testReference = database.reference("testIncrement") testReference.setValue(2.0) @@ -150,7 +164,8 @@ class FirebaseDatabaseTest { } private suspend fun setupRealtimeData() { - val firebaseDatabaseTestReference = Firebase.database + ensureDatabaseConnected() + val firebaseDatabaseTestReference = database .reference("FirebaseRealtimeDatabaseTest") val firebaseDatabaseChildTest1 = FirebaseDatabaseChildTest("aaa") @@ -162,12 +177,6 @@ class FirebaseDatabaseTest { firebaseDatabaseTestReference.child("3").setValue(firebaseDatabaseChildTest3) } - private suspend fun cleanUp() { - Firebase - .takeIf { Firebase.apps(context).isNotEmpty() } - ?.apply { app.delete() } - } - private suspend fun setupDatabase(ref: DatabaseReference, data: T, strategy: SerializationStrategy) { try { ref.setValue(strategy, data) @@ -176,4 +185,10 @@ class FirebaseDatabaseTest { throw err } } + + private suspend fun ensureDatabaseConnected() = withContext(Dispatchers.Default.limitedParallelism(1)) { + withTimeout(2.minutes) { + database.reference(".info/connected").valueEvents.first { it.value() } + } + } } diff --git a/firebase-database/src/iosTest/kotlin/dev/gitlive/firebase/database/database.kt b/firebase-database/src/iosTest/kotlin/dev/gitlive/firebase/database/database.kt index e6b38bb00..410cf18bb 100644 --- a/firebase-database/src/iosTest/kotlin/dev/gitlive/firebase/database/database.kt +++ b/firebase-database/src/iosTest/kotlin/dev/gitlive/firebase/database/database.kt @@ -4,23 +4,9 @@ package dev.gitlive.firebase.database -import kotlinx.coroutines.* -import platform.Foundation.* - actual val emulatorHost: String = "localhost" actual val context: Any = Unit -actual fun runTest(test: suspend () -> Unit) = runBlocking { - val testRun = MainScope().async { test() } - while (testRun.isActive) { - NSRunLoop.mainRunLoop.runMode( - NSDefaultRunLoopMode, - beforeDate = NSDate.create(timeInterval = 1.0, sinceDate = NSDate()) - ) - yield() - } - testRun.await() -} @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) actual annotation class IgnoreForAndroidUnitTest diff --git a/firebase-database/src/jsTest/kotlin/dev/gitlive/firebase/database/database.kt b/firebase-database/src/jsTest/kotlin/dev/gitlive/firebase/database/database.kt index 8faada7b3..48e4649bb 100644 --- a/firebase-database/src/jsTest/kotlin/dev/gitlive/firebase/database/database.kt +++ b/firebase-database/src/jsTest/kotlin/dev/gitlive/firebase/database/database.kt @@ -1,29 +1,8 @@ package dev.gitlive.firebase.database -import dev.gitlive.firebase.Firebase -import dev.gitlive.firebase.database.externals.getDatabase -import dev.gitlive.firebase.database.externals.goOffline -import dev.gitlive.firebase.database.externals.goOnline -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.withContext -import kotlinx.coroutines.withTimeout -import kotlin.time.Duration.Companion.minutes -import kotlin.time.Duration.Companion.seconds - actual val emulatorHost: String = "127.0.0.1" // in JS tests connection is refused if we use localhost actual val context: Any = Unit -actual fun runTest(test: suspend () -> Unit) = kotlinx.coroutines.test.runTest(timeout = 5.minutes) { - // in JS tests we need to wait for the database to be connected - awaitDatabaseConnection() - test() -} -private suspend fun awaitDatabaseConnection() = withContext(Dispatchers.Default) { - withTimeout(2.minutes) { - Firebase.database.reference(".info/connected").valueEvents.first { it.value() } - } -} @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) actual annotation class IgnoreForAndroidUnitTest diff --git a/firebase-database/src/jvmTest/kotlin/dev/gitlive/firebase/database/database.kt b/firebase-database/src/jvmTest/kotlin/dev/gitlive/firebase/database/database.kt index a9757da98..27668d277 100644 --- a/firebase-database/src/jvmTest/kotlin/dev/gitlive/firebase/database/database.kt +++ b/firebase-database/src/jvmTest/kotlin/dev/gitlive/firebase/database/database.kt @@ -10,6 +10,5 @@ actual val emulatorHost: String = "10.0.2.2" actual val context: Any = Unit -actual fun runTest(test: suspend () -> Unit) = kotlinx.coroutines.test.runTest { test() } @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) actual annotation class IgnoreForAndroidUnitTest diff --git a/firebase-firestore/build.gradle.kts b/firebase-firestore/build.gradle.kts index f7d39ff7a..2e830f1eb 100644 --- a/firebase-firestore/build.gradle.kts +++ b/firebase-firestore/build.gradle.kts @@ -1,3 +1,5 @@ +import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSetTree + /* * Copyright (c) 2020 GitLive Ltd. Use of this source code is governed by the Apache 2.0 license. */ @@ -49,7 +51,16 @@ val supportIosTarget = project.property("skipIosTarget") != "true" kotlin { + targets.configureEach { + compilations.configureEach { + kotlinOptions.freeCompilerArgs += "-Xexpect-actual-classes" + } + } + + @Suppress("OPT_IN_USAGE") androidTarget { + instrumentedTestVariant.sourceSetTree.set(KotlinSourceSetTree.test) + unitTestVariant.sourceSetTree.set(KotlinSourceSetTree.test) publishAllLibraryVariants() compilations.configureEach { kotlinOptions { @@ -72,10 +83,11 @@ kotlin { } if (supportIosTarget) { - ios() + iosArm64() + iosX64() iosSimulatorArm64() cocoapods { - ios.deploymentTarget = "11.0" + ios.deploymentTarget = "12.0" framework { baseName = "FirebaseFirestore" } @@ -140,7 +152,7 @@ kotlin { } } - val commonTest by getting { + getByName("commonTest") { dependencies { implementation(project(":test-utils")) } @@ -148,24 +160,9 @@ kotlin { getByName("androidMain") { dependencies { - api("com.google.firebase:firebase-firestore-ktx") + api("com.google.firebase:firebase-firestore") } } - - getByName("androidInstrumentedTest") { - dependencies { - dependsOn(commonTest) - } - } - - if (supportIosTarget) { - val iosMain by getting - val iosSimulatorArm64Main by getting - iosSimulatorArm64Main.dependsOn(iosMain) - val iosTest by sourceSets.getting - val iosSimulatorArm64Test by getting - iosSimulatorArm64Test.dependsOn(iosTest) - } } } diff --git a/firebase-firestore/package.json b/firebase-firestore/package.json index 5b828c6f5..02a96298c 100644 --- a/firebase-firestore/package.json +++ b/firebase-firestore/package.json @@ -1,6 +1,6 @@ { "name": "@gitlive/firebase-firestore", - "version": "1.10.1-SNAPSHOT", + "version": "1.10.4", "description": "Wrapper around firebase for usage in Kotlin Multiplatform projects", "main": "firebase-firestore.js", "scripts": { @@ -23,7 +23,7 @@ }, "homepage": "https://github.com/GitLiveApp/firebase-kotlin-sdk", "dependencies": { - "@gitlive/firebase-app": "1.10.1-SNAPSHOT", + "@gitlive/firebase-app": "1.10.4", "firebase": "9.19.1", "kotlin": "1.8.20", "kotlinx-coroutines-core": "1.6.4" diff --git a/firebase-firestore/src/androidInstrumentedTest/kotlin/dev/gitlive/firebase/firestore/firestore.kt b/firebase-firestore/src/androidInstrumentedTest/kotlin/dev/gitlive/firebase/firestore/firestore.kt index 4563ac81f..8c6035f28 100644 --- a/firebase-firestore/src/androidInstrumentedTest/kotlin/dev/gitlive/firebase/firestore/firestore.kt +++ b/firebase-firestore/src/androidInstrumentedTest/kotlin/dev/gitlive/firebase/firestore/firestore.kt @@ -6,14 +6,10 @@ package dev.gitlive.firebase.firestore import androidx.test.platform.app.InstrumentationRegistry -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.runBlocking actual val emulatorHost: String = "10.0.2.2" actual val context: Any = InstrumentationRegistry.getInstrumentation().targetContext -actual fun runTest(test: suspend CoroutineScope.() -> Unit) = runBlocking { test() } - actual fun encodedAsMap(encoded: Any?): Map = encoded as Map actual fun Map.asEncoded(): Any = this diff --git a/firebase-firestore/src/androidMain/kotlin/dev/gitlive/firebase/firestore/_encoders.kt b/firebase-firestore/src/androidMain/kotlin/dev/gitlive/firebase/firestore/_encoders.kt index 1c6be4a86..d12bda859 100644 --- a/firebase-firestore/src/androidMain/kotlin/dev/gitlive/firebase/firestore/_encoders.kt +++ b/firebase-firestore/src/androidMain/kotlin/dev/gitlive/firebase/firestore/_encoders.kt @@ -1,6 +1,7 @@ package dev.gitlive.firebase.firestore -actual fun isSpecialValue(value: Any) = when(value) { +@PublishedApi +internal actual fun isSpecialValue(value: Any) = when(value) { is NativeFieldValue, is NativeGeoPoint, is NativeTimestamp, diff --git a/firebase-firestore/src/androidMain/kotlin/dev/gitlive/firebase/firestore/firestore.kt b/firebase-firestore/src/androidMain/kotlin/dev/gitlive/firebase/firestore/firestore.kt index dc36f231f..1b0a65b8f 100644 --- a/firebase-firestore/src/androidMain/kotlin/dev/gitlive/firebase/firestore/firestore.kt +++ b/firebase-firestore/src/androidMain/kotlin/dev/gitlive/firebase/firestore/firestore.kt @@ -6,16 +6,7 @@ package dev.gitlive.firebase.firestore import com.google.android.gms.tasks.Task -import com.google.firebase.firestore.MemoryCacheSettings -import com.google.firebase.firestore.MemoryEagerGcSettings -import com.google.firebase.firestore.MemoryLruGcSettings -import com.google.firebase.firestore.MetadataChanges -import com.google.firebase.firestore.PersistentCacheSettings -import com.google.firebase.firestore.ktx.firestoreSettings -import com.google.firebase.firestore.ktx.memoryCacheSettings -import com.google.firebase.firestore.ktx.memoryEagerGcSettings -import com.google.firebase.firestore.ktx.memoryLruGcSettings -import com.google.firebase.firestore.ktx.persistentCacheSettings +import com.google.firebase.firestore.* import dev.gitlive.firebase.* import kotlinx.coroutines.* import kotlinx.coroutines.channels.awaitClose diff --git a/firebase-firestore/src/androidUnitTest/kotlin/firestore/firestore.kt b/firebase-firestore/src/androidUnitTest/kotlin/firestore/firestore.kt index b9ad6b347..e56e244c6 100644 --- a/firebase-firestore/src/androidUnitTest/kotlin/firestore/firestore.kt +++ b/firebase-firestore/src/androidUnitTest/kotlin/firestore/firestore.kt @@ -5,14 +5,9 @@ @file:JvmName("tests") package dev.gitlive.firebase.firestore -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.runBlocking - actual val emulatorHost: String = "10.0.2.2" actual val context: Any = Unit -actual fun runTest(test: suspend CoroutineScope.() -> Unit) = runBlocking { test() } - actual fun encodedAsMap(encoded: Any?): Map = encoded as Map actual fun Map.asEncoded(): Any = this diff --git a/firebase-firestore/src/commonTest/kotlin/dev/gitlive/firebase/firestore/DeferredExtensionsTest.kt b/firebase-firestore/src/commonTest/kotlin/dev/gitlive/firebase/firestore/DeferredExtensionsTest.kt index d0b6378c5..147a1c9d8 100644 --- a/firebase-firestore/src/commonTest/kotlin/dev/gitlive/firebase/firestore/DeferredExtensionsTest.kt +++ b/firebase-firestore/src/commonTest/kotlin/dev/gitlive/firebase/firestore/DeferredExtensionsTest.kt @@ -1,5 +1,6 @@ package dev.gitlive.firebase.firestore +import dev.gitlive.firebase.runTest import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CompletableDeferred import kotlin.test.Test diff --git a/firebase-firestore/src/commonTest/kotlin/dev/gitlive/firebase/firestore/FieldValueTests.kt b/firebase-firestore/src/commonTest/kotlin/dev/gitlive/firebase/firestore/FieldValueTests.kt index afcffb9b3..138a1e070 100644 --- a/firebase-firestore/src/commonTest/kotlin/dev/gitlive/firebase/firestore/FieldValueTests.kt +++ b/firebase-firestore/src/commonTest/kotlin/dev/gitlive/firebase/firestore/FieldValueTests.kt @@ -1,6 +1,7 @@ package dev.gitlive.firebase.firestore import dev.gitlive.firebase.firebaseSerializer +import dev.gitlive.firebase.runTest import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNotEquals diff --git a/firebase-firestore/src/commonTest/kotlin/dev/gitlive/firebase/firestore/FirestoreAsync.kt b/firebase-firestore/src/commonTest/kotlin/dev/gitlive/firebase/firestore/FirestoreAsync.kt index a7ee467f0..af26aca81 100644 --- a/firebase-firestore/src/commonTest/kotlin/dev/gitlive/firebase/firestore/FirestoreAsync.kt +++ b/firebase-firestore/src/commonTest/kotlin/dev/gitlive/firebase/firestore/FirestoreAsync.kt @@ -1,10 +1,8 @@ package dev.gitlive.firebase.firestore -import dev.gitlive.firebase.Firebase -import dev.gitlive.firebase.FirebaseOptions -import dev.gitlive.firebase.apps -import dev.gitlive.firebase.initialize +import dev.gitlive.firebase.* import kotlinx.serialization.Serializable +import kotlin.test.AfterTest import kotlin.test.BeforeTest import kotlin.test.Test @@ -12,65 +10,73 @@ import kotlin.test.Test @IgnoreForAndroidUnitTest class FirestoreAsync { + lateinit var firestore: FirebaseFirestore + @BeforeTest fun initializeFirebase() { - Firebase - .takeIf { Firebase.apps(context).isEmpty() } - ?.apply { - initialize( - context, - FirebaseOptions( - applicationId = "1:846484016111:ios:dd1f6688bad7af768c841a", - apiKey = "AIzaSyCK87dcMFhzCz_kJVs2cT2AVlqOTLuyWV0", - databaseUrl = "https://fir-kotlin-sdk.firebaseio.com", - storageBucket = "fir-kotlin-sdk.appspot.com", - projectId = "fir-kotlin-sdk", - gcmSenderId = "846484016111" - ) - ) - Firebase.firestore.useEmulator(emulatorHost, 8080) - Firebase.firestore.setSettings(createFirestoreTestSettings(cacheSettings = LocalCacheSettings.Persistent())) - } + val app = Firebase.apps(context).firstOrNull() ?: Firebase.initialize( + context, + FirebaseOptions( + applicationId = "1:846484016111:ios:dd1f6688bad7af768c841a", + apiKey = "AIzaSyCK87dcMFhzCz_kJVs2cT2AVlqOTLuyWV0", + databaseUrl = "https://fir-kotlin-sdk.firebaseio.com", + storageBucket = "fir-kotlin-sdk.appspot.com", + projectId = "fir-kotlin-sdk", + gcmSenderId = "846484016111" + ) + ) + + firestore = Firebase.firestore(app).apply { + useEmulator(emulatorHost, 8080) + } } + + @AfterTest + fun deinitializeFirebase() = runBlockingTest { + Firebase.apps(context).forEach { + it.delete() + } + } + @Serializable data class TestData(val value: Int) @Test fun asyncDocumentReferenceTest() = runTest { - fun getDocument() = Firebase.firestore.collection("asyncDocumentReferenceTest") + fun getDocument() = firestore.collection("asyncDocumentReferenceTest") .document("asyncDocumentReferenceTest") - Firebase.firestore.disableNetwork() + firestore.disableNetwork() val update1 = getDocument().async.set(TestData(1)) val update2 = getDocument().async.update(TestData(2)) - Firebase.firestore.enableNetwork() + firestore.enableNetwork() update1.await() update2.await() } @Test fun asyncBatchTest() = runTest { - val batch = Firebase.firestore.batch() + val batch = firestore.batch() - fun getDocument() = Firebase.firestore.collection("asyncBatchTest") + fun getDocument() = firestore.collection("asyncBatchTest") .document("asyncBatchTest") - Firebase.firestore.disableNetwork() + firestore.disableNetwork() batch.set(getDocument(), TestData(1)) batch.update(getDocument(), TestData(1)) val result = batch.async.commit() - Firebase.firestore.enableNetwork() + firestore.enableNetwork() result.await() } @Test fun asyncCollectionAddTest() = runTest { - Firebase.firestore.disableNetwork() - val result = Firebase.firestore.collection("asyncCollectionAddTest").async + firestore.disableNetwork() + val result = firestore.collection("asyncCollectionAddTest").async .add(TestData(1)) - Firebase.firestore.enableNetwork() + firestore.enableNetwork() result.await() } diff --git a/firebase-firestore/src/commonTest/kotlin/dev/gitlive/firebase/firestore/GeoPointTests.kt b/firebase-firestore/src/commonTest/kotlin/dev/gitlive/firebase/firestore/GeoPointTests.kt index b74cf8d81..6571168d1 100644 --- a/firebase-firestore/src/commonTest/kotlin/dev/gitlive/firebase/firestore/GeoPointTests.kt +++ b/firebase-firestore/src/commonTest/kotlin/dev/gitlive/firebase/firestore/GeoPointTests.kt @@ -3,6 +3,7 @@ package dev.gitlive.firebase.firestore import dev.gitlive.firebase.decode import dev.gitlive.firebase.encode import dev.gitlive.firebase.firebaseSerializer +import dev.gitlive.firebase.runTest import kotlinx.serialization.Serializable import kotlin.test.Test import kotlin.test.assertEquals diff --git a/firebase-firestore/src/commonTest/kotlin/dev/gitlive/firebase/firestore/TimestampTests.kt b/firebase-firestore/src/commonTest/kotlin/dev/gitlive/firebase/firestore/TimestampTests.kt index 21ceaf2e4..541d7fdd5 100644 --- a/firebase-firestore/src/commonTest/kotlin/dev/gitlive/firebase/firestore/TimestampTests.kt +++ b/firebase-firestore/src/commonTest/kotlin/dev/gitlive/firebase/firestore/TimestampTests.kt @@ -1,10 +1,6 @@ package dev.gitlive.firebase.firestore -import dev.gitlive.firebase.decode -import dev.gitlive.firebase.encode -import dev.gitlive.firebase.firebaseSerializer -import dev.gitlive.firebase.nativeAssertEquals -import dev.gitlive.firebase.nativeMapOf +import dev.gitlive.firebase.* import kotlinx.serialization.Serializable import kotlin.test.* import kotlin.time.Duration.Companion.milliseconds diff --git a/firebase-firestore/src/commonTest/kotlin/dev/gitlive/firebase/firestore/firestore.kt b/firebase-firestore/src/commonTest/kotlin/dev/gitlive/firebase/firestore/firestore.kt index bc0999b32..b2fec5e9c 100644 --- a/firebase-firestore/src/commonTest/kotlin/dev/gitlive/firebase/firestore/firestore.kt +++ b/firebase-firestore/src/commonTest/kotlin/dev/gitlive/firebase/firestore/firestore.kt @@ -4,14 +4,7 @@ package dev.gitlive.firebase.firestore -import dev.gitlive.firebase.EncodeSettings -import dev.gitlive.firebase.Firebase -import dev.gitlive.firebase.FirebaseOptions -import dev.gitlive.firebase.apps -import dev.gitlive.firebase.decode -import dev.gitlive.firebase.encode -import dev.gitlive.firebase.initialize -import dev.gitlive.firebase.withSerializer +import dev.gitlive.firebase.* import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async @@ -25,17 +18,10 @@ import kotlinx.serialization.builtins.ListSerializer import kotlinx.serialization.builtins.nullable import kotlinx.serialization.builtins.serializer import kotlin.random.Random -import kotlin.test.BeforeTest -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertNotEquals -import kotlin.test.assertNotNull -import kotlin.test.assertNull -import kotlin.test.assertTrue +import kotlin.test.* expect val emulatorHost: String expect val context: Any -expect fun runTest(test: suspend CoroutineScope.() -> Unit): TestResult /** @return a map extracted from the encoded data. */ expect fun encodedAsMap(encoded: Any?): Map @@ -60,30 +46,39 @@ class FirebaseFirestoreTest { val time: BaseTimestamp? ) + lateinit var firestore: FirebaseFirestore + @BeforeTest fun initializeFirebase() { - Firebase - .takeIf { Firebase.apps(context).isEmpty() } - ?.apply { - initialize( - context, - FirebaseOptions( - applicationId = "1:846484016111:ios:dd1f6688bad7af768c841a", - apiKey = "AIzaSyCK87dcMFhzCz_kJVs2cT2AVlqOTLuyWV0", - databaseUrl = "https://fir-kotlin-sdk.firebaseio.com", - storageBucket = "fir-kotlin-sdk.appspot.com", - projectId = "fir-kotlin-sdk", - gcmSenderId = "846484016111" - ) - ) - Firebase.firestore.useEmulator(emulatorHost, 8080) - } + val app = Firebase.apps(context).firstOrNull() ?: Firebase.initialize( + context, + FirebaseOptions( + applicationId = "1:846484016111:ios:dd1f6688bad7af768c841a", + apiKey = "AIzaSyCK87dcMFhzCz_kJVs2cT2AVlqOTLuyWV0", + databaseUrl = "https://fir-kotlin-sdk.firebaseio.com", + storageBucket = "fir-kotlin-sdk.appspot.com", + projectId = "fir-kotlin-sdk", + gcmSenderId = "846484016111" + ) + ) + + firestore = Firebase.firestore(app).apply { + useEmulator(emulatorHost, 8080) + setSettings(FirebaseFirestore.Settings.create(cacheSettings = LocalCacheSettings.Memory(LocalCacheSettings.Memory.GarbageCollectorSettings.Eager))) + } + } + + @AfterTest + fun deinitializeFirebase() = runBlockingTest { + Firebase.apps(context).forEach { + it.delete() + } } @Test fun testStringOrderBy() = runTest { setupFirestoreData() - val resultDocs = Firebase.firestore + val resultDocs = firestore .collection("testFirestoreQuerying") .orderBy("prop1") .get() @@ -98,7 +93,7 @@ class FirebaseFirestoreTest { fun testFieldOrderBy() = runTest { setupFirestoreData() - val resultDocs = Firebase.firestore.collection("testFirestoreQuerying") + val resultDocs = firestore.collection("testFirestoreQuerying") .orderBy(FieldPath("prop1")).get().documents assertEquals(3, resultDocs.size) assertEquals("aaa", resultDocs[0].get("prop1")) @@ -110,7 +105,7 @@ class FirebaseFirestoreTest { fun testStringOrderByAscending() = runTest { setupFirestoreData() - val resultDocs = Firebase.firestore.collection("testFirestoreQuerying") + val resultDocs = firestore.collection("testFirestoreQuerying") .orderBy("prop1", Direction.ASCENDING).get().documents assertEquals(3, resultDocs.size) assertEquals("aaa", resultDocs[0].get("prop1")) @@ -122,7 +117,7 @@ class FirebaseFirestoreTest { fun testFieldOrderByAscending() = runTest { setupFirestoreData() - val resultDocs = Firebase.firestore.collection("testFirestoreQuerying") + val resultDocs = firestore.collection("testFirestoreQuerying") .orderBy(FieldPath("prop1"), Direction.ASCENDING).get().documents assertEquals(3, resultDocs.size) assertEquals("aaa", resultDocs[0].get("prop1")) @@ -134,7 +129,7 @@ class FirebaseFirestoreTest { fun testStringOrderByDescending() = runTest { setupFirestoreData() - val resultDocs = Firebase.firestore.collection("testFirestoreQuerying") + val resultDocs = firestore.collection("testFirestoreQuerying") .orderBy("prop1", Direction.DESCENDING).get().documents assertEquals(3, resultDocs.size) assertEquals("ccc", resultDocs[0].get("prop1")) @@ -146,7 +141,7 @@ class FirebaseFirestoreTest { fun testFieldOrderByDescending() = runTest { setupFirestoreData() - val resultDocs = Firebase.firestore.collection("testFirestoreQuerying") + val resultDocs = firestore.collection("testFirestoreQuerying") .orderBy(FieldPath("prop1"), Direction.DESCENDING).get().documents assertEquals(3, resultDocs.size) assertEquals("ccc", resultDocs[0].get("prop1")) @@ -156,7 +151,7 @@ class FirebaseFirestoreTest { @Test fun testServerTimestampFieldValue() = runTest { - val doc = Firebase.firestore + val doc = firestore .collection("testServerTimestampFieldValue") .document("test") doc.set( @@ -173,7 +168,7 @@ class FirebaseFirestoreTest { @Test fun testServerTimestampBehaviorNone() = runTest { - val doc = Firebase.firestore + val doc = firestore .collection("testServerTimestampBehaviorNone") .document("test${Random.nextInt()}") @@ -194,10 +189,10 @@ class FirebaseFirestoreTest { @Test fun testExtendedSetBatch() = runTest { - val doc = Firebase.firestore + val doc = firestore .collection("testServerTestSetBatch") .document("test") - val batch = Firebase.firestore.batch() + val batch = firestore.batch() batch.set( documentRef = doc, strategy = FirestoreTest.serializer(), @@ -218,7 +213,7 @@ class FirebaseFirestoreTest { @Test fun testServerTimestampBehaviorEstimate() = runTest { - val doc = Firebase.firestore + val doc = firestore .collection("testServerTimestampBehaviorEstimate") .document("test${Random.nextInt()}") @@ -237,7 +232,7 @@ class FirebaseFirestoreTest { @Test fun testServerTimestampBehaviorPrevious() = runTest { - val doc = Firebase.firestore + val doc = firestore .collection("testServerTimestampBehaviorPrevious") .document("test${Random.nextInt()}") @@ -255,13 +250,13 @@ class FirebaseFirestoreTest { @Test fun testDocumentAutoId() = runTest { - val doc = Firebase.firestore + val doc = firestore .collection("testDocumentAutoId") .document doc.set(FirestoreTest.serializer(), FirestoreTest("AutoId")) - val resultDoc = Firebase.firestore + val resultDoc = firestore .collection("testDocumentAutoId") .document(doc.id) .get() @@ -273,7 +268,7 @@ class FirebaseFirestoreTest { @Test fun testStartAfterDocumentSnapshot() = runTest { setupFirestoreData() - val query = Firebase.firestore + val query = firestore .collection("testFirestoreQuerying") .orderBy("prop1", Direction.ASCENDING) @@ -293,7 +288,7 @@ class FirebaseFirestoreTest { @Test fun testStartAfterFieldValues() = runTest { setupFirestoreData() - val query = Firebase.firestore + val query = firestore .collection("testFirestoreQuerying") .orderBy("prop1", Direction.ASCENDING) @@ -311,7 +306,7 @@ class FirebaseFirestoreTest { @Test fun testStartAtDocumentSnapshot() = runTest { setupFirestoreData() - val query = Firebase.firestore + val query = firestore .collection("testFirestoreQuerying") .orderBy("prop1", Direction.ASCENDING) @@ -332,7 +327,7 @@ class FirebaseFirestoreTest { @Test fun testStartAtFieldValues() = runTest { setupFirestoreData() - val query = Firebase.firestore + val query = firestore .collection("testFirestoreQuerying") .orderBy("prop1", Direction.ASCENDING) @@ -351,7 +346,7 @@ class FirebaseFirestoreTest { @Test fun testEndBeforeDocumentSnapshot() = runTest { setupFirestoreData() - val query = Firebase.firestore + val query = firestore .collection("testFirestoreQuerying") .orderBy("prop1", Direction.ASCENDING) @@ -371,7 +366,7 @@ class FirebaseFirestoreTest { @Test fun testEndBeforeFieldValues() = runTest { setupFirestoreData() - val query = Firebase.firestore + val query = firestore .collection("testFirestoreQuerying") .orderBy("prop1", Direction.ASCENDING) @@ -389,7 +384,7 @@ class FirebaseFirestoreTest { @Test fun testEndAtDocumentSnapshot() = runTest { setupFirestoreData() - val query = Firebase.firestore + val query = firestore .collection("testFirestoreQuerying") .orderBy("prop1", Direction.ASCENDING) @@ -410,7 +405,7 @@ class FirebaseFirestoreTest { @Test fun testEndAtFieldValues() = runTest { setupFirestoreData() - val query = Firebase.firestore + val query = firestore .collection("testFirestoreQuerying") .orderBy("prop1", Direction.ASCENDING) @@ -428,7 +423,7 @@ class FirebaseFirestoreTest { @Test fun testIncrementFieldValue() = runTest { - val doc = Firebase.firestore + val doc = firestore .collection("testFirestoreIncrementFieldValue") .document("test1") @@ -443,7 +438,7 @@ class FirebaseFirestoreTest { @Test fun testArrayUnion() = runTest { - val doc = Firebase.firestore + val doc = firestore .collection("testFirestoreArrayUnion") .document("test1") @@ -458,7 +453,7 @@ class FirebaseFirestoreTest { @Test fun testArrayRemove() = runTest { - val doc = Firebase.firestore + val doc = firestore .collection("testFirestoreArrayRemove") .document("test1") @@ -479,7 +474,7 @@ class FirebaseFirestoreTest { val time: Double? ) - val doc = Firebase.firestore + val doc = firestore .collection("testLegacyDoubleTimestamp") .document("test${Random.nextInt()}") @@ -498,10 +493,10 @@ class FirebaseFirestoreTest { @Test fun testSetBatchDoesNotEncodeEmptyValues() = runTest { - val doc = Firebase.firestore + val doc = firestore .collection("testServerTestSetBatch") .document("test") - val batch = Firebase.firestore.batch() + val batch = firestore.batch() batch.set( documentRef = doc, strategy = FirestoreTest.serializer(), @@ -519,7 +514,7 @@ class FirebaseFirestoreTest { @Test fun testExtendedUpdateBatch() = runTest { - val doc = Firebase.firestore + val doc = firestore .collection("testServerTestSetBatch") .document("test").apply { set( @@ -531,7 +526,7 @@ class FirebaseFirestoreTest { } - val batch = Firebase.firestore.batch() + val batch = firestore.batch() batch.update( documentRef = doc, strategy = FirestoreTest.serializer(), @@ -552,7 +547,7 @@ class FirebaseFirestoreTest { @Test fun testUpdateBatchDoesNotEncodeEmptyValues() = runTest { - val doc = Firebase.firestore + val doc = firestore .collection("testServerTestSetBatch") .document("test").apply { set( @@ -562,7 +557,7 @@ class FirebaseFirestoreTest { ) ) } - val batch = Firebase.firestore.batch() + val batch = firestore.batch() batch.update( documentRef = doc, strategy = FirestoreTest.serializer(), @@ -593,7 +588,7 @@ class FirebaseFirestoreTest { val time: Timestamp ) - val doc = Firebase.firestore + val doc = firestore .collection("testLegacyDoubleTimestampEncodeDecode") .document("testLegacy") @@ -612,7 +607,7 @@ class FirebaseFirestoreTest { val time: Timestamp ) - val collection = Firebase.firestore + val collection = firestore .collection("testQueryByTimestamp") val timestamp = Timestamp.fromMilliseconds(1693262549000.0) @@ -639,13 +634,13 @@ class FirebaseFirestoreTest { } private suspend fun setupFirestoreData() { - Firebase.firestore.collection("testFirestoreQuerying") + firestore.collection("testFirestoreQuerying") .document("one") .set(FirestoreTest.serializer(), FirestoreTest("aaa")) - Firebase.firestore.collection("testFirestoreQuerying") + firestore.collection("testFirestoreQuerying") .document("two") .set(FirestoreTest.serializer(), FirestoreTest("bbb")) - Firebase.firestore.collection("testFirestoreQuerying") + firestore.collection("testFirestoreQuerying") .document("three") .set(FirestoreTest.serializer(), FirestoreTest("ccc")) } @@ -660,7 +655,7 @@ class FirebaseFirestoreTest { @Serializable data class DataWithGeoPoint(val geoPoint: GeoPoint) - fun getDocument() = Firebase.firestore.collection("geoPointSerialization") + fun getDocument() = firestore.collection("geoPointSerialization") .document("geoPointSerialization") val data = DataWithGeoPoint(GeoPoint(12.34, 56.78)) @@ -685,7 +680,7 @@ class FirebaseFirestoreTest { val documentReference: DocumentReference ) - fun getCollection() = Firebase.firestore.collection("documentReferenceSerialization") + fun getCollection() = firestore.collection("documentReferenceSerialization") fun getDocument() = getCollection() .document("documentReferenceSerialization") val documentRef1 = getCollection().document("refDoc1").apply { @@ -726,7 +721,7 @@ class FirebaseFirestoreTest { @Test fun encodeDocumentReference() = runTest { - val doc = Firebase.firestore.document("a/b") + val doc = firestore.document("a/b") val item = TestDataWithDocumentReference("123", doc, doc) val encoded = encodedAsMap(encode(item, shouldEncodeElementDefault = false)) assertEquals("123", encoded["uid"]) @@ -743,7 +738,7 @@ class FirebaseFirestoreTest { @Test fun decodeDocumentReference() = runTest { - val doc = Firebase.firestore.document("a/b") + val doc = firestore.document("a/b") val obj = mapOf( "uid" to "123", "reference" to doc.nativeValue, @@ -766,7 +761,7 @@ class FirebaseFirestoreTest { fun testFieldValuesOps() = runTest { @Serializable data class TestData(val values: List) - fun getDocument() = Firebase.firestore.collection("fieldValuesOps") + fun getDocument() = firestore.collection("fieldValuesOps") .document("fieldValuesOps") val data = TestData(listOf(1)) diff --git a/firebase-firestore/src/iosMain/kotlin/dev/gitlive/firebase/firestore/_encoders.kt b/firebase-firestore/src/iosMain/kotlin/dev/gitlive/firebase/firestore/_encoders.kt index 68f1a2ab9..7dc8c4587 100644 --- a/firebase-firestore/src/iosMain/kotlin/dev/gitlive/firebase/firestore/_encoders.kt +++ b/firebase-firestore/src/iosMain/kotlin/dev/gitlive/firebase/firestore/_encoders.kt @@ -2,7 +2,8 @@ package dev.gitlive.firebase.firestore import cocoapods.FirebaseFirestore.FIRFieldValue -actual fun isSpecialValue(value: Any) = when(value) { +@PublishedApi +internal actual fun isSpecialValue(value: Any) = when(value) { is FIRFieldValue, is NativeGeoPoint, is NativeTimestamp, diff --git a/firebase-firestore/src/iosTest/kotlin/dev/gitlive/firebase/firestore/ContextSwitchTest.kt b/firebase-firestore/src/iosTest/kotlin/dev/gitlive/firebase/firestore/ContextSwitchTest.kt index 7a476ddb4..44ba19486 100644 --- a/firebase-firestore/src/iosTest/kotlin/dev/gitlive/firebase/firestore/ContextSwitchTest.kt +++ b/firebase-firestore/src/iosTest/kotlin/dev/gitlive/firebase/firestore/ContextSwitchTest.kt @@ -1,10 +1,6 @@ package dev.gitlive.firebase.firestore -import dev.gitlive.firebase.EncodeSettings -import dev.gitlive.firebase.Firebase -import dev.gitlive.firebase.FirebaseOptions -import dev.gitlive.firebase.apps -import dev.gitlive.firebase.initialize +import dev.gitlive.firebase.* import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.MainScope import kotlinx.coroutines.async @@ -21,6 +17,7 @@ import platform.Foundation.NSDefaultRunLoopMode import platform.Foundation.NSRunLoop import platform.Foundation.create import platform.Foundation.runMode +import kotlin.test.AfterTest import kotlin.test.BeforeTest import kotlin.test.Test import kotlin.test.assertEquals @@ -56,26 +53,34 @@ fun runTestWithContextSwitch(create: suspend CoroutineScope.() -> T, test: s class ContextSwitchTest { + + lateinit var firestore: FirebaseFirestore + @BeforeTest fun initializeFirebase() { - Firebase - .takeIf { Firebase.apps(context).isEmpty() } - ?.apply { - initialize( - context, - FirebaseOptions( - applicationId = "1:846484016111:ios:dd1f6688bad7af768c841a", - apiKey = "AIzaSyCK87dcMFhzCz_kJVs2cT2AVlqOTLuyWV0", - databaseUrl = "https://fir-kotlin-sdk.firebaseio.com", - storageBucket = "fir-kotlin-sdk.appspot.com", - projectId = "fir-kotlin-sdk", - gcmSenderId = "846484016111" - ) - ) - Firebase.firestore.useEmulator(emulatorHost, 8080) - } + val app = Firebase.apps(context).firstOrNull() ?: Firebase.initialize( + context, + FirebaseOptions( + applicationId = "1:846484016111:ios:dd1f6688bad7af768c841a", + apiKey = "AIzaSyCK87dcMFhzCz_kJVs2cT2AVlqOTLuyWV0", + databaseUrl = "https://fir-kotlin-sdk.firebaseio.com", + storageBucket = "fir-kotlin-sdk.appspot.com", + projectId = "fir-kotlin-sdk", + gcmSenderId = "846484016111" + ) + ) + + firestore = Firebase.firestore(app).apply { + useEmulator(emulatorHost, 8080) + } } + @AfterTest + fun deinitializeFirebase() = runBlockingTest { + Firebase.apps(context).forEach { + it.delete() + } + } private data class TestFieldValuesOps( val initial: List, @@ -113,7 +118,7 @@ class ContextSwitchTest { } ) { data -> - fun getDocument() = Firebase.firestore.collection("fieldValuesOps") + fun getDocument() = firestore.collection("fieldValuesOps") .document("fieldValuesOps") // store diff --git a/firebase-firestore/src/iosTest/kotlin/dev/gitlive/firebase/firestore/firestore.kt b/firebase-firestore/src/iosTest/kotlin/dev/gitlive/firebase/firestore/firestore.kt index 5bfb1ecd7..3f54909b5 100644 --- a/firebase-firestore/src/iosTest/kotlin/dev/gitlive/firebase/firestore/firestore.kt +++ b/firebase-firestore/src/iosTest/kotlin/dev/gitlive/firebase/firestore/firestore.kt @@ -4,26 +4,10 @@ package dev.gitlive.firebase.firestore -import dev.gitlive.firebase.* -import kotlinx.coroutines.* -import platform.Foundation.* - actual val emulatorHost: String = "localhost" actual val context: Any = Unit -actual fun runTest(test: suspend CoroutineScope.() -> Unit) = runBlocking { - val testRun = MainScope().async { test() } - while (testRun.isActive) { - NSRunLoop.mainRunLoop.runMode( - NSDefaultRunLoopMode, - beforeDate = NSDate.create(timeInterval = 1.0, sinceDate = NSDate()) - ) - yield() - } - testRun.await() -} - @Suppress("UNCHECKED_CAST") actual fun encodedAsMap(encoded: Any?): Map = encoded as Map actual fun Map.asEncoded(): Any = this diff --git a/firebase-firestore/src/jsMain/kotlin/dev/gitlive/firebase/firestore/_encoders.kt b/firebase-firestore/src/jsMain/kotlin/dev/gitlive/firebase/firestore/_encoders.kt index f191ea2d1..485920fe2 100644 --- a/firebase-firestore/src/jsMain/kotlin/dev/gitlive/firebase/firestore/_encoders.kt +++ b/firebase-firestore/src/jsMain/kotlin/dev/gitlive/firebase/firestore/_encoders.kt @@ -1,6 +1,7 @@ package dev.gitlive.firebase.firestore -actual fun isSpecialValue(value: Any) = when(value) { +@PublishedApi +internal actual fun isSpecialValue(value: Any) = when(value) { is NativeFieldValue, is NativeGeoPoint, is NativeTimestamp, diff --git a/firebase-firestore/src/jsTest/kotlin/dev/gitlive/firebase/firestore/firestore.kt b/firebase-firestore/src/jsTest/kotlin/dev/gitlive/firebase/firestore/firestore.kt index 91fb960f4..17006e809 100644 --- a/firebase-firestore/src/jsTest/kotlin/dev/gitlive/firebase/firestore/firestore.kt +++ b/firebase-firestore/src/jsTest/kotlin/dev/gitlive/firebase/firestore/firestore.kt @@ -4,17 +4,12 @@ package dev.gitlive.firebase.firestore -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.test.runTest import kotlin.js.json -import kotlin.time.Duration.Companion.minutes actual val emulatorHost: String = "localhost" actual val context: Any = Unit -actual fun runTest(test: suspend CoroutineScope.() -> Unit) = runTest(timeout = 5.minutes) { test() } - actual fun encodedAsMap(encoded: Any?): Map { return (js("Object").entries(encoded) as Array>).associate { it[0] as String to it[1] diff --git a/firebase-firestore/src/jvmMain/kotlin/dev/gitlive/firebase/firestore/_encoders.kt b/firebase-firestore/src/jvmMain/kotlin/dev/gitlive/firebase/firestore/_encoders.kt index 1c6be4a86..d12bda859 100644 --- a/firebase-firestore/src/jvmMain/kotlin/dev/gitlive/firebase/firestore/_encoders.kt +++ b/firebase-firestore/src/jvmMain/kotlin/dev/gitlive/firebase/firestore/_encoders.kt @@ -1,6 +1,7 @@ package dev.gitlive.firebase.firestore -actual fun isSpecialValue(value: Any) = when(value) { +@PublishedApi +internal actual fun isSpecialValue(value: Any) = when(value) { is NativeFieldValue, is NativeGeoPoint, is NativeTimestamp, diff --git a/firebase-firestore/src/jvmTest/kotlin/dev/gitlive/firebase/firestore/firestore.kt b/firebase-firestore/src/jvmTest/kotlin/dev/gitlive/firebase/firestore/firestore.kt index 6de57fcef..984b90e2b 100644 --- a/firebase-firestore/src/jvmTest/kotlin/dev/gitlive/firebase/firestore/firestore.kt +++ b/firebase-firestore/src/jvmTest/kotlin/dev/gitlive/firebase/firestore/firestore.kt @@ -5,14 +5,10 @@ @file:JvmName("tests") package dev.gitlive.firebase.firestore -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.runBlocking - actual val emulatorHost: String = "10.0.2.2" actual val context: Any = Unit -actual fun runTest(test: suspend CoroutineScope.() -> Unit) = runBlocking { test() } @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) actual annotation class IgnoreJs @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) diff --git a/firebase-functions/build.gradle.kts b/firebase-functions/build.gradle.kts index 3d4902db9..5b0ba1531 100644 --- a/firebase-functions/build.gradle.kts +++ b/firebase-functions/build.gradle.kts @@ -1,3 +1,5 @@ +import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSetTree + /* * Copyright (c) 2020 GitLive Ltd. Use of this source code is governed by the Apache 2.0 license. */ @@ -46,7 +48,16 @@ val supportIosTarget = project.property("skipIosTarget") != "true" kotlin { + targets.configureEach { + compilations.configureEach { + kotlinOptions.freeCompilerArgs += "-Xexpect-actual-classes" + } + } + + @Suppress("OPT_IN_USAGE") androidTarget { + instrumentedTestVariant.sourceSetTree.set(KotlinSourceSetTree.test) + unitTestVariant.sourceSetTree.set(KotlinSourceSetTree.test) publishAllLibraryVariants() compilations.configureEach { kotlinOptions { @@ -56,7 +67,8 @@ kotlin { } if (supportIosTarget) { - ios() + iosArm64() + iosX64() iosSimulatorArm64() cocoapods { ios.deploymentTarget = "11.0" @@ -66,6 +78,7 @@ kotlin { noPodspec() pod("FirebaseFunctions") { version = "10.15.0" + extraOpts += listOf("-compiler-option", "-fmodules") } } } @@ -110,6 +123,9 @@ kotlin { progressiveMode = true optIn("kotlinx.coroutines.ExperimentalCoroutinesApi") optIn("kotlinx.serialization.InternalSerializationApi") + if (name.lowercase().contains("ios")) { + optIn("kotlinx.cinterop.ExperimentalForeignApi") + } } } @@ -120,7 +136,7 @@ kotlin { } } - val commonTest by getting { + getByName("commonTest") { dependencies { implementation(project(":test-utils")) } @@ -132,24 +148,9 @@ kotlin { } } - getByName("androidInstrumentedTest") { - dependencies { - dependsOn(commonTest) - } - } - getByName("jvmMain") { kotlin.srcDir("src/androidMain/kotlin") } - - if (supportIosTarget) { - val iosMain by getting - val iosSimulatorArm64Main by getting - iosSimulatorArm64Main.dependsOn(iosMain) - val iosTest by sourceSets.getting - val iosSimulatorArm64Test by getting - iosSimulatorArm64Test.dependsOn(iosTest) - } } } diff --git a/firebase-functions/package.json b/firebase-functions/package.json index 890545f0c..c18b774e4 100644 --- a/firebase-functions/package.json +++ b/firebase-functions/package.json @@ -1,6 +1,6 @@ { "name": "@gitlive/firebase-functions", - "version": "1.10.1-SNAPSHOT", + "version": "1.10.4", "description": "Wrapper around firebase for usage in Kotlin Multiplatform projects", "main": "firebase-functions.js", "scripts": { @@ -23,7 +23,7 @@ }, "homepage": "https://github.com/GitLiveApp/firebase-kotlin-sdk", "dependencies": { - "@gitlive/firebase-app": "1.10.1-SNAPSHOT", + "@gitlive/firebase-app": "1.10.4", "firebase": "9.19.1", "kotlin": "1.8.20", "kotlinx-coroutines-core": "1.6.4" diff --git a/firebase-functions/src/androidMain/kotlin/dev/gitlive/firebase/functions/functions.kt b/firebase-functions/src/androidMain/kotlin/dev/gitlive/firebase/functions/functions.kt index 94bcdd94b..5c744950a 100644 --- a/firebase-functions/src/androidMain/kotlin/dev/gitlive/firebase/functions/functions.kt +++ b/firebase-functions/src/androidMain/kotlin/dev/gitlive/firebase/functions/functions.kt @@ -49,3 +49,10 @@ actual class HttpsCallableResult constructor(val android: com.google.firebase.fu } actual typealias FirebaseFunctionsException = com.google.firebase.functions.FirebaseFunctionsException + +actual val FirebaseFunctionsException.code: FunctionsExceptionCode get() = code + +actual val FirebaseFunctionsException.details: Any? get() = details + +actual typealias FunctionsExceptionCode = com.google.firebase.functions.FirebaseFunctionsException.Code + diff --git a/firebase-functions/src/commonMain/kotlin/dev/gitlive/firebase/functions/functions.kt b/firebase-functions/src/commonMain/kotlin/dev/gitlive/firebase/functions/functions.kt index ffa6770e0..edb57bed3 100644 --- a/firebase-functions/src/commonMain/kotlin/dev/gitlive/firebase/functions/functions.kt +++ b/firebase-functions/src/commonMain/kotlin/dev/gitlive/firebase/functions/functions.kt @@ -46,3 +46,29 @@ expect fun Firebase.functions(app: FirebaseApp): FirebaseFunctions expect fun Firebase.functions(app: FirebaseApp, region: String): FirebaseFunctions expect class FirebaseFunctionsException: FirebaseException + +@Suppress("EXTENSION_SHADOWED_BY_MEMBER") +expect val FirebaseFunctionsException.code: FunctionsExceptionCode + +@Suppress("EXTENSION_SHADOWED_BY_MEMBER") +expect val FirebaseFunctionsException.details: Any? + +expect enum class FunctionsExceptionCode { + OK, + CANCELLED, + UNKNOWN, + INVALID_ARGUMENT, + DEADLINE_EXCEEDED, + NOT_FOUND, + ALREADY_EXISTS, + PERMISSION_DENIED, + RESOURCE_EXHAUSTED, + FAILED_PRECONDITION, + ABORTED, + OUT_OF_RANGE, + UNIMPLEMENTED, + INTERNAL, + UNAVAILABLE, + DATA_LOSS, + UNAUTHENTICATED +} diff --git a/firebase-functions/src/iosMain/kotlin/dev/gitlive/firebase/functions/functions.kt b/firebase-functions/src/iosMain/kotlin/dev/gitlive/firebase/functions/functions.kt index f8bde60cd..7184e4836 100644 --- a/firebase-functions/src/iosMain/kotlin/dev/gitlive/firebase/functions/functions.kt +++ b/firebase-functions/src/iosMain/kotlin/dev/gitlive/firebase/functions/functions.kt @@ -4,18 +4,14 @@ package dev.gitlive.firebase.functions -import cocoapods.FirebaseFunctions.* -import dev.gitlive.firebase.DecodeSettings -import dev.gitlive.firebase.EncodeSettings -import dev.gitlive.firebase.Firebase -import dev.gitlive.firebase.FirebaseApp -import dev.gitlive.firebase.FirebaseException -import dev.gitlive.firebase.decode -import dev.gitlive.firebase.encode +import cocoapods.FirebaseFunctions.FIRFunctions +import cocoapods.FirebaseFunctions.FIRHTTPSCallable +import cocoapods.FirebaseFunctions.FIRHTTPSCallableResult +import dev.gitlive.firebase.* import kotlinx.coroutines.CompletableDeferred import kotlinx.serialization.DeserializationStrategy import kotlinx.serialization.SerializationStrategy -import platform.Foundation.* +import platform.Foundation.NSError actual val Firebase.functions get() = FirebaseFunctions(FIRFunctions.functions()) @@ -58,7 +54,55 @@ actual class HttpsCallableResult constructor(val ios: FIRHTTPSCallableResult) { decode(strategy, ios.data(), decodeSettings) } -actual class FirebaseFunctionsException(message: String): FirebaseException(message) +actual class FirebaseFunctionsException(message: String, val code: FunctionsExceptionCode, val details: Any?) : FirebaseException(message) + +actual val FirebaseFunctionsException.code: FunctionsExceptionCode get() = code + +actual val FirebaseFunctionsException.details: Any? get() = details + +actual enum class FunctionsExceptionCode { + OK, + CANCELLED, + UNKNOWN, + INVALID_ARGUMENT, + DEADLINE_EXCEEDED, + NOT_FOUND, + ALREADY_EXISTS, + PERMISSION_DENIED, + RESOURCE_EXHAUSTED, + FAILED_PRECONDITION, + ABORTED, + OUT_OF_RANGE, + UNIMPLEMENTED, + INTERNAL, + UNAVAILABLE, + DATA_LOSS, + UNAUTHENTICATED +} +//todo uncomment once https://github.com/firebase/firebase-ios-sdk/issues/11862 fixed +fun NSError.toException() = when(domain) { +// FIRFunctionsErrorDomain -> when(code) { +// FIRFunctionsErrorCodeOK -> FunctionsExceptionCode.OK +// FIRFunctionsErrorCodeCancelled -> FunctionsExceptionCode.CANCELLED +// FIRFunctionsErrorCodeUnknown -> FunctionsExceptionCode.UNKNOWN +// FIRFunctionsErrorCodeInvalidArgument -> FunctionsExceptionCode.INVALID_ARGUMENT +// FIRFunctionsErrorCodeDeadlineExceeded -> FunctionsExceptionCode.DEADLINE_EXCEEDED +// FIRFunctionsErrorCodeNotFound -> FunctionsExceptionCode.NOT_FOUND +// FIRFunctionsErrorCodeAlreadyExists -> FunctionsExceptionCode.ALREADY_EXISTS +// FIRFunctionsErrorCodePermissionDenied -> FunctionsExceptionCode.PERMISSION_DENIED +// FIRFunctionsErrorCodeResourceExhausted -> FunctionsExceptionCode.RESOURCE_EXHAUSTED +// FIRFunctionsErrorCodeFailedPrecondition -> FunctionsExceptionCode.FAILED_PRECONDITION +// FIRFunctionsErrorCodeAborted -> FunctionsExceptionCode.ABORTED +// FIRFunctionsErrorCodeOutOfRange -> FunctionsExceptionCode.OUT_OF_RANGE +// FIRFunctionsErrorCodeUnimplemented -> FunctionsExceptionCode.UNIMPLEMENTED +// FIRFunctionsErrorCodeInternal -> FunctionsExceptionCode.INTERNAL +// FIRFunctionsErrorCodeUnavailable -> FunctionsExceptionCode.UNAVAILABLE +// FIRFunctionsErrorCodeDataLoss -> FunctionsExceptionCode.DATA_LOSS +// FIRFunctionsErrorCodeUnauthenticated -> FunctionsExceptionCode.UNAUTHENTICATED +// else -> FunctionsExceptionCode.UNKNOWN +// } + else -> FunctionsExceptionCode.UNKNOWN +}.let { FirebaseFunctionsException(description!!, it, null/*userInfo[FIRFunctionsErrorDetails]*/) } suspend inline fun T.await(function: T.(callback: (NSError?) -> Unit) -> Unit) { val job = CompletableDeferred() @@ -66,7 +110,7 @@ suspend inline fun T.await(function: T.(callback: (NSError?) -> Unit) -> Uni if(error == null) { job.complete(Unit) } else { - job.completeExceptionally(FirebaseFunctionsException(error.localizedDescription)) + job.completeExceptionally(error.toException()) } } function(callback) @@ -79,7 +123,7 @@ suspend inline fun T.awaitResult(function: T.(callback: (R?, NSEr if(error == null) { job.complete(result) } else { - job.completeExceptionally(FirebaseFunctionsException(error.localizedDescription)) + job.completeExceptionally(error.toException()) } } function(callback) diff --git a/firebase-functions/src/jsMain/kotlin/dev/gitlive/firebase/functions/functions.kt b/firebase-functions/src/jsMain/kotlin/dev/gitlive/firebase/functions/functions.kt index 75f80d3a1..4db0c0284 100644 --- a/firebase-functions/src/jsMain/kotlin/dev/gitlive/firebase/functions/functions.kt +++ b/firebase-functions/src/jsMain/kotlin/dev/gitlive/firebase/functions/functions.kt @@ -9,7 +9,6 @@ import dev.gitlive.firebase.functions.externals.* import kotlinx.coroutines.await import kotlinx.serialization.DeserializationStrategy import kotlinx.serialization.SerializationStrategy -import org.w3c.dom.url.URL import kotlin.js.json import dev.gitlive.firebase.functions.externals.HttpsCallableResult as JsHttpsCallableResult @@ -53,7 +52,31 @@ actual class HttpsCallableResult constructor(val js: JsHttpsCallableResult) { } -actual open class FirebaseFunctionsException(code: String?, cause: Throwable): FirebaseException(code, cause) +actual class FirebaseFunctionsException(cause: Throwable, val code: FunctionsExceptionCode, val details: Any?) : FirebaseException(cause.message, cause) + +actual val FirebaseFunctionsException.code: FunctionsExceptionCode get() = code + +actual val FirebaseFunctionsException.details: Any? get() = details + +actual enum class FunctionsExceptionCode { + OK, + CANCELLED, + UNKNOWN, + INVALID_ARGUMENT, + DEADLINE_EXCEEDED, + NOT_FOUND, + ALREADY_EXISTS, + PERMISSION_DENIED, + RESOURCE_EXHAUSTED, + FAILED_PRECONDITION, + ABORTED, + OUT_OF_RANGE, + UNIMPLEMENTED, + INTERNAL, + UNAVAILABLE, + DATA_LOSS, + UNAUTHENTICATED +} inline fun T.rethrow(function: T.() -> R): R = dev.gitlive.firebase.functions.rethrow { function() } @@ -63,6 +86,34 @@ inline fun rethrow(function: () -> R): R { } catch (e: Exception) { throw e } catch(e: dynamic) { - throw FirebaseFunctionsException(e.code as String?, e) + throw errorToException(e) } } + +fun errorToException(e: dynamic) = (e?.code ?: e?.message ?: "") + .toString() + .lowercase() + .let { + when { + "cancelled" in it -> FirebaseFunctionsException(e, FunctionsExceptionCode.CANCELLED, e.details) + "invalid-argument" in it -> FirebaseFunctionsException(e, FunctionsExceptionCode.INVALID_ARGUMENT, e.details) + "deadline-exceeded" in it -> FirebaseFunctionsException(e, FunctionsExceptionCode.DEADLINE_EXCEEDED, e.details) + "not-found" in it -> FirebaseFunctionsException(e, FunctionsExceptionCode.NOT_FOUND, e.details) + "already-exists" in it -> FirebaseFunctionsException(e, FunctionsExceptionCode.ALREADY_EXISTS, e.details) + "permission-denied" in it -> FirebaseFunctionsException(e, FunctionsExceptionCode.PERMISSION_DENIED, e.details) + "resource-exhausted" in it -> FirebaseFunctionsException(e, FunctionsExceptionCode.RESOURCE_EXHAUSTED, e.details) + "failed-precondition" in it -> FirebaseFunctionsException(e, FunctionsExceptionCode.FAILED_PRECONDITION, e.details) + "aborted" in it -> FirebaseFunctionsException(e, FunctionsExceptionCode.ABORTED, e.details) + "out-of-range" in it -> FirebaseFunctionsException(e, FunctionsExceptionCode.OUT_OF_RANGE, e.details) + "unimplemented" in it -> FirebaseFunctionsException(e, FunctionsExceptionCode.UNIMPLEMENTED, e.details) + "internal" in it -> FirebaseFunctionsException(e, FunctionsExceptionCode.INTERNAL, e.details) + "unavailable" in it -> FirebaseFunctionsException(e, FunctionsExceptionCode.UNAVAILABLE, e.details) + "data-loss" in it -> FirebaseFunctionsException(e, FunctionsExceptionCode.DATA_LOSS, e.details) + "unauthenticated" in it -> FirebaseFunctionsException(e, FunctionsExceptionCode.UNAUTHENTICATED, e.details) + "unknown" in it -> FirebaseFunctionsException(e, FunctionsExceptionCode.UNKNOWN, e.details) + else -> { + println("Unknown error code in ${JSON.stringify(e)}") + FirebaseFunctionsException(e, FunctionsExceptionCode.UNKNOWN, e.details) + } + } + } diff --git a/firebase-installations/build.gradle.kts b/firebase-installations/build.gradle.kts index 858a4bf9b..f0d5c0cc2 100644 --- a/firebase-installations/build.gradle.kts +++ b/firebase-installations/build.gradle.kts @@ -1,3 +1,5 @@ +import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSetTree + /* * Copyright (c) 2020 GitLive Ltd. Use of this source code is governed by the Apache 2.0 license. */ @@ -46,7 +48,16 @@ val supportIosTarget = project.property("skipIosTarget") != "true" kotlin { + targets.configureEach { + compilations.configureEach { + kotlinOptions.freeCompilerArgs += "-Xexpect-actual-classes" + } + } + + @Suppress("OPT_IN_USAGE") androidTarget { + instrumentedTestVariant.sourceSetTree.set(KotlinSourceSetTree.test) + unitTestVariant.sourceSetTree.set(KotlinSourceSetTree.test) publishAllLibraryVariants() compilations.configureEach { kotlinOptions { @@ -69,7 +80,8 @@ kotlin { } if (supportIosTarget) { - ios() + iosArm64() + iosX64() iosSimulatorArm64() cocoapods { ios.deploymentTarget = "11.0" @@ -113,6 +125,9 @@ kotlin { this.apiVersion = apiVersion this.languageVersion = languageVersion progressiveMode = true + if (name.lowercase().contains("ios")) { + optIn("kotlinx.cinterop.ExperimentalForeignApi") + } } } @@ -123,7 +138,7 @@ kotlin { } } - val commonTest by getting { + getByName("commonTest") { dependencies { implementation(project(":test-utils")) } @@ -135,24 +150,9 @@ kotlin { } } - getByName("androidInstrumentedTest") { - dependencies { - dependsOn(commonTest) - } - } - getByName("jvmMain") { kotlin.srcDir("src/androidMain/kotlin") } - - if (supportIosTarget) { - val iosMain by getting - val iosSimulatorArm64Main by getting - iosSimulatorArm64Main.dependsOn(iosMain) - val iosTest by sourceSets.getting - val iosSimulatorArm64Test by getting - iosSimulatorArm64Test.dependsOn(iosTest) - } } } diff --git a/firebase-installations/package.json b/firebase-installations/package.json index 9f88ce7bd..af5d99226 100644 --- a/firebase-installations/package.json +++ b/firebase-installations/package.json @@ -1,6 +1,6 @@ { "name": "@gitlive/firebase-installations", - "version": "1.10.1-SNAPSHOT", + "version": "1.10.4", "description": "Wrapper around firebase for usage in Kotlin Multiplatform projects", "main": "firebase-installations.js", "scripts": { @@ -23,7 +23,7 @@ }, "homepage": "https://github.com/GitLiveApp/firebase-kotlin-sdk", "dependencies": { - "@gitlive/firebase-app": "1.10.1-SNAPSHOT", + "@gitlive/firebase-app": "1.10.4", "firebase": "9.19.1", "kotlin": "1.8.20", "kotlinx-coroutines-core": "1.6.4" diff --git a/firebase-perf/build.gradle.kts b/firebase-perf/build.gradle.kts index fd57f9bc5..e79a99ded 100644 --- a/firebase-perf/build.gradle.kts +++ b/firebase-perf/build.gradle.kts @@ -1,3 +1,5 @@ +import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSetTree + /* * Copyright (c) 2020 GitLive Ltd. Use of this source code is governed by the Apache 2.0 license. */ @@ -47,7 +49,16 @@ val supportIosTarget = project.property("skipIosTarget") != "true" kotlin { + targets.configureEach { + compilations.configureEach { + kotlinOptions.freeCompilerArgs += "-Xexpect-actual-classes" + } + } + + @Suppress("OPT_IN_USAGE") androidTarget { + instrumentedTestVariant.sourceSetTree.set(KotlinSourceSetTree.test) + unitTestVariant.sourceSetTree.set(KotlinSourceSetTree.test) publishAllLibraryVariants() compilations.configureEach { kotlinOptions { @@ -70,7 +81,8 @@ kotlin { } if (supportIosTarget) { - ios() + iosArm64() + iosX64() iosSimulatorArm64() cocoapods { ios.deploymentTarget = "11.0" @@ -106,6 +118,9 @@ kotlin { this.languageVersion = languageVersion progressiveMode = true optIn("kotlinx.coroutines.ExperimentalCoroutinesApi") + if (name.lowercase().contains("ios")) { + optIn("kotlinx.cinterop.ExperimentalForeignApi") + } } } @@ -116,7 +131,7 @@ kotlin { } } - val commonTest by getting { + getByName("commonTest") { dependencies { implementation(project(":test-utils")) } @@ -128,25 +143,9 @@ kotlin { } } - getByName("androidInstrumentedTest") { - dependencies { - dependsOn(commonTest) - } - } - // getByName("jvmMain") { // kotlin.srcDir("src/androidMain/kotlin") // } - - if (supportIosTarget) { - val iosMain by getting - val iosSimulatorArm64Main by getting - iosSimulatorArm64Main.dependsOn(iosMain) - - val iosTest by sourceSets.getting - val iosSimulatorArm64Test by sourceSets.getting - iosSimulatorArm64Test.dependsOn(iosTest) - } } } diff --git a/firebase-perf/package.json b/firebase-perf/package.json index 3e0f7d632..e53193deb 100644 --- a/firebase-perf/package.json +++ b/firebase-perf/package.json @@ -1,6 +1,6 @@ { "name": "@gitlive/firebase-perf", - "version": "1.10.1-SNAPSHOT", + "version": "1.10.4", "description": "Wrapper around firebase for usage in Kotlin Multiplatform projects", "main": "firebase-perf.js", "scripts": { @@ -23,7 +23,7 @@ }, "homepage": "https://github.com/GitLiveApp/firebase-kotlin-sdk", "dependencies": { - "@gitlive/firebase-app": "1.10.1-SNAPSHOT", + "@gitlive/firebase-app": "1.10.4", "firebase": "9.19.1", "kotlin": "1.6.10", "kotlinx-coroutines-core": "1.6.1-native-mt" diff --git a/firebase-perf/src/androidInstrumentedTest/kotlin/dev/gitlive/firebase/perf/metrics/Trace.kt b/firebase-perf/src/androidInstrumentedTest/kotlin/dev/gitlive/firebase/perf/metrics/Trace.kt index a99532882..a72a9e093 100644 --- a/firebase-perf/src/androidInstrumentedTest/kotlin/dev/gitlive/firebase/perf/metrics/Trace.kt +++ b/firebase-perf/src/androidInstrumentedTest/kotlin/dev/gitlive/firebase/perf/metrics/Trace.kt @@ -1,14 +1,15 @@ package dev.gitlive.firebase.perf.metrics -import dev.gitlive.firebase.Firebase -import dev.gitlive.firebase.FirebaseOptions -import dev.gitlive.firebase.apps -import dev.gitlive.firebase.initialize +import dev.gitlive.firebase.* import dev.gitlive.firebase.perf.FirebasePerformance +import dev.gitlive.firebase.perf.context import dev.gitlive.firebase.perf.performance +import kotlinx.coroutines.delay +import kotlin.test.AfterTest import kotlin.test.BeforeTest import kotlin.test.Test import kotlin.test.assertEquals +import kotlin.time.Duration.Companion.seconds class AndroidTraceTest { @@ -16,29 +17,32 @@ class AndroidTraceTest { @BeforeTest fun initializeFirebase() { - Firebase - .takeIf { Firebase.apps(dev.gitlive.firebase.perf.context).isEmpty() } - ?.apply { - initialize( - dev.gitlive.firebase.perf.context, - FirebaseOptions( - applicationId = "1:846484016111:ios:dd1f6688bad7af768c841a", - apiKey = "AIzaSyCK87dcMFhzCz_kJVs2cT2AVlqOTLuyWV0", - databaseUrl = "https://fir-kotlin-sdk.firebaseio.com", - storageBucket = "fir-kotlin-sdk.appspot.com", - projectId = "fir-kotlin-sdk", - gcmSenderId = "846484016111" - ) - ) - } - - performance = Firebase.performance - + val app = Firebase.apps(context).firstOrNull() ?: Firebase.initialize( + dev.gitlive.firebase.perf.context, + FirebaseOptions( + applicationId = "1:846484016111:ios:dd1f6688bad7af768c841a", + apiKey = "AIzaSyCK87dcMFhzCz_kJVs2cT2AVlqOTLuyWV0", + databaseUrl = "https://fir-kotlin-sdk.firebaseio.com", + storageBucket = "fir-kotlin-sdk.appspot.com", + projectId = "fir-kotlin-sdk", + gcmSenderId = "846484016111" + ) + ) + + performance = Firebase.performance(app) + } + @AfterTest + fun deinitializeFirebase() = runBlockingTest { + // Performance runs installation in the background, which crashes if the app is deleted before completion + delay(5.seconds) + Firebase.apps(context).forEach { + it.delete() + } } @Test - fun testGetAttributes() { + fun testGetAttributes() = runTest { val trace = performance.newTrace("testGetAttributes") trace.start() val values = listOf(1, 2, 3) @@ -60,7 +64,7 @@ class AndroidTraceTest { } @Test - fun testGetAttribute() { + fun testGetAttribute() = runTest { val trace = performance.newTrace("testGetAttribute") trace.start() trace.putAttribute("Test_Get_Attribute", "Test Get Attribute Value") @@ -70,7 +74,7 @@ class AndroidTraceTest { } @Test - fun testPutAttribute() { + fun testPutAttribute() = runTest { val trace = performance.newTrace("testPutAttribute") trace.start() trace.putAttribute("Test_Put_Attribute", "Test Put Attribute Value") diff --git a/firebase-perf/src/androidInstrumentedTest/kotlin/dev/gitlive/firebase/perf/performance.kt b/firebase-perf/src/androidInstrumentedTest/kotlin/dev/gitlive/firebase/perf/performance.kt index 3c7aeaf98..045b947fe 100644 --- a/firebase-perf/src/androidInstrumentedTest/kotlin/dev/gitlive/firebase/perf/performance.kt +++ b/firebase-perf/src/androidInstrumentedTest/kotlin/dev/gitlive/firebase/perf/performance.kt @@ -6,12 +6,10 @@ package dev.gitlive.firebase.perf import androidx.test.platform.app.InstrumentationRegistry -import kotlinx.coroutines.CoroutineScope actual val emulatorHost: String = "10.0.2.2" actual val context: Any = InstrumentationRegistry.getInstrumentation().targetContext -actual fun runTest(test: suspend CoroutineScope.() -> Unit) = kotlinx.coroutines.test.runTest { test() } @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) actual annotation class IgnoreForAndroidUnitTest diff --git a/firebase-perf/src/androidUnitTest/kotlin/dev/gitlive/firebase/perf/performance.kt b/firebase-perf/src/androidUnitTest/kotlin/dev/gitlive/firebase/perf/performance.kt index d0d95632f..f54647241 100644 --- a/firebase-perf/src/androidUnitTest/kotlin/dev/gitlive/firebase/perf/performance.kt +++ b/firebase-perf/src/androidUnitTest/kotlin/dev/gitlive/firebase/perf/performance.kt @@ -1,12 +1,10 @@ @file:JvmName("tests") package dev.gitlive.firebase.perf -import kotlinx.coroutines.CoroutineScope import org.junit.Ignore actual val emulatorHost: String = "10.0.2.2" actual val context: Any = "" -actual fun runTest(test: suspend CoroutineScope.() -> Unit) = kotlinx.coroutines.test.runTest { test() } actual typealias IgnoreForAndroidUnitTest = Ignore diff --git a/firebase-perf/src/commonTest/kotlin/dev/gitlive/firebase/perf/metrics/Trace.kt b/firebase-perf/src/commonTest/kotlin/dev/gitlive/firebase/perf/metrics/Trace.kt index 6fac9d3dd..539f165bc 100644 --- a/firebase-perf/src/commonTest/kotlin/dev/gitlive/firebase/perf/metrics/Trace.kt +++ b/firebase-perf/src/commonTest/kotlin/dev/gitlive/firebase/perf/metrics/Trace.kt @@ -1,15 +1,16 @@ package dev.gitlive.firebase.perf.metrics -import dev.gitlive.firebase.Firebase -import dev.gitlive.firebase.FirebaseOptions -import dev.gitlive.firebase.apps -import dev.gitlive.firebase.initialize +import dev.gitlive.firebase.* import dev.gitlive.firebase.perf.FirebasePerformance import dev.gitlive.firebase.perf.IgnoreForAndroidUnitTest +import dev.gitlive.firebase.perf.context import dev.gitlive.firebase.perf.performance +import kotlinx.coroutines.delay +import kotlin.test.AfterTest import kotlin.test.BeforeTest import kotlin.test.Test import kotlin.test.assertEquals +import kotlin.time.Duration.Companion.seconds @IgnoreForAndroidUnitTest class TraceTest { @@ -18,29 +19,32 @@ class TraceTest { @BeforeTest fun initializeFirebase() { - Firebase - .takeIf { Firebase.apps(dev.gitlive.firebase.perf.context).isEmpty() } - ?.apply { - initialize( - dev.gitlive.firebase.perf.context, - FirebaseOptions( - applicationId = "1:846484016111:ios:dd1f6688bad7af768c841a", - apiKey = "AIzaSyCK87dcMFhzCz_kJVs2cT2AVlqOTLuyWV0", - databaseUrl = "https://fir-kotlin-sdk.firebaseio.com", - storageBucket = "fir-kotlin-sdk.appspot.com", - projectId = "fir-kotlin-sdk", - gcmSenderId = "846484016111" - ) - ) - } - - performance = Firebase.performance + val app = Firebase.apps(context).firstOrNull() ?: Firebase.initialize( + dev.gitlive.firebase.perf.context, + FirebaseOptions( + applicationId = "1:846484016111:ios:dd1f6688bad7af768c841a", + apiKey = "AIzaSyCK87dcMFhzCz_kJVs2cT2AVlqOTLuyWV0", + databaseUrl = "https://fir-kotlin-sdk.firebaseio.com", + storageBucket = "fir-kotlin-sdk.appspot.com", + projectId = "fir-kotlin-sdk", + gcmSenderId = "846484016111" + ) + ) + performance = Firebase.performance(app) + } + @AfterTest + fun deinitializeFirebase() = runBlockingTest { + // Performance runs installation in the background, which crashes if the app is deleted before completion + delay(1.seconds) + Firebase.apps(context).forEach { + it.delete() + } } @Test - fun testGetLongMetric() { + fun testGetLongMetric() = runTest { val trace = performance.newTrace("testGetLongMetric") trace.start() trace.putMetric("Get Long Metric Test", 1L) @@ -50,7 +54,7 @@ class TraceTest { } @Test - fun testIncrementMetric() { + fun testIncrementMetric() = runTest { val trace = performance.newTrace("testIncrementMetric") trace.start() trace.putMetric("Get Increment Metric Test", 1L) @@ -62,7 +66,7 @@ class TraceTest { } @Test - fun testPutMetric() { + fun testPutMetric() = runTest { val trace = performance.newTrace("testPutMetric") trace.start() trace.putMetric("Get Put Metric Test", 1L) diff --git a/firebase-perf/src/commonTest/kotlin/dev/gitlive/firebase/perf/performance.kt b/firebase-perf/src/commonTest/kotlin/dev/gitlive/firebase/perf/performance.kt index 053aefb1d..fae090c5c 100644 --- a/firebase-perf/src/commonTest/kotlin/dev/gitlive/firebase/perf/performance.kt +++ b/firebase-perf/src/commonTest/kotlin/dev/gitlive/firebase/perf/performance.kt @@ -4,46 +4,50 @@ package dev.gitlive.firebase.perf -import dev.gitlive.firebase.Firebase -import dev.gitlive.firebase.FirebaseOptions -import dev.gitlive.firebase.apps -import dev.gitlive.firebase.initialize +import dev.gitlive.firebase.* import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.delay import kotlinx.coroutines.test.TestResult import kotlin.test.* +import kotlin.time.Duration.Companion.seconds expect val emulatorHost: String expect val context: Any -expect fun runTest(test: suspend CoroutineScope.() -> Unit): TestResult expect annotation class IgnoreForAndroidUnitTest() @IgnoreForAndroidUnitTest class FirebasePerformanceTest { + lateinit var performance: FirebasePerformance + @BeforeTest fun initializeFirebase() { - Firebase - .takeIf { Firebase.apps(context).isEmpty() } - ?.apply { - initialize( - context, - FirebaseOptions( - applicationId = "1:846484016111:ios:dd1f6688bad7af768c841a", - apiKey = "AIzaSyCK87dcMFhzCz_kJVs2cT2AVlqOTLuyWV0", - databaseUrl = "https://fir-kotlin-sdk.firebaseio.com", - storageBucket = "fir-kotlin-sdk.appspot.com", - projectId = "fir-kotlin-sdk", - gcmSenderId = "846484016111" - ) - ) - } + val app = Firebase.apps(context).firstOrNull() ?: Firebase.initialize( + context, + FirebaseOptions( + applicationId = "1:846484016111:ios:dd1f6688bad7af768c841a", + apiKey = "AIzaSyCK87dcMFhzCz_kJVs2cT2AVlqOTLuyWV0", + databaseUrl = "https://fir-kotlin-sdk.firebaseio.com", + storageBucket = "fir-kotlin-sdk.appspot.com", + projectId = "fir-kotlin-sdk", + gcmSenderId = "846484016111" + ) + ) + + performance = Firebase.performance(app) + } + + @AfterTest + fun deinitializeFirebase() = runBlockingTest { + // Performance runs installation in the background, which crashes if the app is deleted before completion + delay(5.seconds) + Firebase.apps(context).forEach { + it.delete() + } } @Test fun testNewTrace() = runTest { - - val performance = Firebase.performance - val trace = performance.newTrace("Test Trace") assertNotNull(trace) @@ -51,9 +55,6 @@ class FirebasePerformanceTest { @Test fun testPerformanceCollectionEnabled() = runTest { - - val performance = Firebase.performance - performance.setPerformanceCollectionEnabled(false) assertFalse(performance.isPerformanceCollectionEnabled()) diff --git a/firebase-perf/src/iosTest/kotlin/dev/gitlive/firebase/perf/performance.kt b/firebase-perf/src/iosTest/kotlin/dev/gitlive/firebase/perf/performance.kt index b1814fbf2..67cfa78ac 100644 --- a/firebase-perf/src/iosTest/kotlin/dev/gitlive/firebase/perf/performance.kt +++ b/firebase-perf/src/iosTest/kotlin/dev/gitlive/firebase/perf/performance.kt @@ -4,23 +4,9 @@ package dev.gitlive.firebase.perf -import kotlinx.coroutines.* -import platform.Foundation.* - actual val emulatorHost: String = "localhost" actual val context: Any = Unit -actual fun runTest(test: suspend CoroutineScope.() -> Unit) = runBlocking { - val testRun = MainScope().async { test() } - while (testRun.isActive) { - NSRunLoop.mainRunLoop.runMode( - NSDefaultRunLoopMode, - beforeDate = NSDate.create(timeInterval = 1.0, sinceDate = NSDate()) - ) - yield() - } - testRun.await() -} @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) actual annotation class IgnoreForAndroidUnitTest diff --git a/firebase-perf/src/jsTest/kotlin/dev/gitlive/firebase/perf/metrics/Trace.kt b/firebase-perf/src/jsTest/kotlin/dev/gitlive/firebase/perf/metrics/Trace.kt index dc36d0f7b..319f48a56 100644 --- a/firebase-perf/src/jsTest/kotlin/dev/gitlive/firebase/perf/metrics/Trace.kt +++ b/firebase-perf/src/jsTest/kotlin/dev/gitlive/firebase/perf/metrics/Trace.kt @@ -1,11 +1,10 @@ package dev.gitlive.firebase.perf.metrics -import dev.gitlive.firebase.Firebase -import dev.gitlive.firebase.FirebaseOptions -import dev.gitlive.firebase.apps -import dev.gitlive.firebase.initialize +import dev.gitlive.firebase.* import dev.gitlive.firebase.perf.FirebasePerformance +import dev.gitlive.firebase.perf.context import dev.gitlive.firebase.perf.performance +import kotlin.test.AfterTest import kotlin.test.BeforeTest import kotlin.test.Test import kotlin.test.assertEquals @@ -16,29 +15,30 @@ class JsTraceTest { @BeforeTest fun initializeFirebase() { - Firebase - .takeIf { Firebase.apps(dev.gitlive.firebase.perf.context).isEmpty() } - ?.apply { - initialize( - dev.gitlive.firebase.perf.context, - FirebaseOptions( - applicationId = "1:846484016111:ios:dd1f6688bad7af768c841a", - apiKey = "AIzaSyCK87dcMFhzCz_kJVs2cT2AVlqOTLuyWV0", - databaseUrl = "https://fir-kotlin-sdk.firebaseio.com", - storageBucket = "fir-kotlin-sdk.appspot.com", - projectId = "fir-kotlin-sdk", - gcmSenderId = "846484016111" - ) - ) - } - - performance = Firebase.performance - + val app = Firebase.apps(context).firstOrNull() ?: Firebase.initialize( + context, + FirebaseOptions( + applicationId = "1:846484016111:ios:dd1f6688bad7af768c841a", + apiKey = "AIzaSyCK87dcMFhzCz_kJVs2cT2AVlqOTLuyWV0", + databaseUrl = "https://fir-kotlin-sdk.firebaseio.com", + storageBucket = "fir-kotlin-sdk.appspot.com", + projectId = "fir-kotlin-sdk", + gcmSenderId = "846484016111" + ) + ) + + performance = Firebase.performance(app) + } + @AfterTest + fun deinitializeFirebase() = runBlockingTest { + Firebase.apps(context).forEach { + it.delete() + } } @Test - fun testGetAttribute() { + fun testGetAttribute() = runTest { val trace = performance.newTrace("testGetAttribute") trace.start() trace.putAttribute("Test_Get_Attribute", "Test Get Attribute Value") @@ -48,7 +48,7 @@ class JsTraceTest { } @Test - fun testPutAttribute() { + fun testPutAttribute() = runTest { val trace = performance.newTrace("testPutAttribute") trace.start() trace.putAttribute("Test_Put_Attribute", "Test Put Attribute Value") diff --git a/firebase-perf/src/jsTest/kotlin/dev/gitlive/firebase/perf/performance.kt b/firebase-perf/src/jsTest/kotlin/dev/gitlive/firebase/perf/performance.kt index 1712a7beb..a1b91cdfd 100644 --- a/firebase-perf/src/jsTest/kotlin/dev/gitlive/firebase/perf/performance.kt +++ b/firebase-perf/src/jsTest/kotlin/dev/gitlive/firebase/perf/performance.kt @@ -4,10 +4,7 @@ package dev.gitlive.firebase.perf -import dev.gitlive.firebase.Firebase -import dev.gitlive.firebase.FirebaseOptions -import dev.gitlive.firebase.apps -import dev.gitlive.firebase.initialize +import dev.gitlive.firebase.* import kotlinx.coroutines.CoroutineScope import kotlin.test.* import kotlin.time.Duration.Companion.minutes @@ -16,8 +13,6 @@ actual val emulatorHost: String = "localhost" actual val context: Any = Unit -actual fun runTest(test: suspend CoroutineScope.() -> Unit) = kotlinx.coroutines.test.runTest(timeout = 5.minutes) { test() } - @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) actual annotation class IgnoreForAndroidUnitTest @@ -27,32 +22,23 @@ class JsPerformanceTest { @BeforeTest fun initializeFirebase() { - Firebase - .takeIf { Firebase.apps(context).isEmpty() } - ?.apply { - initialize( - context, - FirebaseOptions( - applicationId = "1:846484016111:ios:dd1f6688bad7af768c841a", - apiKey = "AIzaSyCK87dcMFhzCz_kJVs2cT2AVlqOTLuyWV0", - databaseUrl = "https://fir-kotlin-sdk.firebaseio.com", - storageBucket = "fir-kotlin-sdk.appspot.com", - projectId = "fir-kotlin-sdk", - gcmSenderId = "846484016111" - ) - ) - } - - performance = Firebase.performance - - + val app = Firebase.apps(context).firstOrNull() ?: Firebase.initialize( + context, + FirebaseOptions( + applicationId = "1:846484016111:ios:dd1f6688bad7af768c841a", + apiKey = "AIzaSyCK87dcMFhzCz_kJVs2cT2AVlqOTLuyWV0", + databaseUrl = "https://fir-kotlin-sdk.firebaseio.com", + storageBucket = "fir-kotlin-sdk.appspot.com", + projectId = "fir-kotlin-sdk", + gcmSenderId = "846484016111" + ) + ) + + performance = Firebase.performance(app) } @Test fun testInstrumentationEnabled() = runTest { - - val performance = Firebase.performance - performance.setInstrumentationEnabled(false) assertFalse(performance.isInstrumentationEnabled()) diff --git a/firebase-perf/src/jvmMain/kotlin/dev/gitlive/firebase/perf/performance.jvm.kt b/firebase-perf/src/jvmMain/kotlin/dev/gitlive/firebase/perf/performance.jvm.kt index f77c9e0cb..941a3bd8a 100644 --- a/firebase-perf/src/jvmMain/kotlin/dev/gitlive/firebase/perf/performance.jvm.kt +++ b/firebase-perf/src/jvmMain/kotlin/dev/gitlive/firebase/perf/performance.jvm.kt @@ -28,4 +28,4 @@ actual class FirebasePerformance { } -actual open class FirebasePerformanceException : FirebaseException() \ No newline at end of file +actual open class FirebasePerformanceException internal constructor(message: String) : FirebaseException(message) \ No newline at end of file diff --git a/firebase-perf/src/jvmTest/kotlin/dev/gitlive/firebase/perf/performance.kt b/firebase-perf/src/jvmTest/kotlin/dev/gitlive/firebase/perf/performance.kt index 8fcbdfbd0..f8134eecb 100644 --- a/firebase-perf/src/jvmTest/kotlin/dev/gitlive/firebase/perf/performance.kt +++ b/firebase-perf/src/jvmTest/kotlin/dev/gitlive/firebase/perf/performance.kt @@ -5,12 +5,9 @@ @file:JvmName("tests") package dev.gitlive.firebase.perf -import kotlinx.coroutines.CoroutineScope - actual val emulatorHost: String = "10.0.2.2" actual val context: Any = Unit -actual fun runTest(test: suspend CoroutineScope.() -> Unit) = kotlinx.coroutines.test.runTest { test() } @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) actual annotation class IgnoreForAndroidUnitTest diff --git a/firebase-storage/build.gradle.kts b/firebase-storage/build.gradle.kts index bd183e6e5..1afcfefdb 100644 --- a/firebase-storage/build.gradle.kts +++ b/firebase-storage/build.gradle.kts @@ -1,3 +1,5 @@ +import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSetTree + /* * Copyright (c) 2023 GitLive Ltd. Use of this source code is governed by the Apache 2.0 license. */ @@ -46,7 +48,16 @@ val supportIosTarget = project.property("skipIosTarget") != "true" kotlin { + targets.configureEach { + compilations.configureEach { + kotlinOptions.freeCompilerArgs += "-Xexpect-actual-classes" + } + } + + @Suppress("OPT_IN_USAGE") androidTarget { + instrumentedTestVariant.sourceSetTree.set(KotlinSourceSetTree.test) + unitTestVariant.sourceSetTree.set(KotlinSourceSetTree.test) publishAllLibraryVariants() compilations.configureEach { kotlinOptions { @@ -69,7 +80,8 @@ kotlin { } if (supportIosTarget) { - ios() + iosArm64() + iosX64() iosSimulatorArm64() cocoapods { ios.deploymentTarget = "11.0" @@ -79,6 +91,7 @@ kotlin { noPodspec() pod("FirebaseStorage") { version = "10.15.0" + extraOpts += listOf("-compiler-option", "-fmodules") } } } @@ -113,6 +126,9 @@ kotlin { this.apiVersion = apiVersion this.languageVersion = languageVersion progressiveMode = true + if (name.lowercase().contains("ios")) { + optIn("kotlinx.cinterop.ExperimentalForeignApi") + } } } @@ -123,7 +139,7 @@ kotlin { } } - val commonTest by getting { + getByName("commonTest") { dependencies { implementation(project(":test-utils")) } @@ -134,21 +150,6 @@ kotlin { api("com.google.firebase:firebase-storage") } } - - getByName("androidInstrumentedTest") { - dependencies { - dependsOn(commonTest) - } - } - - if (supportIosTarget) { - val iosMain by getting - val iosSimulatorArm64Main by getting - iosSimulatorArm64Main.dependsOn(iosMain) - val iosTest by sourceSets.getting - val iosSimulatorArm64Test by getting - iosSimulatorArm64Test.dependsOn(iosTest) - } } } diff --git a/firebase-storage/package.json b/firebase-storage/package.json index 22d330b4c..92ff99ae6 100644 --- a/firebase-storage/package.json +++ b/firebase-storage/package.json @@ -1,6 +1,6 @@ { "name": "@gitlive/firebase-storage", - "version": "1.10.1-SNAPSHOT", + "version": "1.10.4", "description": "Wrapper around firebase for usage in Kotlin Multiplatform projects", "main": "firebase-storage.js", "scripts": { @@ -23,7 +23,7 @@ }, "homepage": "https://github.com/GitLiveApp/firebase-kotlin-sdk", "dependencies": { - "@gitlive/firebase-app": "1.10.1-SNAPSHOT", + "@gitlive/firebase-app": "1.10.4", "firebase": "9.19.1", "kotlin": "1.6.10", "kotlinx-coroutines-core": "1.6.1-native-mt" diff --git a/firebase-storage/src/androidInstrumentedTest/kotlin/dev/gitlive/firebase/storage/storage.kt b/firebase-storage/src/androidInstrumentedTest/kotlin/dev/gitlive/firebase/storage/storage.kt index 093077ed3..b19cde437 100644 --- a/firebase-storage/src/androidInstrumentedTest/kotlin/dev/gitlive/firebase/storage/storage.kt +++ b/firebase-storage/src/androidInstrumentedTest/kotlin/dev/gitlive/firebase/storage/storage.kt @@ -13,6 +13,5 @@ actual val emulatorHost: String = "10.0.2.2" actual val context: Any = InstrumentationRegistry.getInstrumentation().targetContext -actual fun runTest(test: suspend CoroutineScope.() -> Unit) = runBlocking { test() } @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) actual annotation class IgnoreForAndroidUnitTest \ No newline at end of file diff --git a/firebase-storage/src/androidUnitTest/kotlin/dev/gitlive/firebase/storage/storage.kt b/firebase-storage/src/androidUnitTest/kotlin/dev/gitlive/firebase/storage/storage.kt index 94430eadc..bb42eb2f7 100644 --- a/firebase-storage/src/androidUnitTest/kotlin/dev/gitlive/firebase/storage/storage.kt +++ b/firebase-storage/src/androidUnitTest/kotlin/dev/gitlive/firebase/storage/storage.kt @@ -1,12 +1,9 @@ package dev.gitlive.firebase.storage -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.runBlocking import org.junit.Ignore actual val emulatorHost: String = "10.0.2.2" actual val context: Any = "" -actual fun runTest(test: suspend CoroutineScope.() -> Unit) = runBlocking { test() } actual typealias IgnoreForAndroidUnitTest = Ignore diff --git a/firebase-storage/src/commonTest/kotlin/dev/gitlive/firebase/storage/storage.kt b/firebase-storage/src/commonTest/kotlin/dev/gitlive/firebase/storage/storage.kt index 7c104afef..001373004 100644 --- a/firebase-storage/src/commonTest/kotlin/dev/gitlive/firebase/storage/storage.kt +++ b/firebase-storage/src/commonTest/kotlin/dev/gitlive/firebase/storage/storage.kt @@ -8,34 +8,32 @@ import dev.gitlive.firebase.Firebase import dev.gitlive.firebase.FirebaseOptions import dev.gitlive.firebase.apps import dev.gitlive.firebase.initialize -import kotlinx.coroutines.CoroutineScope import kotlin.test.BeforeTest expect val emulatorHost: String expect val context: Any -expect fun runTest(test: suspend CoroutineScope.() -> Unit) expect annotation class IgnoreForAndroidUnitTest() class FirebaseStorageTest { + lateinit var storage: FirebaseStorage + @BeforeTest fun initializeFirebase() { - Firebase - .takeIf { Firebase.apps(context).isEmpty() } - ?.apply { - initialize( - context, - FirebaseOptions( - applicationId = "1:846484016111:ios:dd1f6688bad7af768c841a", - apiKey = "AIzaSyCK87dcMFhzCz_kJVs2cT2AVlqOTLuyWV0", - databaseUrl = "https://fir-kotlin-sdk.firebaseio.com", - storageBucket = "fir-kotlin-sdk.appspot.com", - projectId = "fir-kotlin-sdk", - gcmSenderId = "846484016111" - ) - ) - Firebase.storage.useEmulator(emulatorHost, 9199) - } - } + val app = Firebase.apps(context).firstOrNull() ?: Firebase.initialize( + context, + FirebaseOptions( + applicationId = "1:846484016111:ios:dd1f6688bad7af768c841a", + apiKey = "AIzaSyCK87dcMFhzCz_kJVs2cT2AVlqOTLuyWV0", + databaseUrl = "https://fir-kotlin-sdk.firebaseio.com", + storageBucket = "fir-kotlin-sdk.appspot.com", + projectId = "fir-kotlin-sdk", + gcmSenderId = "846484016111" + ) + ) + storage = Firebase.storage(app).apply { + useEmulator(emulatorHost, 9199) + } + } } \ No newline at end of file diff --git a/firebase-storage/src/iosTest/kotlin/dev/gitlive/firebase/storage/storage.kt b/firebase-storage/src/iosTest/kotlin/dev/gitlive/firebase/storage/storage.kt index 56c5d9dc4..7b3541194 100644 --- a/firebase-storage/src/iosTest/kotlin/dev/gitlive/firebase/storage/storage.kt +++ b/firebase-storage/src/iosTest/kotlin/dev/gitlive/firebase/storage/storage.kt @@ -4,31 +4,9 @@ package dev.gitlive.firebase.storage -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.MainScope -import kotlinx.coroutines.async -import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.yield -import platform.Foundation.NSDate -import platform.Foundation.NSDefaultRunLoopMode -import platform.Foundation.NSRunLoop -import platform.Foundation.create -import platform.Foundation.runMode - actual val emulatorHost: String = "127.0.0.1" actual val context: Any = Unit -actual fun runTest(test: suspend CoroutineScope.() -> Unit) = runBlocking { - val testRun = MainScope().async { test() } - while (testRun.isActive) { - NSRunLoop.mainRunLoop.runMode( - NSDefaultRunLoopMode, - beforeDate = NSDate.create(timeInterval = 1.0, sinceDate = NSDate()) - ) - yield() - } - testRun.await() -} @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) actual annotation class IgnoreForAndroidUnitTest diff --git a/firebase-storage/src/jsTest/kotlin/dev/gitlive/firebase/storage/storage.kt b/firebase-storage/src/jsTest/kotlin/dev/gitlive/firebase/storage/storage.kt index dafd2b588..9b2873e17 100644 --- a/firebase-storage/src/jsTest/kotlin/dev/gitlive/firebase/storage/storage.kt +++ b/firebase-storage/src/jsTest/kotlin/dev/gitlive/firebase/storage/storage.kt @@ -4,15 +4,9 @@ package dev.gitlive.firebase.storage -import kotlinx.coroutines.CoroutineScope -import kotlin.time.Duration.Companion.minutes - actual val emulatorHost: String = "127.0.0.1" actual val context: Any = Unit -actual fun runTest(test: suspend CoroutineScope.() -> Unit) { - kotlinx.coroutines.test.runTest(timeout = 5.minutes) { test() } -} @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) actual annotation class IgnoreForAndroidUnitTest \ No newline at end of file diff --git a/firebase-storage/src/jvmMain/kotlin/dev/gitlive/firebase/storage/storage.jvm.kt b/firebase-storage/src/jvmMain/kotlin/dev/gitlive/firebase/storage/storage.jvm.kt index 2d1f07ca4..cc61e378b 100644 --- a/firebase-storage/src/jvmMain/kotlin/dev/gitlive/firebase/storage/storage.jvm.kt +++ b/firebase-storage/src/jvmMain/kotlin/dev/gitlive/firebase/storage/storage.jvm.kt @@ -85,4 +85,4 @@ actual class ListResult { } actual class File -actual class FirebaseStorageException : FirebaseException() \ No newline at end of file +actual class FirebaseStorageException internal constructor(message: String) : FirebaseException(message) \ No newline at end of file diff --git a/firebase-storage/src/jvmTest/kotlin/dev/gitlive/firebase/storage/storage.kt b/firebase-storage/src/jvmTest/kotlin/dev/gitlive/firebase/storage/storage.kt index b9664f544..b21166041 100644 --- a/firebase-storage/src/jvmTest/kotlin/dev/gitlive/firebase/storage/storage.kt +++ b/firebase-storage/src/jvmTest/kotlin/dev/gitlive/firebase/storage/storage.kt @@ -5,13 +5,9 @@ @file:JvmName("tests") package dev.gitlive.firebase.storage -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.runBlocking - actual val emulatorHost: String = "10.0.2.2" actual val context: Any = Unit -actual fun runTest(test: suspend CoroutineScope.() -> Unit) = runBlocking { test() } @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) actual annotation class IgnoreForAndroidUnitTest \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 0864cfc09..d476d43ee 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,8 +11,6 @@ kotlin.mpp.stability.nowarn=true #kotlin.native.enableDependencyPropagation=false kotlin.native.enableParallelExecutionCheck=false kotlin.setJvmTargetFromAndroidCompileOptions=true -kotlin.native.binary.memoryModel=experimental -kotlin.native.binary.freezing=disabled org.gradle.jvmargs=-Xmx8G -Dfile.encoding\=UTF-8 -XX:MaxMetaspaceSize=512m -Dkotlin.daemon.jvm.options\=-Xmx8G,-XX:MaxMetaspaceSize=512m org.gradle.parallel=true systemProp.org.gradle.internal.publish.checksums.insecure=true @@ -51,23 +49,23 @@ firebase-storage.skipJsTests=false # Versions: ## do not upstream ## ##################### -firebase-app.version=1.10.1-SNAPSHOT -firebase-auth.version=1.10.1-SNAPSHOT -firebase-common.version=1.10.1-SNAPSHOT -firebase-config.version=1.10.1-SNAPSHOT -firebase-database.version=1.10.1-SNAPSHOT -firebase-firestore.version=1.10.1-SNAPSHOT -firebase-functions.version=1.10.1-SNAPSHOT -firebase-installations.version=1.10.1-SNAPSHOT -firebase-perf.version=1.10.1-SNAPSHOT -firebase-crashlytics.version=1.10.1-SNAPSHOT -firebase-storage.version=1.10.1-SNAPSHOT +firebase-app.version=1.10.4-SNAPSHOT +firebase-auth.version=1.10.4-SNAPSHOT +firebase-common.version=1.10.4-SNAPSHOT +firebase-config.version=1.10.4-SNAPSHOT +firebase-database.version=1.10.4-SNAPSHOT +firebase-firestore.version=1.10.4-SNAPSHOT +firebase-functions.version=1.10.4-SNAPSHOT +firebase-installations.version=1.10.4-SNAPSHOT +firebase-perf.version=1.10.4-SNAPSHOT +firebase-crashlytics.version=1.10.4-SNAPSHOT +firebase-storage.version=1.10.4-SNAPSHOT # Dependencies Versions: -gradlePluginVersion=8.1.1 -kotlinVersion=1.9.10 +gradlePluginVersion=8.1.3 +kotlinVersion=1.9.20 coroutinesVersion=1.7.3 serializationVersion=1.6.0 -firebaseBoMVersion=32.2.3 +firebaseBoMVersion=32.5.0 apiVersion=1.8 languageVersion=1.9 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index fae08049a..e411586a5 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/test-utils/build.gradle.kts b/test-utils/build.gradle.kts index 9b3874310..d8f7ea223 100644 --- a/test-utils/build.gradle.kts +++ b/test-utils/build.gradle.kts @@ -41,6 +41,13 @@ android { kotlin { + targets.configureEach { + compilations.configureEach { + kotlinOptions.freeCompilerArgs += "-Xexpect-actual-classes" + } + } + + @Suppress("OPT_IN_USAGE") androidTarget { publishAllLibraryVariants() compilations.configureEach { @@ -66,7 +73,8 @@ kotlin { val supportIosTarget = project.property("skipIosTarget") != "true" if (supportIosTarget) { - ios() + iosArm64() + iosX64() iosSimulatorArm64() } @@ -84,12 +92,19 @@ kotlin { this.apiVersion = apiVersion this.languageVersion = languageVersion progressiveMode = true + if (name.lowercase().contains("ios")) { + optIn("kotlinx.cinterop.ExperimentalForeignApi") + optIn("kotlinx.cinterop.BetaInteropApi") + } } } getByName("commonMain") { dependencies { + val coroutinesVersion: String by project api(kotlin("test")) + api("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion") + api("org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesVersion") } } @@ -97,15 +112,6 @@ kotlin { kotlin.srcDir("src/androidMain/kotlin") } - if (supportIosTarget) { - val iosMain by getting - val iosSimulatorArm64Main by getting - iosSimulatorArm64Main.dependsOn(iosMain) - val iosTest by sourceSets.getting - val iosSimulatorArm64Test by getting - iosSimulatorArm64Test.dependsOn(iosTest) - } - getByName("jsMain") { dependencies { implementation(kotlin("test-js")) diff --git a/test-utils/src/androidMain/kotlin/dev/gitlive/firebase/TestUtils.kt b/test-utils/src/androidMain/kotlin/dev/gitlive/firebase/TestUtils.kt index a558fcd39..1a4635f85 100644 --- a/test-utils/src/androidMain/kotlin/dev/gitlive/firebase/TestUtils.kt +++ b/test-utils/src/androidMain/kotlin/dev/gitlive/firebase/TestUtils.kt @@ -1,9 +1,17 @@ +@file:JvmName("TestUtilsAndroid") /* * Copyright (c) 2020 GitLive Ltd. Use of this source code is governed by the Apache 2.0 license. */ package dev.gitlive.firebase +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.runBlocking +import kotlin.time.Duration.Companion.minutes + +actual fun runTest(test: suspend CoroutineScope.() -> Unit) = kotlinx.coroutines.test.runTest(timeout = 5.minutes) { test() } +actual fun runBlockingTest(action: suspend CoroutineScope.() -> Unit) = runBlocking(block = action) + actual fun nativeMapOf(vararg pairs: Pair): Any = mapOf(*pairs) actual fun nativeListOf(vararg elements: Any): Any = listOf(*elements) actual fun nativeAssertEquals(expected: Any?, actual: Any?) { diff --git a/test-utils/src/commonMain/kotlin/dev/gitlive/firebase/TestUtils.kt b/test-utils/src/commonMain/kotlin/dev/gitlive/firebase/TestUtils.kt index bbdbd3481..4fa7e1c05 100644 --- a/test-utils/src/commonMain/kotlin/dev/gitlive/firebase/TestUtils.kt +++ b/test-utils/src/commonMain/kotlin/dev/gitlive/firebase/TestUtils.kt @@ -4,6 +4,11 @@ package dev.gitlive.firebase +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.test.TestResult +expect fun runTest(test: suspend CoroutineScope.() -> Unit): TestResult +expect fun runBlockingTest(action: suspend CoroutineScope.() -> Unit) + expect fun nativeMapOf(vararg pairs: Pair): Any expect fun nativeListOf(vararg elements: Any): Any expect fun nativeAssertEquals(expected: Any?, actual: Any?) diff --git a/test-utils/src/iosMain/kotlin/dev/gitlive/firebase/TestUtils.kt b/test-utils/src/iosMain/kotlin/dev/gitlive/firebase/TestUtils.kt index a558fcd39..6ba4248a4 100644 --- a/test-utils/src/iosMain/kotlin/dev/gitlive/firebase/TestUtils.kt +++ b/test-utils/src/iosMain/kotlin/dev/gitlive/firebase/TestUtils.kt @@ -4,6 +4,29 @@ package dev.gitlive.firebase +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.MainScope +import kotlinx.coroutines.async +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.yield +import platform.Foundation.NSDate +import platform.Foundation.NSDefaultRunLoopMode +import platform.Foundation.NSRunLoop +import platform.Foundation.create +import platform.Foundation.runMode + +actual fun runTest(test: suspend CoroutineScope.() -> Unit) = runBlocking { + val testRun = MainScope().async { test() } + while (testRun.isActive) { + NSRunLoop.mainRunLoop.runMode( + NSDefaultRunLoopMode, + beforeDate = NSDate.create(timeInterval = 1.0, sinceDate = NSDate()) + ) + yield() + } + testRun.await() +} +actual fun runBlockingTest(action: suspend CoroutineScope.() -> Unit) = runBlocking(block = action) actual fun nativeMapOf(vararg pairs: Pair): Any = mapOf(*pairs) actual fun nativeListOf(vararg elements: Any): Any = listOf(*elements) actual fun nativeAssertEquals(expected: Any?, actual: Any?) { diff --git a/test-utils/src/jsMain/kotlin/dev/gitlive/firebase/TestUtils.kt b/test-utils/src/jsMain/kotlin/dev/gitlive/firebase/TestUtils.kt index f9444d7a8..eac94efcf 100644 --- a/test-utils/src/jsMain/kotlin/dev/gitlive/firebase/TestUtils.kt +++ b/test-utils/src/jsMain/kotlin/dev/gitlive/firebase/TestUtils.kt @@ -4,7 +4,15 @@ package dev.gitlive.firebase +import kotlinx.coroutines.CoroutineScope import kotlin.js.json +import kotlin.time.Duration.Companion.minutes + +actual fun runTest(test: suspend CoroutineScope.() -> Unit) = + kotlinx.coroutines.test.runTest(timeout = 5.minutes) { test() } +actual fun runBlockingTest(action: suspend CoroutineScope.() -> Unit) { + kotlinx.coroutines.test.runTest { action() } +} actual fun nativeMapOf(vararg pairs: Pair): Any = json(*pairs.map { (key, value) -> ((key as? String) ?: JSON.stringify(key)) to value }.toTypedArray()) actual fun nativeListOf(vararg elements: Any): Any = elements