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

Exception when running tests using ScalaTest #2595

Closed
ex0ns opened this issue Jun 10, 2023 · 28 comments · Fixed by #2612 or #2617
Closed

Exception when running tests using ScalaTest #2595

ex0ns opened this issue Jun 10, 2023 · 28 comments · Fixed by #2612 or #2617
Milestone

Comments

@ex0ns
Copy link

ex0ns commented Jun 10, 2023

When upgrading to mill 0.11.0 I got the following stack trace when trying to run my tests using scalatest

ex0ns@build:~/tmp$ mill  __.test
[82/83] core.test.test.super.mill.scalalib.TestModule.test 
java.lang.NoClassDefFoundError: sbt/testing/EventHandler
java.lang.NoClassDefFoundError: sbt/testing/EventHandler
        at mill.testrunner.TestRunnerMain0$.main0(TestRunnerMain0.scala:29)
        at mill.testrunner.TestRunnerMain0.main0(TestRunnerMain0.scala)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:568)
        at mill.testrunner.entrypoint.TestRunnerMain.main(TestRunnerMain.java:41)
Caused by: java.lang.ClassNotFoundException: sbt.testing.EventHandler
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
        at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
        at mill.testrunner.entrypoint.TestRunnerMain$1.findClass(TestRunnerMain.java:30)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:587)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
        ... 7 more

The minimized build.sc:

import mill._
import mill.scalalib._

object library {

  object Version {
    val scalaTest  = "3.2.16"
    val sbtTesting = "1.0"
  }

  val scalaTest  = ivy"org.scalatest::scalatest::${Version.scalaTest}"
  val sbtTesting = ivy"org.scala-sbt:test-interface:${Version.sbtTesting}"
}

object core extends ScalaModule {
  def scalaVersion = "2.13.11"

  object test extends ScalaTests with TestModule.ScalaTest {
    def ivyDeps = T {
      super.ivyDeps() ++ Agg(
        library.scalaTest
          // library.sbtTesting
      )
    }
  }
}

Adding test-interface explicitly fixes the issue, but I think that there must be something else going on here

@lolgab
Copy link
Member

lolgab commented Jun 11, 2023

It seems that there is a problem resolving transitive dependencies.
Since scalatest depends on scalatest-core which depends on test-interface already.
https://central.sonatype.com/artifact/org.scalatest/scalatest-core_2.13/3.2.16/dependencies

@ex0ns
Copy link
Author

ex0ns commented Jun 12, 2023

Side note (and probably expected), I get the exact same issue with a project running zio-test

@lefou
Copy link
Member

lefou commented Jun 12, 2023

Thanks for your report! This looks like a bug in Mill to me. We changed the way how we run tests and test frameworks. Instead of loading the test into a mostly isolated classloader hierarchy below the test runner, we now load the test runner into the tests class path. I guess, we might have overlooked something and need some more tweaking.

@lihaoyi
Copy link
Member

lihaoyi commented Jun 13, 2023

Yeah, that change aimed to run the tests in as clean a classpath as possible. Maybe we need to add org.scala-sbt:test-interface to TestModule.ScalaTest by default? From @lolgab's link, it seems like org.scala-sbt:test-interface should get pulled in automatically, but we must be missing something

@ex0ns
Copy link
Author

ex0ns commented Jun 13, 2023

I was trying to investigate why this was note the case, here is the runClassPath when I do not add scalatest as a dependency:

ex0ns@build:~/telegram/tmp$ mill show core.test.runClasspath
[1/1] show > [73/73] core.test.runClasspath 
[
  "ref:v0:c984eca8:/home/ex0ns/telegram/tmp/core/test/compile-resources",
  "ref:v0:c984eca8:/home/ex0ns/telegram/tmp/core/test/resources",
  "ref:v0:c984eca8:/home/ex0ns/telegram/tmp/out/core/test/compile.dest/classes",
  "ref:v0:c984eca8:/home/ex0ns/telegram/tmp/core/compile-resources",
  "ref:v0:c984eca8:/home/ex0ns/telegram/tmp/core/resources",
  "ref:v0:c984eca8:/home/ex0ns/telegram/tmp/out/core/compile.dest/classes",
  "qref:v1:df5c395d:/home/ex0ns/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.11/scala-library-2.13.11.jar"
]

