Skip to content

Commit

Permalink
Merge pull request #3969 from durban/testCancel
Browse files Browse the repository at this point in the history
Attempt to cancel the running test in case of a timeout
  • Loading branch information
djspiewak authored Jan 26, 2024
2 parents 6320ad7 + c14bdd7 commit 8930ffd
Showing 1 changed file with 23 additions and 7 deletions.
30 changes: 23 additions & 7 deletions tests/shared/src/test/scala/cats/effect/Runners.scala
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ trait Runners extends SpecificationLike with TestInstances with RunnersPlatform
Execution.result(test(Ticker(TestContext())))

def real[A: AsResult](test: => IO[A]): Execution =
Execution.withEnvAsync(_ => timeout(test.unsafeToFuture()(runtime()), executionTimeout))
Execution.withEnvAsync { _ =>
val (fut, cancel) = test.unsafeToFutureCancelable()(runtime())
timeout(fut, cancel, executionTimeout)
}

/*
* Hacky implementation of effectful property testing
Expand All @@ -53,7 +56,8 @@ trait Runners extends SpecificationLike with TestInstances with RunnersPlatform
def realWithRuntime[A: AsResult](test: IORuntime => IO[A]): Execution =
Execution.withEnvAsync { _ =>
val rt = runtime()
timeout(test(rt).unsafeToFuture()(rt), executionTimeout)
val (fut, cancel) = test(rt).unsafeToFutureCancelable()(rt)
timeout(fut, cancel, executionTimeout)
}

def completeAs[A: Eq: Show](expected: A)(implicit ticker: Ticker): Matcher[IO[A]] =
Expand Down Expand Up @@ -100,17 +104,29 @@ trait Runners extends SpecificationLike with TestInstances with RunnersPlatform
def mustEqual(a: A) = fa.flatMap { res => IO(res must beEqualTo(a)) }
}

private def timeout[A](f: Future[A], duration: FiniteDuration): Future[A] = {
private def timeout[A](
f: Future[A],
cancel: () => Future[Unit],
duration: FiniteDuration): Future[A] = {
val p = Promise[A]()
val r = runtime()
implicit val ec = r.compute

val cancel =
r.scheduler.sleep(duration, { () => p.tryFailure(new TestTimeoutException); () })
val cancelTimer =
r.scheduler
.sleep(
duration,
{ () =>
if (p.tryFailure(new TestTimeoutException)) {
cancel()
()
}
})

f.onComplete { result =>
p.tryComplete(result)
cancel.run()
if (p.tryComplete(result)) {
cancelTimer.run()
}
}

p.future
Expand Down

0 comments on commit 8930ffd

Please sign in to comment.