Skip to content

Commit bfc34c8

Browse files
authored
Move Junit5 test discovery to zinc worker (#6127)
Fixes #5708
1 parent ee470bc commit bfc34c8

File tree

8 files changed

+104
-41
lines changed

8 files changed

+104
-41
lines changed

libs/javalib/api/src/mill/javalib/api/JvmWorkerApi.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,9 @@ trait JvmWorkerApi {
5757
value: mill.javalib.api.internal.ZincGetTestTasks,
5858
javaHome: Option[os.Path]
5959
)(using ctx: JvmWorkerApi.Ctx): Seq[String] = Nil
60+
61+
def discoverJunit5Tests(
62+
value: mill.javalib.api.internal.ZincDiscoverJunit5Tests,
63+
javaHome: Option[os.Path]
64+
)(using ctx: JvmWorkerApi.Ctx): Seq[String] = Nil
6065
}

libs/javalib/api/src/mill/javalib/api/internal/zinc_operations.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,9 @@ case class ZincGetTestTasks(
4747
selectors: Seq[String],
4848
args: Seq[String]
4949
) derives upickle.ReadWriter
50+
51+
case class ZincDiscoverJunit5Tests(
52+
runCp: Seq[os.Path],
53+
testCp: Seq[os.Path],
54+
classesDir: Option[os.Path]
55+
) derives upickle.ReadWriter

libs/javalib/src/mill/javalib/TestModule.scala

Lines changed: 8 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import mill.api.Task
1010
import mill.api.TaskCtx
1111
import mill.api.DefaultTaskModule
1212
import mill.javalib.bsp.BspModule
13-
import mill.util.Jvm
1413
import mill.api.JsonFormatters.given
1514
import mill.constants.EnvVars
1615
import mill.javalib.api.internal.ZincDiscoverTests
@@ -390,46 +389,14 @@ object TestModule {
390389
* override this method.
391390
*/
392391
override def discoveredTestClasses: T[Seq[String]] = Task {
393-
Jvm.withClassLoader(
394-
classPath = runClasspath().map(_.path).toVector,
395-
sharedPrefixes = Seq("sbt.testing.", "mill.api.daemon.internal.TestReporter")
396-
) { classLoader =>
397-
val builderClass: Class[?] =
398-
classLoader.loadClass("com.github.sbt.junit.jupiter.api.JupiterTestCollector$Builder")
399-
val builder = builderClass.getConstructor().newInstance()
400-
401-
classesDir().foreach { path =>
402-
builderClass.getMethod("withClassDirectory", classOf[java.io.File]).invoke(
403-
builder,
404-
path.wrapped.toFile
405-
)
406-
}
407-
408-
builderClass.getMethod("withRuntimeClassPath", classOf[Array[java.net.URL]]).invoke(
409-
builder,
410-
testClasspath().map(_.path.toURL).toArray
411-
)
412-
builderClass.getMethod("withClassLoader", classOf[ClassLoader]).invoke(builder, classLoader)
413-
414-
val testCollector = builderClass.getMethod("build").invoke(builder)
415-
val testCollectorClass =
416-
classLoader.loadClass("com.github.sbt.junit.jupiter.api.JupiterTestCollector")
417-
418-
val result = testCollectorClass.getMethod("collectTests").invoke(testCollector)
419-
val resultClass =
420-
classLoader.loadClass("com.github.sbt.junit.jupiter.api.JupiterTestCollector$Result")
421-
422-
val items = resultClass.getMethod(
423-
"getDiscoveredTests"
424-
).invoke(result).asInstanceOf[java.util.List[?]]
425-
val itemClass =
426-
classLoader.loadClass("com.github.sbt.junit.jupiter.api.JupiterTestCollector$Item")
427-
428-
import scala.jdk.CollectionConverters._
429-
items.asScala.map { item =>
430-
itemClass.getMethod("getFullyQualifiedClassName").invoke(item).asInstanceOf[String]
431-
}.toSeq
432-
}
392+
jvmWorker().worker().discoverJunit5Tests(
393+
mill.javalib.api.internal.ZincDiscoverJunit5Tests(
394+
runClasspath().map(_.path),
395+
testClasspath().map(_.path),
396+
classesDir()
397+
),
398+
javaHome().map(_.path)
399+
)
433400
}
434401
}
435402

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package mill.javalib.testrunner
2+
3+
import mill.api.daemon.internal.internal
4+
5+
@internal object DiscoverJunit5TestsMain {
6+
7+
def apply(args0: mill.javalib.api.internal.ZincDiscoverJunit5Tests): Seq[String] = {
8+
import args0.*
9+
mill.util.Jvm.withClassLoader(
10+
classPath = runCp,
11+
sharedPrefixes = Seq("sbt.testing.")
12+
) { classLoader =>
13+
val builderClass: Class[?] =
14+
classLoader.loadClass("com.github.sbt.junit.jupiter.api.JupiterTestCollector$Builder")
15+
val builder = builderClass.getConstructor().newInstance()
16+
17+
classesDir.foreach { path =>
18+
builderClass.getMethod("withClassDirectory", classOf[java.io.File]).invoke(
19+
builder,
20+
path.wrapped.toFile
21+
)
22+
}
23+
24+
builderClass.getMethod("withRuntimeClassPath", classOf[Array[java.net.URL]]).invoke(
25+
builder,
26+
testCp.map(_.toURL).toArray
27+
)
28+
builderClass.getMethod("withClassLoader", classOf[ClassLoader]).invoke(builder, classLoader)
29+
30+
val testCollector = builderClass.getMethod("build").invoke(builder)
31+
val testCollectorClass =
32+
classLoader.loadClass("com.github.sbt.junit.jupiter.api.JupiterTestCollector")
33+
34+
val result = testCollectorClass.getMethod("collectTests").invoke(testCollector)
35+
val resultClass =
36+
classLoader.loadClass("com.github.sbt.junit.jupiter.api.JupiterTestCollector$Result")
37+
38+
val items = resultClass.getMethod(
39+
"getDiscoveredTests"
40+
).invoke(result).asInstanceOf[java.util.List[?]]
41+
val itemClass =
42+
classLoader.loadClass("com.github.sbt.junit.jupiter.api.JupiterTestCollector$Item")
43+
44+
import scala.jdk.CollectionConverters._
45+
items.asScala.map { item =>
46+
itemClass.getMethod("getFullyQualifiedClassName").invoke(item).asInstanceOf[String]
47+
}.toSeq
48+
}
49+
}
50+
}