And the same with Scalatest:

ex0ns@build:~/telegram/tmp$ mill show core.test.runClasspath
[1/1] show > [67/73] core.resources 
[
  "ref:v0:c984eca8:/home/ex0ns/telegram/tmp/core/test/compile-resources",
  "ref:v0:c984eca8:/home/ex0ns/telegram/tmp/core/test/resources",
  "ref:v0:9d39abea:/home/ex0ns/telegram/tmp/out/core/test/compile.dest/classes",
  "ref:v0:c984eca8:/home/ex0ns/telegram/tmp/core/compile-resources",
  "ref:v0:c984eca8:/home/ex0ns/telegram/tmp/core/resources",
  "ref:v0:c984eca8:/home/ex0ns/telegram/tmp/out/core/compile.dest/classes",
  "qref:v1:f43841ce:/home/ex0ns/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scalatest/scalatest_2.13/3.2.16/scalatest_2.13-3.2.16.jar",
  "qref:v1:df5c395d:/home/ex0ns/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.11/scala-library-2.13.11.jar",
  "qref:v1:79ae7013:/home/ex0ns/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scalatest/scalatest-core_2.13/3.2.16/scalatest-core_2.13-3.2.16.jar",
  "qref:v1:4173992a:/home/ex0ns/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scalatest/scalatest-featurespec_2.13/3.2.16/scalatest-featurespec_2.13-3.2.16.jar",
  "qref:v1:89daae4f:/home/ex0ns/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scalatest/scalatest-flatspec_2.13/3.2.16/scalatest-flatspec_2.13-3.2.16.jar",
  "qref:v1:a5af85f0:/home/ex0ns/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scalatest/scalatest-freespec_2.13/3.2.16/scalatest-freespec_2.13-3.2.16.jar",
  "qref:v1:05d94500:/home/ex0ns/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scalatest/scalatest-funsuite_2.13/3.2.16/scalatest-funsuite_2.13-3.2.16.jar",
  "qref:v1:5b8ebee5:/home/ex0ns/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scalatest/scalatest-funspec_2.13/3.2.16/scalatest-funspec_2.13-3.2.16.jar",
  "qref:v1:d0d9c0fc:/home/ex0ns/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scalatest/scalatest-propspec_2.13/3.2.16/scalatest-propspec_2.13-3.2.16.jar",
  "qref:v1:9afb4c96:/home/ex0ns/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scalatest/scalatest-refspec_2.13/3.2.16/scalatest-refspec_2.13-3.2.16.jar",
  "qref:v1:622010d9:/home/ex0ns/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scalatest/scalatest-wordspec_2.13/3.2.16/scalatest-wordspec_2.13-3.2.16.jar",
  "qref:v1:eb241cdc:/home/ex0ns/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scalatest/scalatest-diagrams_2.13/3.2.16/scalatest-diagrams_2.13-3.2.16.jar",
  "qref:v1:506ef7dc:/home/ex0ns/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scalatest/scalatest-matchers-core_2.13/3.2.16/scalatest-matchers-core_2.13-3.2.16.jar",
  "qref:v1:02b524d2:/home/ex0ns/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scalatest/scalatest-shouldmatchers_2.13/3.2.16/scalatest-shouldmatchers_2.13-3.2.16.jar",
  "qref:v1:9b35eea7:/home/ex0ns/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scalatest/scalatest-mustmatchers_2.13/3.2.16/scalatest-mustmatchers_2.13-3.2.16.jar",
  "qref:v1:7d3fb7c5:/home/ex0ns/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-reflect/2.13.11/scala-reflect-2.13.11.jar",
  "qref:v1:6f76a73d:/home/ex0ns/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scalatest/scalatest-compatible/3.2.16/scalatest-compatible-3.2.16.jar",
  "qref:v1:8158e172:/home/ex0ns/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scalactic/scalactic_2.13/3.2.16/scalactic_2.13-3.2.16.jar",
  "qref:v1:0172b928:/home/ex0ns/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/modules/scala-xml_2.13/2.1.0/scala-xml_2.13-2.1.0.jar"
]

