From 446c38e57c35c4691bda991d9946d5ef32c38b3b Mon Sep 17 00:00:00 2001 From: Alejandro Serrano Date: Wed, 22 Dec 2021 16:59:50 +0100 Subject: [PATCH 1/5] Upgrade to kotlinx-coroutines 1.6.0 --- .../src/jvmTest/kotlin/arrow/fx/coroutines/FlowJvmTest.kt | 1 + gradle/libs.versions.toml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/arrow-libs/fx/arrow-fx-coroutines/src/jvmTest/kotlin/arrow/fx/coroutines/FlowJvmTest.kt b/arrow-libs/fx/arrow-fx-coroutines/src/jvmTest/kotlin/arrow/fx/coroutines/FlowJvmTest.kt index fd7ae9a5b8d..bfcfec5d811 100644 --- a/arrow-libs/fx/arrow-fx-coroutines/src/jvmTest/kotlin/arrow/fx/coroutines/FlowJvmTest.kt +++ b/arrow-libs/fx/arrow-fx-coroutines/src/jvmTest/kotlin/arrow/fx/coroutines/FlowJvmTest.kt @@ -14,6 +14,7 @@ import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.toList import kotlinx.coroutines.flow.toSet +import kotlinx.coroutines.test.currentTime import kotlinx.coroutines.test.runBlockingTest import kotlin.time.ExperimentalTime import kotlin.time.milliseconds diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b7d9409a654..257fbfe4150 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,7 +2,7 @@ animalSniffer = "1.5.0" arrowGradleConfig = "0.6.0-alpha.4" assertj = "3.21.0" -coroutines = "1.5.2" +coroutines = "1.6.0" classgraph = "4.8.137" dokka = "1.5.30" jUnit = "4.12" From 0cde75e9ec7389878d49a95e75eba12aa9d47df3 Mon Sep 17 00:00:00 2001 From: Simon Vergauwen Date: Wed, 22 Dec 2021 20:02:15 +0100 Subject: [PATCH 2/5] Rewrite Flow cancellation test --- .../kotlin/arrow/fx/coroutines/FlowTest.kt | 68 ++++++++----------- 1 file changed, 28 insertions(+), 40 deletions(-) diff --git a/arrow-libs/fx/arrow-fx-coroutines/src/commonTest/kotlin/arrow/fx/coroutines/FlowTest.kt b/arrow-libs/fx/arrow-fx-coroutines/src/commonTest/kotlin/arrow/fx/coroutines/FlowTest.kt index cb209dde436..b9b3ad17b24 100644 --- a/arrow-libs/fx/arrow-fx-coroutines/src/commonTest/kotlin/arrow/fx/coroutines/FlowTest.kt +++ b/arrow-libs/fx/arrow-fx-coroutines/src/commonTest/kotlin/arrow/fx/coroutines/FlowTest.kt @@ -5,10 +5,10 @@ import io.kotest.matchers.shouldBe import io.kotest.matchers.types.shouldBeTypeOf import io.kotest.property.Arb import io.kotest.property.arbitrary.int -import io.kotest.property.checkAll import io.kotest.property.arbitrary.positiveInts -import kotlinx.coroutines.CancellationException +import kotlin.time.ExperimentalTime import kotlinx.coroutines.CompletableDeferred +import kotlinx.coroutines.cancelAndJoin import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOf @@ -16,7 +16,6 @@ import kotlinx.coroutines.flow.reduce import kotlinx.coroutines.flow.toList import kotlinx.coroutines.flow.toSet import kotlinx.coroutines.launch -import kotlin.time.ExperimentalTime @ExperimentalTime class FlowTest : ArrowFxSpec( @@ -72,28 +71,22 @@ class FlowTest : ArrowFxSpec( } "parMap - triggers cancel signal" { - checkAll(Arb.int(), Arb.int(1..2)) { i, n -> + checkAll { val latch = CompletableDeferred() - val exit = CompletableDeferred>() + val exit = CompletableDeferred() - assertThrowable { - flowOf(1, 2).parMap { index -> - if (index == n) { - guaranteeCase({ - latch.complete(Unit) - never() - }, { ex -> exit.complete(Pair(i, ex)) }) - } else { - latch.await() - throw CancellationException(null, null) - } + val job = launch { + flowOf(1).parMap { index -> + guaranteeCase({ + latch.complete(Unit) + never() + }, { ex -> exit.complete(ex) }) }.collect() - fail("Cannot reach here. CancellationException should be thrown.") - }.shouldBeTypeOf() - - val (ii, ex) = exit.await() - ii shouldBe i - ex.shouldBeTypeOf() + } + latch.await() + job.cancelAndJoin() + job.isCancelled shouldBe true + exit.await().shouldBeTypeOf() } } @@ -175,28 +168,23 @@ class FlowTest : ArrowFxSpec( } "parMapUnordered - triggers cancel signal" { - checkAll(Arb.int(), Arb.int(1..2)) { i, n -> + checkAll { val latch = CompletableDeferred() - val exit = CompletableDeferred>() + val exit = CompletableDeferred() - assertThrowable { - flowOf(1, 2).parMapUnordered { index -> - if (index == n) { - guaranteeCase({ - latch.complete(Unit) - never() - }, { ex -> exit.complete(Pair(i, ex)) }) - } else { - latch.await() - throw CancellationException(null, null) - } + val job = launch { + flowOf(1).parMapUnordered { + guaranteeCase({ + latch.complete(Unit) + never() + }, { ex -> exit.complete(ex) }) }.collect() - fail("Cannot reach here. CancellationException should be thrown.") - }.shouldBeTypeOf() + } + latch.await() + job.cancelAndJoin() - val (ii, ex) = exit.await() - ii shouldBe i - ex.shouldBeTypeOf() + job.isCancelled shouldBe true + exit.await().shouldBeTypeOf() } } From 9a21aa5d8e79e5145f8a0d453e65bceaaa2be4c5 Mon Sep 17 00:00:00 2001 From: Simon Vergauwen Date: Wed, 22 Dec 2021 20:05:40 +0100 Subject: [PATCH 3/5] Use awaitCancellation --- .../kotlin/arrow/fx/coroutines/builders.kt | 6 ++++-- .../kotlin/arrow/fx/coroutines/FlowTest.kt | 13 +++++++------ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/arrow-libs/fx/arrow-fx-coroutines/src/commonMain/kotlin/arrow/fx/coroutines/builders.kt b/arrow-libs/fx/arrow-fx-coroutines/src/commonMain/kotlin/arrow/fx/coroutines/builders.kt index 938a0d33961..4acd577d018 100644 --- a/arrow-libs/fx/arrow-fx-coroutines/src/commonMain/kotlin/arrow/fx/coroutines/builders.kt +++ b/arrow-libs/fx/arrow-fx-coroutines/src/commonMain/kotlin/arrow/fx/coroutines/builders.kt @@ -1,8 +1,10 @@ package arrow.fx.coroutines -import kotlinx.coroutines.suspendCancellableCoroutine +import kotlinx.coroutines.awaitCancellation +// TODO deprecate? public suspend fun never(): A = - suspendCancellableCoroutine {} + awaitCancellation() +// TODO deprecate? public suspend fun unit(): Unit = Unit diff --git a/arrow-libs/fx/arrow-fx-coroutines/src/commonTest/kotlin/arrow/fx/coroutines/FlowTest.kt b/arrow-libs/fx/arrow-fx-coroutines/src/commonTest/kotlin/arrow/fx/coroutines/FlowTest.kt index b9b3ad17b24..44ffc09672c 100644 --- a/arrow-libs/fx/arrow-fx-coroutines/src/commonTest/kotlin/arrow/fx/coroutines/FlowTest.kt +++ b/arrow-libs/fx/arrow-fx-coroutines/src/commonTest/kotlin/arrow/fx/coroutines/FlowTest.kt @@ -8,6 +8,7 @@ import io.kotest.property.arbitrary.int import io.kotest.property.arbitrary.positiveInts import kotlin.time.ExperimentalTime import kotlinx.coroutines.CompletableDeferred +import kotlinx.coroutines.awaitCancellation import kotlinx.coroutines.cancelAndJoin import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.flow @@ -79,7 +80,7 @@ class FlowTest : ArrowFxSpec( flowOf(1).parMap { index -> guaranteeCase({ latch.complete(Unit) - never() + awaitCancellation() }, { ex -> exit.complete(ex) }) }.collect() } @@ -100,7 +101,7 @@ class FlowTest : ArrowFxSpec( if (index == n) { guaranteeCase({ latch.complete(Unit) - never() + awaitCancellation() }, { ex -> exit.complete(Pair(i, ex)) }) } else { latch.await() @@ -126,7 +127,7 @@ class FlowTest : ArrowFxSpec( flowOf(1, 2).parMap { index -> guaranteeCase({ if (index == 2) latch.complete(Unit) - never() + awaitCancellation() }, { ex -> if (index == 1) exitA.complete(Pair(i, ex)) else exitB.complete(Pair(i2, ex)) @@ -176,7 +177,7 @@ class FlowTest : ArrowFxSpec( flowOf(1).parMapUnordered { guaranteeCase({ latch.complete(Unit) - never() + awaitCancellation() }, { ex -> exit.complete(ex) }) }.collect() } @@ -198,7 +199,7 @@ class FlowTest : ArrowFxSpec( if (index == n) { guaranteeCase({ latch.complete(Unit) - never() + awaitCancellation() }, { ex -> exit.complete(Pair(i, ex)) }) } else { latch.await() @@ -224,7 +225,7 @@ class FlowTest : ArrowFxSpec( flowOf(1, 2).parMapUnordered { index -> guaranteeCase({ if (index == 2) latch.complete(Unit) - never() + awaitCancellation() }, { ex -> if (index == 1) exitA.complete(Pair(i, ex)) else exitB.complete(Pair(i2, ex)) From 7b7920647e7fab0f8bcf29f10e466a21aa13a93b Mon Sep 17 00:00:00 2001 From: Alejandro Serrano Date: Thu, 23 Dec 2021 09:43:52 +0100 Subject: [PATCH 4/5] Generate distinct values in test --- .../src/commonTest/kotlin/arrow/fx/stm/TMapTest.kt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/arrow-libs/fx/arrow-fx-stm/src/commonTest/kotlin/arrow/fx/stm/TMapTest.kt b/arrow-libs/fx/arrow-fx-stm/src/commonTest/kotlin/arrow/fx/stm/TMapTest.kt index f26a2b6181b..eef60daca27 100644 --- a/arrow-libs/fx/arrow-fx-stm/src/commonTest/kotlin/arrow/fx/stm/TMapTest.kt +++ b/arrow-libs/fx/arrow-fx-stm/src/commonTest/kotlin/arrow/fx/stm/TMapTest.kt @@ -4,8 +4,12 @@ import arrow.fx.coroutines.ArrowFxSpec import io.kotest.matchers.shouldBe import io.kotest.property.Arb import io.kotest.property.arbitrary.int -import io.kotest.property.arbitrary.pair +import io.kotest.property.arbitrary.list import io.kotest.property.arbitrary.map +import io.kotest.property.arbitrary.pair + +val distinctValuesList: Arb>> = + Arb.list(Arb.pair(Arb.int(), Arb.int())).map { it.distinctBy(Pair::component1) } class TMapTest : ArrowFxSpec( spec = { @@ -17,7 +21,7 @@ class TMapTest : ArrowFxSpec( } } "insert multiple values" { - checkAll(Arb.list(Arb.pair(Arb.int(), Arb.int())).map { it.distinct() }) { pairs -> + checkAll(distinctValuesList) { pairs -> val map = TMap.new() atomically { for ((k, v) in pairs) map.insert(k, v) @@ -28,7 +32,7 @@ class TMapTest : ArrowFxSpec( } } "insert multiple colliding values" { - checkAll(Arb.list(Arb.pair(Arb.int(), Arb.int()))) { pairs -> + checkAll(distinctValuesList) { pairs -> val map = TMap.new { 0 } // hash function that always returns 0 atomically { for ((k, v) in pairs) map.insert(k, v) From 5d1c812f725d11ef311a45d898bfa0786ec69e37 Mon Sep 17 00:00:00 2001 From: Alejandro Serrano Date: Thu, 23 Dec 2021 09:51:12 +0100 Subject: [PATCH 5/5] Generate map instead of list of distinct pairs --- .../src/commonTest/kotlin/arrow/fx/stm/TMapTest.kt | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/arrow-libs/fx/arrow-fx-stm/src/commonTest/kotlin/arrow/fx/stm/TMapTest.kt b/arrow-libs/fx/arrow-fx-stm/src/commonTest/kotlin/arrow/fx/stm/TMapTest.kt index eef60daca27..97bf982db01 100644 --- a/arrow-libs/fx/arrow-fx-stm/src/commonTest/kotlin/arrow/fx/stm/TMapTest.kt +++ b/arrow-libs/fx/arrow-fx-stm/src/commonTest/kotlin/arrow/fx/stm/TMapTest.kt @@ -4,12 +4,7 @@ import arrow.fx.coroutines.ArrowFxSpec import io.kotest.matchers.shouldBe import io.kotest.property.Arb import io.kotest.property.arbitrary.int -import io.kotest.property.arbitrary.list import io.kotest.property.arbitrary.map -import io.kotest.property.arbitrary.pair - -val distinctValuesList: Arb>> = - Arb.list(Arb.pair(Arb.int(), Arb.int())).map { it.distinctBy(Pair::component1) } class TMapTest : ArrowFxSpec( spec = { @@ -21,7 +16,7 @@ class TMapTest : ArrowFxSpec( } } "insert multiple values" { - checkAll(distinctValuesList) { pairs -> + checkAll(Arb.map(Arb.int(), Arb.int())) { pairs -> val map = TMap.new() atomically { for ((k, v) in pairs) map.insert(k, v) @@ -32,7 +27,7 @@ class TMapTest : ArrowFxSpec( } } "insert multiple colliding values" { - checkAll(distinctValuesList) { pairs -> + checkAll(Arb.map(Arb.int(), Arb.int())) { pairs -> val map = TMap.new { 0 } // hash function that always returns 0 atomically { for ((k, v) in pairs) map.insert(k, v)