Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Failing Node JS Tests #665

Merged
merged 3 commits into from
Oct 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ androidCompileSdk = "33"
androidGradlePlugin = "7.4.2"
androidTargetSdk = "33"
atomicFu = "0.24.0"
baseKotlin = "2.0.0"
baseKotlin = "2.0.20"
dokkaGradlePlugin = "1.9.10"
ktlintGradle = "12.1.0"
jacocoGradlePlugin = "0.8.7"
Expand All @@ -14,10 +14,10 @@ pagingCompose = "3.3.0-alpha02"
pagingRuntime = "3.2.1"
spotlessPluginGradle = "6.4.1"
junit = "4.13.2"
kotlinxCoroutines = "1.8.0"
kotlinxSerialization = "1.5.1"
kotlinxCoroutines = "1.8.1"
kotlinxSerialization = "1.6.3"
kermit = "2.0.4"
testCore = "1.5.0"
testCore = "1.6.1"
kmmBridge = "0.3.2"
ktlint = "0.39.0"
kover = "0.6.0"
Expand Down
28 changes: 11 additions & 17 deletions paging/kover/coverage.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,15 @@
<report name="Intellij Coverage Report">
<package name="org/mobilenativefoundation/store/paging5">
<class name="org/mobilenativefoundation/store/paging5/BuildConfig" sourcefilename="BuildConfig.java">
<method name="&lt;clinit&gt;" desc="()V">
<counter type="INSTRUCTION" missed="3" covered="0"/>
<counter type="BRANCH" missed="0" covered="0"/>
<counter type="LINE" missed="1" covered="0"/>
</method>
<method name="&lt;init&gt;" desc="()V">
<counter type="INSTRUCTION" missed="2" covered="0"/>
<counter type="BRANCH" missed="0" covered="0"/>
<counter type="LINE" missed="1" covered="0"/>
</method>
<counter type="INSTRUCTION" missed="5" covered="0"/>
<counter type="INSTRUCTION" missed="2" covered="0"/>
<counter type="BRANCH" missed="0" covered="0"/>
<counter type="LINE" missed="2" covered="0"/>
<counter type="METHOD" missed="2" covered="0"/>
<counter type="LINE" missed="1" covered="0"/>
<counter type="METHOD" missed="1" covered="0"/>
</class>
<class name="org/mobilenativefoundation/store/paging5/LaunchPagingStoreKt" sourcefilename="LaunchPagingStore.kt">
<method name="launchPagingStore$lambda$1" desc="(Lorg/mobilenativefoundation/store/store5/MutableStore;Lorg/mobilenativefoundation/store/core5/StoreKey;)Lkotlinx/coroutines/flow/Flow;">
Expand Down Expand Up @@ -278,10 +273,9 @@
</class>
<sourcefile name="BuildConfig.java">
<line nr="6" mi="2" ci="0" mb="0" cb="0"/>
<line nr="7" mi="3" ci="0" mb="0" cb="0"/>
<counter type="INSTRUCTION" missed="5" covered="0"/>
<counter type="INSTRUCTION" missed="2" covered="0"/>
<counter type="BRANCH" missed="0" covered="0"/>
<counter type="LINE" missed="2" covered="0"/>
<counter type="LINE" missed="1" covered="0"/>
</sourcefile>
<sourcefile name="LaunchPagingStore.kt">
<line nr="21" mi="0" ci="2" mb="0" cb="0"/>
Expand Down Expand Up @@ -449,10 +443,10 @@
<counter type="BRANCH" missed="11" covered="11"/>
<counter type="LINE" missed="0" covered="119"/>
</sourcefile>
<counter type="INSTRUCTION" missed="46" covered="1702"/>
<counter type="INSTRUCTION" missed="43" covered="1702"/>
<counter type="BRANCH" missed="17" covered="27"/>
<counter type="LINE" missed="4" covered="154"/>
<counter type="METHOD" missed="4" covered="27"/>
<counter type="LINE" missed="3" covered="154"/>
<counter type="METHOD" missed="3" covered="27"/>
<counter type="CLASS" missed="1" covered="19"/>
</package>
<package name="org/mobilenativefoundation/store/paging5/util">
Expand Down Expand Up @@ -1066,10 +1060,10 @@
<counter type="METHOD" missed="13" covered="37"/>
<counter type="CLASS" missed="11" covered="18"/>
</package>
<counter type="INSTRUCTION" missed="289" covered="2284"/>
<counter type="INSTRUCTION" missed="286" covered="2284"/>
<counter type="BRANCH" missed="45" covered="50"/>
<counter type="LINE" missed="41" covered="257"/>
<counter type="METHOD" missed="17" covered="64"/>
<counter type="LINE" missed="40" covered="257"/>
<counter type="METHOD" missed="16" covered="64"/>
<counter type="CLASS" missed="12" covered="37"/>
</report>

