|
1 | 1 | /*
|
2 |
| - * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. |
| 2 | + * Copyright 2016-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. |
3 | 3 | */
|
4 | 4 |
|
5 | 5 | package kotlinx.coroutines.future
|
@@ -264,11 +264,9 @@ class FutureTest : TestBase() {
|
264 | 264 | try {
|
265 | 265 | deferred.await()
|
266 | 266 | fail("deferred.await() should throw an exception")
|
267 |
| - } catch (e: CompletionException) { |
| 267 | + } catch (e: TestException) { |
268 | 268 | assertTrue(deferred.isCancelled)
|
269 |
| - val cause = e.cause?.cause!! // Stacktrace augmentation |
270 |
| - assertTrue(cause is TestException) |
271 |
| - assertEquals("something went wrong", cause.message) |
| 269 | + assertEquals("something went wrong", e.message) |
272 | 270 | }
|
273 | 271 | }
|
274 | 272 |
|
@@ -437,6 +435,45 @@ class FutureTest : TestBase() {
|
437 | 435 | }
|
438 | 436 | }
|
439 | 437 |
|
| 438 | + /** |
| 439 | + * Tests that both [CompletionStage.await] and [CompletionStage.asDeferred] consistently unwrap |
| 440 | + * [CompletionException] both in their slow and fast paths. |
| 441 | + * See [issue #1479](https://github.com/Kotlin/kotlinx.coroutines/issues/1479). |
| 442 | + */ |
| 443 | + @Test |
| 444 | + fun testConsistentExceptionUnwrapping() = runTest { |
| 445 | + expect(1) |
| 446 | + // Check the fast path |
| 447 | + val fFast = CompletableFuture.supplyAsync { |
| 448 | + expect(2) |
| 449 | + throw TestException() |
| 450 | + } |
| 451 | + fFast.checkFutureException<TestException>() // wait until it completes |
| 452 | + // Fast path in await and asDeferred.await() shall produce TestException |
| 453 | + expect(3) |
| 454 | + val dFast = fFast.asDeferred() |
| 455 | + assertFailsWith<TestException> { fFast.await() } |
| 456 | + assertFailsWith<TestException> { dFast.await() } |
| 457 | + // Same test, but future has not completed yet, check the slow path |
| 458 | + expect(4) |
| 459 | + val barrier = CyclicBarrier(2) |
| 460 | + val fSlow = CompletableFuture.supplyAsync { |
| 461 | + barrier.await() |
| 462 | + expect(6) |
| 463 | + throw TestException() |
| 464 | + } |
| 465 | + val dSlow = fSlow.asDeferred() |
| 466 | + launch(start = CoroutineStart.UNDISPATCHED) { |
| 467 | + expect(5) |
| 468 | + // Slow path on await shall produce TestException, too |
| 469 | + assertFailsWith<TestException> { fSlow.await() } // will suspend here |
| 470 | + assertFailsWith<TestException> { dSlow.await() } |
| 471 | + finish(7) |
| 472 | + } |
| 473 | + barrier.await() |
| 474 | + fSlow.checkFutureException<TestException>() // now wait until it completes |
| 475 | + } |
| 476 | + |
440 | 477 | private inline fun <reified T: Throwable> CompletableFuture<*>.checkFutureException(vararg suppressed: KClass<out Throwable>) {
|
441 | 478 | val e = assertFailsWith<ExecutionException> { get() }
|
442 | 479 | val cause = e.cause!!
|
|
0 commit comments