No signs of test-interface in the list. As, as far as I could remember, mill is using coursier to resolve the dependencies, a quick check:

cs resolve -t  'org.scalatest::scalatest:3.2.16' | grep sbt
  Result:

No results for test-interface and this can be confirmed with a

cs resolve 'org.scalatest::scalatest::3.2.16' --what-depends-on org.scala-sbt:test-interface
  Result:

So somehow it seems that it's not detected as a dependency by coursier. And this could actually make sense, according to https://github.com/scalatest/scalatest/blob/d5f38074ea9057a0f56045f1bfd1f6eb2e24a782/project/scalatest.scala#L147 as it's marked as Optional.

Should we add it by default to the module that require it ? As far as I could test its needed for ZioTest and ScalaTest

@lefou
Copy link
Member

lefou commented Jun 13, 2023

As we clearly depend on test-interface, we should always add this dependency to the run classpath, when resolving the test runner.

@ex0ns
Copy link
Author

ex0ns commented Jun 13, 2023

I don't think I will have the time to contribute before the end of the week, however where would be the best place to include that ?
If I understood the problem correctly, we would need the runClasspath located

classPath = (runClasspath() ++ zincWorker().testrunnerEntrypointClasspath()).map(_.path),
to contain org.scala-sbt:test-interface is that the correct idea ?

@lefou
Copy link
Member

lefou commented Jun 13, 2023

Yeah, looks like the right location. As we work with already resolved classpaths, it's probably the good idea to pre-resolve the sbt-testing jars in a separate target and add it's result to the end. That way, we make sure test-interface is present, but if the runClasspath already contains one (which might be even newer) than that one is used.

@lihaoyi
Copy link
Member

lihaoyi commented Jun 13, 2023

If it's the Mill code in TestRunnetMain0 that depends on test-interface, shouldnt we just add the dependency to thay module in

mill/build.sc

Line 511 in e5a3990

object testrunner extends MillPublishScalaModule {
?

@lefou
Copy link
Member

lefou commented Jun 13, 2023

We should! (I was not sure whether our module loading mechanism can do that now.)

@lihaoyi
Copy link
Member

lihaoyi commented Jun 13, 2023

It should just work I think. Looking at the stack trace, it seems that the code path being exercised is within the classloader, which would contain the classpath from the mill testrunner module. Everything in there is hidden from user code anyway, so no need any further classpath fiddling

Unrelated, I wonder why our tests didn't catch this. Maybe Scalatest/ZIOtest exercise different code paths than uTest does

@lefou
Copy link
Member

lefou commented Jun 13, 2023

Probably, because the dependency is marked as optional. We should have a test case for each supported test framework.

@ex0ns
Copy link
Author

ex0ns commented Jun 14, 2023

So, a bit of news, I got some time to (try) adding tests for that, see #2609

Also, regarding @lihaoyi comments about the testrunner it seems that this is not the issue here (unless it was fix in between):

ex0ns@build:~/Projects/mill$ mill show testrunner.runClasspath | grep test-interface
[info] compiling 1 Scala source to /home/ex0ns/Projects/mill/out/mill-build/compile.dest/classes ...
[info] done compiling
  "qref:v1:3ed2ed17:/home/ex0ns/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-sbt/test-interface/1.0/test-interface-1.0.jar",

The jar is already in the class path for this

Do the tests looks good ? Should I continue with other tests framework ? I have added the libraries in the main build.sc so we get update when there is a new version of the test framework, is it a good idea or should we hardcode the values in the tests ?

Edit:
I have added the dependency directly in the TestModule in aaa9514 and this seems to work, I will test the other framework in the future

@lihaoyi
Copy link
Member

lihaoyi commented Jun 15, 2023

@ex0ns interesting. If the class is actually on the classpath, then the problem may well be on this line where we try and splice the classpaths together https://github.com/com-lihaoyi/mill/blob/main/testrunner/entrypoint/src/mill/testrunner/entrypoint/TestRunnerMain.java#L29

What that lines tries to do is to ensure that the classes in sbt.testing are shared between the testrunner classpath and the enclosing JVM classpath. It assumes the parent classpath contains the class, and so it directs the code running inside testrunner to load it from the parent classloader, rather than using it's own implementation. But as it turns out, it seems that many test frameworks do not include those classes in the parent JVM, and so the lookup fails even though the sub-classloader does contain the class

Two options include:

