Skip to content
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

ExceptionInInitializerError causes test to hang for entire timeout #772

Open
armanbilge opened this issue Apr 23, 2024 · 8 comments
Open

Comments

@armanbilge
Copy link
Contributor

//> using dep org.scalameta::munit::1.0.0-M12

import munit.FunSuite
import scala.concurrent.Future
import scala.concurrent.ExecutionContext

object Dep {
  def attr: Boolean = true

  throw new IllegalArgumentException("boom")
}

final class InitSuite extends FunSuite {
  test("hanging") {
    Future(assert(Dep.attr))(ExecutionContext.global)
  }
}
java.lang.ExceptionInInitializerError
        at InitSuite.$init$$$anonfun$1$$anonfun$1$$anonfun$1(foo.test.scala:15)
        at munit.Assertions.munitCaptureClues(Assertions.scala:299)
        at munit.Assertions.munitCaptureClues$(Assertions.scala:15)
        at munit.FunSuite.munitCaptureClues(FunSuite.scala:11)
        at munit.Assertions.assert$$anonfun$1(Assertions.scala:30)
        at munit.Assertions.assert$$anonfun$adapted$1(Assertions.scala:34)
        at munit.internal.console.StackTraces$.dropInside(StackTraces.scala:10)
        at munit.Assertions.assert(Assertions.scala:34)
        at munit.Assertions.assert$(Assertions.scala:15)
        at munit.FunSuite.assert(FunSuite.scala:11)
        at InitSuite.$init$$$anonfun$1$$anonfun$1(foo.test.scala:15)
        at InitSuite.$init$$$anonfun$1$$anonfun$adapted$1(foo.test.scala:15)
        at scala.concurrent.Future$.$anonfun$apply$1(Future.scala:687)
        at scala.concurrent.impl.Promise$Transformation.run(Promise.scala:467)
        at java.base/java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1395)
        at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
        at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182)
        at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655)
        at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622)
        at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)
Caused by: java.lang.IllegalArgumentException: boom
        at Dep$.<clinit>(foo.test.scala:10)
        ... 20 more
InitSuite:
==> X InitSuite.hanging  30.01s java.util.concurrent.TimeoutException: test timed out after 30 seconds

h/t @milessabin

@armanbilge
Copy link
Contributor Author

Might be related to this.

// NOTE(olafur): these exceptions appear when we await on futures. We unwrap
// these exception in order to provide more helpful error messages.
@tailrec
def rootCause(x: Throwable): Throwable = x match {
case _: InvocationTargetException | _: ExceptionInInitializerError |
_: UndeclaredThrowableException | _: ExecutionException
if x.getCause != null =>
rootCause(x.getCause)
case _ => x
}

@milessabin
Copy link

I think the issue is here,

ec.execute(new Runnable {
def run(): Unit = {
startFuture().onComplete { result =>
onComplete.tryComplete(result)
timeout.foreach(_.cancel(false))
}(ec)
}
})

The ExceptionInInitializerError will escape the Try and so the timeout won't be cancelled.

@kitbellew
Copy link
Contributor

@armanbilge i can't repro in 1.0.4, is it still an issue?

@armanbilge
Copy link
Contributor Author

@kitbellew huh, that's interesting. I can still repro with 1.0.4. Are you using scala-cli or maybe some other way of running the test?

@kitbellew
Copy link
Contributor

@kitbellew huh, that's interesting. I can still repro with 1.0.4. Are you using scala-cli or maybe some other way of running the test?

I added this test as a suite to this repository and ran sbt testsJVM/test.

@armanbilge
Copy link
Contributor Author

I added this test as a suite to this repository

I see, would you mind pushing a branch / sharing a commit? I'll take a look.

@kitbellew
Copy link
Contributor

ok, turns out i was putting object Dep within the test (where it doesn't fail) and not at the file level (where it does).

so, here's the result: if you use munitExecutionContext, everything works. even if it's set to ExecutionContext.global at the test suite level.

however, if you ExecutionContext.global in your future only, I found no way to catch the exception, it's just not propagated anywhere.

here the exception is looked at but since it's not NonFatal, not handled.

so... i give up.

@milessabin
Copy link

I think this is a situation where NonFatal isn't the right choice, which in turn means that Try isn't the right thing to use here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants