Skip to content

eng: update a comment, unit test for better clarity about why the start = Lazy #5226

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

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ internal class AsyncCache<K, V> {
val deferred = mutex.withLock {
var cached = cache[key]
if (cached == null || cached.isCancelled) {
//LAZY - to free the mutex lock as fast as possible
// LAZY - to release the mutex as quickly as possible and defer the work
cached = async(start = CoroutineStart.LAZY) { load() }
cache[key] = cached
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Copyright 2020-2024 JetBrains s.r.o. and respective authors and developers.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file.
*/

package org.jetbrains.compose.resources

import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.delay
import kotlinx.coroutines.test.runTest
import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.assertEquals

class AsyncCacheTest {

private lateinit var cache: AsyncCache<String, String>

@BeforeTest
fun setup() {
cache = AsyncCache()
}

@Test
fun `test cache stores and retrieves value`() = runTest {
val key = "testKey"
val expectedValue = "Hello, World!"

val value = cache.getOrLoad(key) { expectedValue }

assertEquals(expectedValue, value)
}

@Test
fun `test cache returns same instance for same key`() = runTest {
val key = "testKey"
var loadCount = 0

val firstLoad = cache.getOrLoad(key) {
loadCount++
"Hello"
}
val secondLoad = cache.getOrLoad(key) { "NewValue" }

assertEquals("Hello", firstLoad)
assertEquals("Hello", secondLoad)
assertEquals(1, loadCount) // Ensures the load function runs only once
}

@Test
fun `test concurrent access to cache`() = runTest {
val key = "testKey"
var loadCount = 0

coroutineScope {
repeat(10) {
launch {
cache.getOrLoad(key) {
delay(100) // Simulate work
loadCount++
"Concurrent Value"
}
}
}
}

assertEquals(1, loadCount) // Ensures only one load operation happened
}

@Test
fun `test cache invalidation on clear`() = runTest {
val key = "testKey"

cache.getOrLoad(key) { "InitialValue" }
cache.clear()

val newValue = cache.getOrLoad(key) { "NewValue" }

assertEquals("NewValue", newValue)
}
}