  1. Try to look up the class in the parent JVM classloader, but if that fails, then load the class from the testrunner classloader. Presumably if the parent JVM classloader does not include the class at all, then any concerns about sharing the class between parent and child classloaders is moot

  2. Always include the class in the parent JVM classloader. This can be done by adding it as an ivyDep to testrunner.entrypoint module here https://github.com/com-lihaoyi/mill/blob/main/build.sc#L512

Option (1) is probably the better one. We want to keep the parent JVM classloader as clean as possible, so as to ensure that the user test code is running in as realistic a classloading environment as possible. Option (2) is available as a fallback, but only if Option (1) doesn't work. Option (1) should work

@ex0ns
Copy link
Author

ex0ns commented Jun 15, 2023

I am not sure that I fully understand, are you talking about something like that:

if (name.startsWith("sbt.testing")) {
  try {
    return TestRunnerMain.class.getClassLoader().loadClass(name);
   catch (ClassNotFoundException e) {
     return super.findClass(name);
    }
 } else {

If yes, then we still have an issue, the stack trace went from:

java.lang.NoClassDefFoundError: sbt/testing/EventHandler
java.lang.NoClassDefFoundError: sbt/testing/EventHandler
        at mill.testrunner.TestRunnerMain0$.main0(TestRunnerMain0.scala:29)
        at mill.testrunner.TestRunnerMain0.main0(TestRunnerMain0.scala)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:568)
        at mill.testrunner.entrypoint.TestRunnerMain.main(TestRunnerMain.java:55)
Caused by: java.lang.ClassNotFoundException: sbt.testing.EventHandler
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
        at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
        at mill.testrunner.entrypoint.TestRunnerMain$1.findClass(TestRunnerMain.java:34)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:587)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
        ... 7 more

Failing in val filter = TestRunnerUtils.globFilter(testArgs.globSelectors)

With this try/catch, the stack trace become:

java.lang.NoClassDefFoundError: sbt/testing/Framework
java.lang.NoClassDefFoundError: sbt/testing/Framework
        at java.base/java.lang.ClassLoader.defineClass1(Native Method)
        at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1012)
        at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:150)
        at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:862)
        at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:760)
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:681)
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:639)
        at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
        at mill.testrunner.Framework$.framework(Framework.scala:9)
        at mill.testrunner.TestRunnerMain0$.$anonfun$main0$2(TestRunnerMain0.scala:33)
        at mill.testrunner.TestRunnerUtils$.runTestFramework0(TestRunnerUtils.scala:109)
        at mill.testrunner.TestRunnerMain0$.main0(TestRunnerMain0.scala:39)
        at mill.testrunner.TestRunnerMain0.main0(TestRunnerMain0.scala)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:568)
        at mill.testrunner.entrypoint.TestRunnerMain.main(TestRunnerMain.java:48)
Caused by: java.lang.ClassNotFoundException: sbt.testing.Framework
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
        at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
        ... 19 morejava.lang.NoClassDefFoundError: sbt/testing/Framework
