Skip to content

Commit

Permalink
Add back test
Browse files Browse the repository at this point in the history
Signed-off-by: matt-ramotar <[email protected]>
  • Loading branch information
matt-ramotar committed Oct 18, 2024
1 parent a7aeb50 commit 175dd6a
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 25 deletions.
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
Expand Up @@ -2,13 +2,20 @@ package org.mobilenativefoundation.store.store5

import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.Job
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.time.Duration.Companion.hours

@OptIn(ExperimentalStoreApi::class)
@FlowPreview
@ExperimentalCoroutinesApi
class StoreWithInMemoryCacheTests {
Expand Down Expand Up @@ -39,4 +46,91 @@ class StoreWithInMemoryCacheTests {
assertEquals("result", c)
assertEquals("result", d)
}

@Test
fun storeDeadlock() =
runTest {
repeat(100) {
val store: MutableStore<Int, String> =
StoreBuilder
.from(
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 = network

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
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(this),
)
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(this),
)
jobs.add(
store.stream<Nothing>(StoreReadRequest.cached(3, refresh = true))
.mapNotNull { it.dataOrNull() }
.launchIn(this),
)
job1.cancel()
assertEquals(
expected = "source_of_truth_0",
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(),
)
}
}
}
}

0 comments on commit 175dd6a

Please sign in to comment.