libs/javalib/worker/src/mill/javalib/worker/JvmWorkerImpl.scala

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,18 @@ class JvmWorkerImpl(args: JvmWorkerArgs) extends JvmWorkerApi with AutoCloseable
111111
result.result
112112
}
113113

114+
override def discoverJunit5Tests(
115+
op: mill.javalib.api.internal.ZincDiscoverJunit5Tests,
116+
javaHome: Option[os.Path]
117+
)(using ctx: JvmWorkerApi.Ctx): Seq[String] = {
118+
given RequestId = requestIds.next()
119+
120+
val zinc = zincApi(javaHome, JavaRuntimeOptions(Seq.empty))
121+
val result = Timed(zinc.discoverJunit5Tests(op))
122+
fileLog(s"discoverJunit5Tests took ${result.durationPretty}")
123+
result.result
124+
}
125+
114126
override def close(): Unit = {
115127
zincLocalWorker.close()
116128
subprocessCache.close()
@@ -450,6 +462,14 @@ class JvmWorkerImpl(args: JvmWorkerArgs) extends JvmWorkerApi with AutoCloseable
450462
rpcClient(msg)
451463
}
452464
}
465+
466+
override def discoverJunit5Tests(op: mill.javalib.api.internal.ZincDiscoverJunit5Tests)
467+
: Seq[String] = {
468+
withRpcClient(serverRpcToClientHandler(reporter = None, log, cacheKey)) { rpcClient =>
469+
val msg = ZincWorkerRpcServer.ClientToServer.DiscoverJunit5Tests(op)
470+
rpcClient(msg)
471+
}
472+
}
453473
}
454474
}
455475

libs/javalib/worker/src/mill/javalib/zinc/ZincApi.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,6 @@ trait ZincApi {
3030
def discoverTests(value: mill.javalib.api.internal.ZincDiscoverTests): Seq[String]
3131

3232
def getTestTasks(value: mill.javalib.api.internal.ZincGetTestTasks): Seq[String]
33+
34+
def discoverJunit5Tests(value: mill.javalib.api.internal.ZincDiscoverJunit5Tests): Seq[String]
3335
}

libs/javalib/worker/src/mill/javalib/zinc/ZincWorker.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,10 @@ class ZincWorker(jobs: Int) extends AutoCloseable { self =>
308308

309309
override def getTestTasks(op: mill.javalib.api.internal.ZincGetTestTasks): Seq[String] =
310310
mill.javalib.testrunner.GetTestTasksMain(op)
311+
312+
override def discoverJunit5Tests(op: mill.javalib.api.internal.ZincDiscoverJunit5Tests)
313+
: Seq[String] =
314+
mill.javalib.testrunner.DiscoverJunit5TestsMain(op)
311315
}
312316

313317
def close(): Unit = {

libs/javalib/worker/src/mill/javalib/zinc/ZincWorkerRpcServer.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,10 @@ class ZincWorkerRpcServer(
102102
mill.javalib.testrunner.DiscoverTestsMain(msg.value).asInstanceOf[input.Response]
103103
case msg: ClientToServer.GetTestTasks =>
104104
mill.javalib.testrunner.GetTestTasksMain(msg.value).asInstanceOf[input.Response]
105+
case msg: ClientToServer.DiscoverJunit5Tests =>
106+
mill.javalib.testrunner.DiscoverJunit5TestsMain(
107+
msg.value
108+
).asInstanceOf[input.Response]
105109
}
106110
}
107111
writeToLocalLog(s"$requestId with data $input processed in ${result.durationPretty}")
@@ -197,6 +201,11 @@ object ZincWorkerRpcServer {
197201
) extends ClientToServer {
198202
override type Response = Seq[String]
199203
}
204+
case class DiscoverJunit5Tests(
205+
value: mill.javalib.api.internal.ZincDiscoverJunit5Tests
206+
) extends ClientToServer {
207+
override type Response = Seq[String]
208+
}
200209

201210
}
202211

0 commit comments

Comments
 (0)