diff --git a/libraries/stdlib/test/concurrent/TimerTest.kt b/libraries/stdlib/test/concurrent/TimerTest.kt index 3e4009f1098..1c79b7d43dc 100644 --- a/libraries/stdlib/test/concurrent/TimerTest.kt +++ b/libraries/stdlib/test/concurrent/TimerTest.kt @@ -1,26 +1,32 @@ @file:kotlin.jvm.JvmVersion package test.concurrent +import java.util.* import kotlin.concurrent.* import kotlin.test.* -import java.util.concurrent.atomic.AtomicInteger -import java.util.Timer +import java.util.concurrent.CountDownLatch +import java.util.concurrent.TimeUnit +import java.util.concurrent.TimeoutException class TimerTest { @Test fun scheduledTask() { - val counter = AtomicInteger(0) val timer = Timer() - val task = timer.scheduleAtFixedRate(1000, 100) { - val current = counter.incrementAndGet() - if (false) println("Timer fired at $current") + val latch = CountDownLatch(10) + val startedAt = System.nanoTime() + lateinit var callbackTask: TimerTask + val task = timer.scheduleAtFixedRate(100, 10) { + callbackTask = this + latch.countDown() + if (latch.count == 0L) this.cancel() } - Thread.sleep(1500) - task.cancel() + if (!latch.await(1500, TimeUnit.MILLISECONDS)) throw TimeoutException() + val elapsed = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startedAt) - val value = counter.get() - assertTrue(value >= 4, "Expected to fire at least 4 times, but was $value") + val expectedRange = 100L..500L + assertTrue(elapsed in expectedRange, "Expected elapsed ($elapsed ms) to fit in range $expectedRange") + assertSame(task, callbackTask) } } \ No newline at end of file diff --git a/libraries/stdlib/test/utils/KotlinVersionTest.kt b/libraries/stdlib/test/utils/KotlinVersionTest.kt index 39b3ef847bc..71d55f625fe 100644 --- a/libraries/stdlib/test/utils/KotlinVersionTest.kt +++ b/libraries/stdlib/test/utils/KotlinVersionTest.kt @@ -60,7 +60,7 @@ class KotlinVersionTest { val random = java.util.Random() fun randomComponent(): Int = random.nextInt(KotlinVersion.MAX_COMPONENT_VALUE + 1) fun randomVersion() = KotlinVersion(randomComponent(), randomComponent(), randomComponent()) - repeat(10000) { + repeat(1000) { val v1 = randomVersion() val v2 = randomVersion() if (v1.isAtLeast(v2.major, v2.minor, v2.patch)) diff --git a/libraries/stdlib/test/utils/LazyJVMTest.kt b/libraries/stdlib/test/utils/LazyJVMTest.kt index 0c638d9ae26..e6a2668b9cc 100644 --- a/libraries/stdlib/test/utils/LazyJVMTest.kt +++ b/libraries/stdlib/test/utils/LazyJVMTest.kt @@ -4,11 +4,13 @@ package test.utils import kotlin.* import kotlin.test.* -import java.io.* import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.atomic.AtomicInteger import kotlin.concurrent.thread import test.io.serializeAndDeserialize +import java.util.* +import java.util.concurrent.ConcurrentLinkedQueue +import java.util.concurrent.atomic.AtomicBoolean class LazyJVMTest { @@ -16,11 +18,12 @@ class LazyJVMTest { val counter = AtomicInteger(0) val lazy = lazy { val value = counter.incrementAndGet() - Thread.sleep(100) + Thread.sleep(80) value } - val accessThreads = listOf(lazy, lazy).map { thread { it.value } } + val accessThreads = List(3) { thread(start = false) { lazy.value } } + accessThreads.forEach { it.start() } accessThreads.forEach { it.join() } assertEquals(1, counter.get()) @@ -35,7 +38,7 @@ class LazyJVMTest { val initializer = { val value = counter.incrementAndGet() runs += (value to initialized) - Thread.sleep(100) + Thread.sleep(50) initialized = true value } @@ -54,26 +57,32 @@ class LazyJVMTest { @Test fun publishOnceLazy() { val counter = AtomicInteger(0) - var initialized: Boolean = false - val runs = ConcurrentHashMap() + val initialized = AtomicBoolean(false) + val threads = 3 + val values = Random().let { r -> List(threads) { 50 + r.nextInt(50) } } + data class Run(val id: Int, val value: Int, val initialized: Boolean) + val runs = ConcurrentLinkedQueue() val initializer = { - val value = counter.incrementAndGet() - runs += (value to initialized) - Thread.sleep((3 - value) * 100L) - initialized = true + val id = counter.getAndIncrement() + val value = values[id] + runs += Run(id, value, initialized.get()) + Thread.sleep(value.toLong()) + initialized.set(true) value } val lazy = lazy(LazyThreadSafetyMode.PUBLICATION, initializer) - val accessThreads = listOf(lazy, lazy).map { thread { it.value } } + val accessThreads = List(threads) { thread(start = false) { lazy.value } } + accessThreads.forEach { it.start() } + val result = run { while (!lazy.isInitialized()) /* wait */; lazy.value } accessThreads.forEach { it.join() } - assertEquals(2, counter.get()) - assertEquals(2, lazy.value) - @Suppress("NAME_SHADOWING") - for ((_, initialized) in runs) { - assertFalse(initialized, "Expected uninitialized on first and second run") + assertEquals(threads, counter.get()) + assertEquals(result, lazy.value, "Value must not change after isInitialized is set: $lazy, runs: $runs") + + runs.forEach { + assertFalse(it.initialized, "Expected uninitialized on all initializer executions, runs: $runs") } }