Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Adding fixes for OnDisconnect
  • Loading branch information
Daeda88 committed Apr 11, 2024
commit 06dd193c679660e5d8e70032954d69e89a71e45f
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ actual class FirebaseDatabase private constructor(val android: com.google.fireba

actual fun useEmulator(host: String, port: Int) =
android.useEmulator(host, port)

actual fun goOffline() = android.goOffline()

actual fun goOnline() = android.goOnline()
}

internal actual open class NativeQuery(
Expand Down Expand Up @@ -293,8 +297,9 @@ internal actual class NativeOnDisconnect internal constructor(
.run { if(persistenceEnabled) await() else awaitWhileOnline(database) }
.run { Unit }

actual suspend fun updateEncodedChildren(encodedUpdate: Map<String, Any?>) =
android.updateChildren(encodedUpdate)
@Suppress("UNCHECKED_CAST")
actual suspend fun updateEncodedChildren(encodedUpdate: Any?) =
android.updateChildren(encodedUpdate as Map<String, Any?>)
.run { if(persistenceEnabled) await() else awaitWhileOnline(database) }
.run { Unit }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ expect class FirebaseDatabase {
fun setPersistenceEnabled(enabled: Boolean)
fun setLoggingEnabled(enabled: Boolean)
fun useEmulator(host: String, port: Int)

fun goOffline()

fun goOnline()
}

data class ChildEvent internal constructor(
Expand Down Expand Up @@ -140,7 +144,7 @@ internal expect class NativeOnDisconnect {
suspend fun removeValue()
suspend fun cancel()
suspend fun setValue(encodedValue: Any?)
suspend fun updateEncodedChildren(encodedUpdate: Map<String, Any?>)
suspend fun updateEncodedChildren(encodedUpdate: Any?)
}

class OnDisconnect internal constructor(@PublishedApi internal val native: NativeOnDisconnect) {
Expand All @@ -156,7 +160,7 @@ class OnDisconnect internal constructor(@PublishedApi internal val native: Nativ
setValue(strategy, value) { this.encodeDefaults = encodeDefaults }
suspend inline fun <T> setValue(strategy: SerializationStrategy<T>, value: T, buildSettings: EncodeSettings.Builder.() -> Unit = {}) = setValue(encode(strategy, value, buildSettings))

suspend inline fun updateChildren(update: Map<String, Any?>, buildSettings: EncodeSettings.Builder.() -> Unit = {}) = native.updateEncodedChildren(update.mapValues { (_, it) -> encode(it, buildSettings) })
suspend inline fun updateChildren(update: Map<String, Any?>, buildSettings: EncodeSettings.Builder.() -> Unit = {}) = native.updateEncodedChildren(encode(update, buildSettings))
@Deprecated("Deprecated. Use builder instead", replaceWith = ReplaceWith("updateChildren(update) { this.encodeDefaults = encodeDefaults }"))
suspend fun updateChildren(update: Map<String, Any?>, encodeDefaults: Boolean) = updateChildren(update) {
this.encodeDefaults = encodeDefaults
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import dev.gitlive.firebase.runBlockingTest
import dev.gitlive.firebase.runTest
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.withContext
import kotlinx.coroutines.withTimeout
import kotlinx.serialization.Serializable
Expand All @@ -16,6 +17,7 @@ import kotlin.test.AfterTest
import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
import kotlin.time.Duration.Companion.minutes

Expand All @@ -41,9 +43,9 @@ class FirebaseDatabaseTest {
FirebaseOptions(
applicationId = "1:846484016111:ios:dd1f6688bad7af768c841a",
apiKey = "AIzaSyCK87dcMFhzCz_kJVs2cT2AVlqOTLuyWV0",
databaseUrl = "https://fir-kotlin-sdk.firebaseio.com",
databaseUrl = "https://fir-kotlin-sdk-default-rtdb.firebaseio.com",
storageBucket = "fir-kotlin-sdk.appspot.com",
projectId = "fir-kotlin-sdk",
projectId = "fir-kotlin-sdk-default-rtdb",
gcmSenderId = "846484016111"
)
)
Expand All @@ -60,112 +62,127 @@ class FirebaseDatabaseTest {
}
}

@Test
fun testSetValue() = runTest {
ensureDatabaseConnected()
val testValue = "test"
val testReference = database.reference("testPath")

testReference.setValue(testValue)

val testReferenceValue = testReference
.valueEvents
.first()
.value<String>()

assertEquals(testValue, testReferenceValue)
}
// @Test
// fun testSetValue() = runTest {
// ensureDatabaseConnected()
// val testValue = "test"
// val testReference = database.reference("testPath")
//
// testReference.setValue(testValue)
//
// val testReferenceValue = testReference
// .valueEvents
// .first()
// .value<String>()
//
// assertEquals(testValue, testReferenceValue)
// }
//
// @Test
// fun testChildCount() = runTest {
// setupRealtimeData()
// val dataSnapshot = database
// .reference("FirebaseRealtimeDatabaseTest")
// .valueEvents
// .first()
//
// val firebaseDatabaseChildCount = dataSnapshot.children.count()
// assertEquals(3, firebaseDatabaseChildCount)
// }
//
// @Test
// fun testBasicIncrementTransaction() = runTest {
// ensureDatabaseConnected()
// val data = DatabaseTest("PostOne", 2)
// val userRef = database.reference("users/user_1/post_id_1")
// setupDatabase(userRef, data, DatabaseTest.serializer())
//
// // Check database before transaction
// val userDocBefore = userRef.valueEvents.first().value(DatabaseTest.serializer())
// assertEquals(data.title, userDocBefore.title)
// assertEquals(data.likes, userDocBefore.likes)
//
// // Run transaction
// val transactionSnapshot = userRef.runTransaction(DatabaseTest.serializer()) { it.copy(likes = it.likes + 1) }
// val userDocAfter = transactionSnapshot.value(DatabaseTest.serializer())
//
// // Check the database after transaction
// assertEquals(data.title, userDocAfter.title)
// assertEquals(data.likes + 1, userDocAfter.likes)
// }
//
// @Test
// fun testBasicDecrementTransaction() = runTest {
// ensureDatabaseConnected()
// val data = DatabaseTest("PostTwo", 2)
// val userRef = database.reference("users/user_1/post_id_2")
// setupDatabase(userRef, data, DatabaseTest.serializer())
//
// // Check database before transaction
// val userDocBefore = userRef.valueEvents.first().value(DatabaseTest.serializer())
// assertEquals(data.title, userDocBefore.title)
// assertEquals(data.likes, userDocBefore.likes)
//
// // Run transaction
// val transactionSnapshot = userRef.runTransaction(DatabaseTest.serializer()) { it.copy(likes = it.likes - 1) }
// val userDocAfter = transactionSnapshot.value(DatabaseTest.serializer())
//
// // Check the database after transaction
// assertEquals(data.title, userDocAfter.title)
// assertEquals(data.likes - 1, userDocAfter.likes)
// }
//
// @Test
// fun testSetServerTimestamp() = runTest {
// ensureDatabaseConnected()
// val testReference = database.reference("testSetServerTimestamp")
//
// testReference.setValue(ServerValue.TIMESTAMP)
//
// val timestamp = testReference
// .valueEvents
// .first()
// .value<Long>()
//
// assertTrue(timestamp > 0)
// }
//
// @Test
// fun testIncrement() = runTest {
// ensureDatabaseConnected()
// val testReference = database.reference("testIncrement")
//
// testReference.setValue(2.0)
//
// val value = testReference
// .valueEvents
// .first()
// .value<Double>()
//
// assertEquals(2.0, value)
//
// testReference.setValue(ServerValue.increment(5.0))
// val updatedValue = testReference
// .valueEvents
// .first()
// .value<Double>()
//
// assertEquals(7.0, updatedValue)
// }

@Test
fun testChildCount() = runTest {
fun testUpdateChildren() = runTest {
setupRealtimeData()
val dataSnapshot = database
val reference = database
.reference("FirebaseRealtimeDatabaseTest")
.valueEvents
.first()

val firebaseDatabaseChildCount = dataSnapshot.children.count()
assertEquals(3, firebaseDatabaseChildCount)
}
val valueEvents = reference.child("lastActivity").valueEvents
assertTrue(valueEvents.first().exists)
reference.onDisconnect().updateChildren(mapOf("test" to false, "nested" to mapOf("lastActivity" to null), "lastActivity" to null))
database.goOffline()

@Test
fun testBasicIncrementTransaction() = runTest {
database.goOnline()
ensureDatabaseConnected()
val data = DatabaseTest("PostOne", 2)
val userRef = database.reference("users/user_1/post_id_1")
setupDatabase(userRef, data, DatabaseTest.serializer())

// Check database before transaction
val userDocBefore = userRef.valueEvents.first().value(DatabaseTest.serializer())
assertEquals(data.title, userDocBefore.title)
assertEquals(data.likes, userDocBefore.likes)

// Run transaction
val transactionSnapshot = userRef.runTransaction(DatabaseTest.serializer()) { it.copy(likes = it.likes + 1) }
val userDocAfter = transactionSnapshot.value(DatabaseTest.serializer())

// Check the database after transaction
assertEquals(data.title, userDocAfter.title)
assertEquals(data.likes + 1, userDocAfter.likes)
}

@Test
fun testBasicDecrementTransaction() = runTest {
ensureDatabaseConnected()
val data = DatabaseTest("PostTwo", 2)
val userRef = database.reference("users/user_1/post_id_2")
setupDatabase(userRef, data, DatabaseTest.serializer())

// Check database before transaction
val userDocBefore = userRef.valueEvents.first().value(DatabaseTest.serializer())
assertEquals(data.title, userDocBefore.title)
assertEquals(data.likes, userDocBefore.likes)

// Run transaction
val transactionSnapshot = userRef.runTransaction(DatabaseTest.serializer()) { it.copy(likes = it.likes - 1) }
val userDocAfter = transactionSnapshot.value(DatabaseTest.serializer())

// Check the database after transaction
assertEquals(data.title, userDocAfter.title)
assertEquals(data.likes - 1, userDocAfter.likes)
}

@Test
fun testSetServerTimestamp() = runTest {
ensureDatabaseConnected()
val testReference = database.reference("testSetServerTimestamp")

testReference.setValue(ServerValue.TIMESTAMP)

val timestamp = testReference
.valueEvents
.first()
.value<Long>()

assertTrue(timestamp > 0)
}

@Test
fun testIncrement() = runTest {
ensureDatabaseConnected()
val testReference = database.reference("testIncrement")

testReference.setValue(2.0)

val value = testReference
.valueEvents
.first()
.value<Double>()

assertEquals(2.0, value)

testReference.setValue(ServerValue.increment(5.0))
val updatedValue = testReference
.valueEvents
.first()
.value<Double>()

assertEquals(7.0, updatedValue)
assertFalse(valueEvents.first().exists)
}

private suspend fun setupRealtimeData() {
Expand All @@ -177,9 +194,13 @@ class FirebaseDatabaseTest {
val firebaseDatabaseChildTest2 = FirebaseDatabaseChildTest("bbb")
val firebaseDatabaseChildTest3 = FirebaseDatabaseChildTest("ccc")

firebaseDatabaseTestReference.child("1").setValue(firebaseDatabaseChildTest1)
firebaseDatabaseTestReference.child("2").setValue(firebaseDatabaseChildTest2)
firebaseDatabaseTestReference.child("3").setValue(firebaseDatabaseChildTest3)
val values = firebaseDatabaseTestReference.child("values")
values.child("1").setValue(firebaseDatabaseChildTest1)
values.child("2").setValue(firebaseDatabaseChildTest2)
values.child("3").setValue(firebaseDatabaseChildTest3)
firebaseDatabaseTestReference.child("lastActivity").setValue(1)
firebaseDatabaseTestReference.child("test").setValue(true)
firebaseDatabaseTestReference.child("nested").setValue(mapOf("lastActivity" to 0))
}

private suspend fun <T> setupDatabase(ref: DatabaseReference, data: T, strategy: SerializationStrategy<T>) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ actual class FirebaseDatabase internal constructor(val ios: FIRDatabase) {

actual fun useEmulator(host: String, port: Int) =
ios.useEmulatorWithHost(host, port.toLong())

actual fun goOffline() = ios.goOffline()

actual fun goOnline() = ios.goOnline()
}

fun Type.toEventType() = when(this) {
Expand Down Expand Up @@ -238,7 +242,7 @@ internal actual class NativeOnDisconnect internal constructor(
}

@Suppress("UNCHECKED_CAST")
actual suspend fun updateEncodedChildren(encodedUpdate: Map<String, Any?>) {
actual suspend fun updateEncodedChildren(encodedUpdate: Any?) {
ios.await(persistenceEnabled) { onDisconnectUpdateChildValues(encodedUpdate as Map<Any?, *>, it) }
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ import dev.gitlive.firebase.database.externals.OnDisconnect as JsOnDisconnect
import dev.gitlive.firebase.database.externals.Query as JsQuery
import dev.gitlive.firebase.database.externals.endAt as jsEndAt
import dev.gitlive.firebase.database.externals.equalTo as jsEqualTo
import dev.gitlive.firebase.database.externals.goOffline as jsGoOffline
import dev.gitlive.firebase.database.externals.goOnline as jsGoOnline
import dev.gitlive.firebase.database.externals.limitToFirst as jsLimitToFirst
import dev.gitlive.firebase.database.externals.limitToLast as jsLimitToLast
import dev.gitlive.firebase.database.externals.orderByChild as jsOrderByChild
Expand All @@ -72,6 +74,10 @@ actual class FirebaseDatabase internal constructor(val js: Database) {
actual fun setPersistenceEnabled(enabled: Boolean) {}
actual fun setLoggingEnabled(enabled: Boolean) = rethrow { enableLogging(enabled) }
actual fun useEmulator(host: String, port: Int) = rethrow { connectDatabaseEmulator(js, host, port) }

actual fun goOffline() = rethrow { jsGoOffline(js) }

actual fun goOnline() = rethrow { jsGoOnline(js) }
}

internal actual open class NativeQuery(
Expand Down Expand Up @@ -228,8 +234,8 @@ internal actual class NativeOnDisconnect internal constructor(
actual suspend fun setValue(encodedValue: Any?) =
rethrow { js.set(encodedValue).awaitWhileOnline(database) }

actual suspend fun updateEncodedChildren(encodedUpdate: Map<String, Any?>) =
rethrow { js.update(encodedUpdate).awaitWhileOnline(database) }
actual suspend fun updateEncodedChildren(encodedUpdate: Any?) =
rethrow { js.update(encodedUpdate ?: json()).awaitWhileOnline(database) }

}

Expand Down
12 changes: 11 additions & 1 deletion test/database.rules.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
{
"rules": {
".read": true,
".write": true
".write": true,
"FirebaseRealtimeDatabaseTest": {
"lastActivity": {
".validate": "!newData.exists() || newData.isNumber()"
},
"nested": {
"lastActivity": {
".validate": "!newData.exists() || newData.isNumber()"
}
}
}
}
}