java.lang.NoClassDefFoundError: sbt/testing/Framework
        at java.base/java.lang.ClassLoader.defineClass1(Native Method)
        at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1012)
        at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:150)
        at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:862)
        at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:760)
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:681)
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:639)
        at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
        at mill.testrunner.Framework$.framework(Framework.scala:9)
        at mill.testrunner.TestRunnerMain0$.$anonfun$main0$2(TestRunnerMain0.scala:33)
        at mill.testrunner.TestRunnerUtils$.runTestFramework0(TestRunnerUtils.scala:109)
        at mill.testrunner.TestRunnerMain0$.main0(TestRunnerMain0.scala:39)
        at mill.testrunner.TestRunnerMain0.main0(TestRunnerMain0.scala)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:568)
        at mill.testrunner.entrypoint.TestRunnerMain.main(TestRunnerMain.java:48)
Caused by: java.lang.ClassNotFoundException: sbt.testing.Framework
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
        at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
        ... 19 mor

Which is a failure inside TestRunnerUtils, when loading the framework

    val framework = frameworkInstances(cl)

Another question I had, is that maybe we should change the class loader that we provide to the following code:

mainMethod.invoke(null, args, TestRunnerMain.class.getClassLoader());

@lihaoyi
Copy link
Member

lihaoyi commented Jun 15, 2023

So with the try catch, even though the immediate failure goes away, we still have a failure later on. This is because the child classloader uses the parent classloader when trying to load the sbt.testing.Framework instances. This makes sense, as test frameworks are defined in the user classpath or even user code. And because the parent classloader does not have sbt.testing.* on the classpath, this fails.

I think we have no choice but to either add the test-interface dependency to testrunner.entrypoint, or add it to each of TestModule.ScalaTest, TestModule.ZIOTest, etc. that seem to have the dependency marked as optional. I don't have a strong opinion here which one is better, so either works for me

@lefou
Copy link
Member

lefou commented Jun 15, 2023

So with the try catch, even though the immediate failure goes away, we still have a failure later on. This is because the child classloader uses the parent classloader when trying to load the sbt.testing.Framework instances. This makes sense, as test frameworks are defined in the user classpath or even user code. And because the parent classloader does not have sbt.testing.* on the classpath, this fails.

I think we have no choice but to either add the test-interface dependency to testrunner.entrypoint, or add it to each of TestModule.ScalaTest, TestModule.ZIOTest, etc. that seem to have the dependency marked as optional. I don't have a strong opinion here which one is better, so either works for me

I'd prefer to add it to testrunner.entrypoint, as runIvyDeps if possible, or as ivyDeps otherwise. The reason is, that the customized classloading is located in this module and explicitly requests it's own classloader to load the sbt.testing classes, so this module clearly requires this dependency at runtime.

@lolgab
Copy link
Member

lolgab commented Jun 16, 2023

Also you can use scalatest by simply setting the def testFramework (without extending the TestModule.Scalatest trait) and only adding the dependency in TestModule.Scalatest would not fix the problem in this case.

@lefou
Copy link
Member

lefou commented Jun 16, 2023

@lefou lefou closed this as completed Jun 16, 2023
@lefou lefou reopened this Jun 16, 2023
@lefou
Copy link
Member

lefou commented Jun 16, 2023

[info] compiling 1 Scala source to /home/lefou/work/opensource/mill/target/workspace/mill/scalalib/TestRunnerTests/eval/TestRunner/ZioTest/ziotest.test/ziotest/compile.dest/classes ...
mill.scalalib.TestRunnerTests: [83/83] ziotest.test 
java.lang.ClassNotFoundException: zio.test.sbt.ZTestFramework
java.lang.ClassNotFoundException: zio.test.sbt.ZTestFramework
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
        at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
        at mill.testrunner.Framework$.framework(Framework.scala:9)
        at mill.testrunner.TestRunnerMain0$.$anonfun$main0$2(TestRunnerMain0.scala:32)
        at mill.testrunner.TestRunnerUtils$.runTestFramework0(TestRunnerUtils.scala:109)
        at mill.testrunner.TestRunnerMain0$.main0(TestRunnerMain0.scala:38)
        at mill.testrunner.TestRunnerMain0.main0(TestRunnerMain0.scala)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at mill.testrunner.entrypoint.TestRunnerMain.main(TestRunnerMain.java:42)