Original file line number Diff line number Diff line change
Expand Up @@ -201,16 +201,11 @@ internal class RealMutableStore<Key : Any, Network : Any, Output : Any, Local :
private suspend fun <Output : Any?> withThreadSafety(
key: Key,
block: suspend ThreadSafety.() -> Output,
): Output {
storeLock.lock()
try {
): Output =
storeLock.withLock {
val threadSafety = requireNotNull(keyToThreadSafety[key])
val output = threadSafety.block()
return output
} finally {
storeLock.unlock()
threadSafety.block()
}
}

private suspend fun conflictsMightExist(key: Key): Boolean {
val lastFailedSync = bookkeeper?.getLastFailedSync(key)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
package org.mobilenativefoundation.store.store5

import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.Job
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
import org.mobilenativefoundation.store.core5.ExperimentalStoreApi
import org.mobilenativefoundation.store.store5.impl.extensions.get
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertIs
import kotlin.test.assertNotNull
import kotlin.time.Duration.Companion.hours

@OptIn(ExperimentalStoreApi::class)
@FlowPreview
@ExperimentalCoroutinesApi
class StoreWithInMemoryCacheTests {
Expand Down Expand Up @@ -51,82 +49,86 @@ class StoreWithInMemoryCacheTests {

@Test
fun storeDeadlock() =
testScope.runTest {
repeat(1000) {
val store =
runTest {
repeat(100) {
val store: MutableStore<Int, String> =
StoreBuilder
.from(
fetcher = Fetcher.of { key: Int -> "fetcher_${key}" },
sourceOfTruth = SourceOfTruth.Companion.of(
reader = { key ->
flow<String> {
emit("source_of_truth_${key}")
}
},
writer = { key: Int, local: String ->

}
)
fetcher = Fetcher.of { key: Int -> "fetcher_$key" },
sourceOfTruth =
SourceOfTruth.of(
reader = { key: Int ->
flowOf("source_of_truth_$key")
},
writer = { key: Int, local: String -> },
),
)
.disableCache()
.toMutableStoreBuilder(
converter = object : Converter<String, String, String> {
override fun fromNetworkToLocal(network: String): String {
return network
}
converter =
object : Converter<String, String, String> {
override fun fromNetworkToLocal(network: String): String = network

override fun fromOutputToLocal(output: String): String {
return output
}
},
override fun fromOutputToLocal(output: String): String = output
},
)
.build(
updater = object : Updater<Int, String, Unit> {
var callCount = -1
override suspend fun post(key: Int, value: String): UpdaterResult {
callCount += 1
if (callCount % 2 == 0) {
throw IllegalArgumentException(key.toString() + "value:$value")
} else {
return UpdaterResult.Success.Untyped("")
}
}
updater =
object : Updater<Int, String, Unit> {
var callCount = -1

override val onCompletion: OnUpdaterCompletion<Unit>?
get() = null
override suspend fun post(
key: Int,
value: String,
): UpdaterResult {
callCount += 1
return if (callCount % 2 == 0) {
throw IllegalArgumentException("$key value: $value")
} else {
UpdaterResult.Success.Untyped("")
}
}

}
override val onCompletion: OnUpdaterCompletion<Unit>? = null
},
)

val jobs = mutableListOf<Job>()
jobs.add(
store.stream<Nothing>(StoreReadRequest.cached(1, refresh = true))
.mapNotNull { it.dataOrNull() }
.launchIn(CoroutineScope(Dispatchers.Default))
.launchIn(this),
)
val job1 = store.stream<Nothing>(StoreReadRequest.cached(0, refresh = true))
.mapNotNull { it.dataOrNull() }
.launchIn(CoroutineScope(Dispatchers.Default))
val job1 =
store.stream<Nothing>(StoreReadRequest.cached(0, refresh = true))
.mapNotNull { it.dataOrNull() }
.launchIn(this)
jobs.add(
store.stream<Nothing>(StoreReadRequest.cached(2, refresh = true))
.mapNotNull { it.dataOrNull() }
.launchIn(CoroutineScope(Dispatchers.Default)))
.launchIn(this),
)
jobs.add(
store.stream<Nothing>(StoreReadRequest.cached(3, refresh = true))
.mapNotNull { it.dataOrNull() }
.launchIn(CoroutineScope(Dispatchers.Default)))
.launchIn(this),
)
job1.cancel()
assertEquals(
expected = "source_of_truth_0",
actual = store.stream<Nothing>(StoreReadRequest.cached(0, refresh = true))
.mapNotNull { it.dataOrNull() }.first()
actual =
store.stream<Nothing>(StoreReadRequest.cached(0, refresh = true))
.mapNotNull { it.dataOrNull() }
.first(),
)
jobs.forEach {
it.cancel()
assertEquals(
expected = "source_of_truth_0",
actual = store.stream<Nothing>(StoreReadRequest.cached(0, refresh = true))
.mapNotNull { it.dataOrNull() }.first()
actual =
store.stream<Nothing>(StoreReadRequest.cached(0, refresh = true))
.mapNotNull { it.dataOrNull() }
.first(),
)
}
}
Expand Down
Loading