mill.scalalib.TestRunnerTests: [83/83] ziotest.test failed
X mill.scalalib.TestRunnerTests.TestRunner.ZioTest.ziotest.test 5377ms 
  scala.MatchError: Left(Failure(Test execution failed.,None)) (of class scala.util.Left)
    mill.scalalib.TestRunnerTests$.$anonfun$tests$23(TestRunnerTests.scala:102)
    mill.scalalib.TestRunnerTests$.$anonfun$tests$23$adapted(TestRunnerTests.scala:101)
    mill.scalalib.TestRunnerTests$.workspaceTest(TestRunnerTests.scala:53)
    mill.scalalib.TestRunnerTests$.$anonfun$tests$22(TestRunnerTests.scala:56)
1 targets failed
scalalib.test.testOnly 1 tests failed: 
  mill.scalalib.TestRunnerTests mill.scalalib.TestRunnerTests.TestRunner.ZioTest.ziotest.test

@lefou
Copy link
Member

lefou commented Jun 16, 2023

Looks like an additional artifact zio-test-sbt is needed.

@ex0ns
Copy link
Author

ex0ns commented Jun 16, 2023

oh you are correct, and this is documented on ZIO's side it seems: https://zio.dev/reference/test/installation so I guess we don't have to do anything specific about that (except what you did to fix the tests in the PR)

@lefou lefou added this to the 0.11.1 milestone Jun 16, 2023
@lefou
Copy link
Member

lefou commented Jun 16, 2023

I triggered a manual CI run (https://github.com/com-lihaoyi/mill/actions/runs/5290282018) to publish a new snapshot release 0.11.0-19-d4e35f.

@lefou
Copy link
Member

lefou commented Jun 17, 2023

I still see the same issue although I use the latest Mill snapshot release containing the fix.

https://github.com/lefou/mill-kotlin/actions/runs/5298466073/jobs/9590834819?pr=80

 java.lang.NoClassDefFoundError: sbt/testing/EventHandler
java.lang.NoClassDefFoundError: sbt/testing/EventHandler
	at mill.testrunner.TestRunnerMain0$.main0(TestRunnerMain0.scala:29)
	at mill.testrunner.TestRunnerMain0.main0(TestRunnerMain0.scala)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at mill.testrunner.entrypoint.TestRunnerMain.main(TestRunnerMain.java:42)
Caused by: java.lang.ClassNotFoundException: sbt.testing.EventHandler
	at java.net.URLClassLoader.findClass(URLClassLoader.java:387)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
	at mill.testrunner.entrypoint.TestRunnerMain$1.findClass(TestRunnerMain.java:31)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
	... 7 more
1 targets failed
main[0.10].test.test Test execution failed.

What am I missing? This is a scoverage enabled test module, so it could be relevant.

@lolgab
Copy link
Member

lolgab commented Jun 17, 2023

You are probably missing super.ivyDeps() ++ in https://github.com/lefou/mill-kotlin/blob/a553c6acaa4a7e9e100c162e84b756094ebede69/build.sc#L143
Should we use mandatoryIvyDeps for test-interface to avoid this problem?

@lefou
Copy link
Member

lefou commented Jun 17, 2023

I don't think that's the issue, as we always add the entrypoint classpath.

classPath = (runClasspath() ++ zincWorker().testrunnerEntrypointClasspath()).map(_.path),

@lefou
Copy link
Member

lefou commented Jun 17, 2023

But I currently wonder, whether there is a difference regarding the runtime-dependency handling from within Mill tests vs. when running standalone.

@lefou
Copy link
Member

lefou commented Jun 17, 2023

Yeah, looks like that makes the difference.

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