From eeeb4c9ff2e047599b9bbc83a1dcd8951cf9ddad Mon Sep 17 00:00:00 2001 From: OlegYch Date: Mon, 23 Apr 2018 20:46:08 +0300 Subject: [PATCH] Remove usage of DynamicVariable and fix memory leak, fixes https://github.com/sbt/sbt/issues/4112 --- build.sbt | 2 ++ .../scala/sbt/JUnitXmlTestsListener.scala | 23 ++++++++++++------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/build.sbt b/build.sbt index 5baf26bfc..c1e10290a 100644 --- a/build.sbt +++ b/build.sbt @@ -220,6 +220,8 @@ lazy val testingProj = (project in file("testing")) exclude[DirectMissingMethodProblem]("sbt.protocol.testing.TestItemEvent.copy$default$*"), exclude[DirectMissingMethodProblem]("sbt.protocol.testing.TestStringEvent.copy"), exclude[DirectMissingMethodProblem]("sbt.protocol.testing.TestStringEvent.copy$default$1"), + //no reason to use + exclude[DirectMissingMethodProblem]("sbt.JUnitXmlTestsListener.testSuite"), ) ) .configure(addSbtIO, addSbtCompilerClasspath, addSbtUtilLogging) diff --git a/testing/src/main/scala/sbt/JUnitXmlTestsListener.scala b/testing/src/main/scala/sbt/JUnitXmlTestsListener.scala index 3e62dcea2..29a4ebc8c 100644 --- a/testing/src/main/scala/sbt/JUnitXmlTestsListener.scala +++ b/testing/src/main/scala/sbt/JUnitXmlTestsListener.scala @@ -12,7 +12,6 @@ import java.net.InetAddress import java.util.Hashtable import scala.collection.mutable.ListBuffer -import scala.util.DynamicVariable import scala.xml.{ Elem, Node => XNode, XML } import testing.{ Event => TEvent, @@ -124,21 +123,28 @@ class JUnitXmlTestsListener(val outputDir: String) extends TestsListener { } /**The currently running test suite*/ - val testSuite = new DynamicVariable(null: TestSuite) + private val testSuite = new InheritableThreadLocal[Option[TestSuite]] { + override def initialValue(): Option[TestSuite] = None + } + + private def withTestSuite[T](f: TestSuite => T) = + testSuite.get().map(f).getOrElse(sys.error("no test suite")) /**Creates the output Dir*/ - override def doInit() = { targetDir.mkdirs() } + override def doInit() = { + val _ = targetDir.mkdirs() + } /** * Starts a new, initially empty Suite with the given name. */ - override def startGroup(name: String): Unit = testSuite.value_=(new TestSuite(name)) + override def startGroup(name: String): Unit = testSuite.set(Some(new TestSuite(name))) /** * Adds all details for the given even to the current suite. */ override def testEvent(event: TestEvent): Unit = for (e <- event.detail) { - testSuite.value.addEvent(e) + withTestSuite(_.addEvent(e)) } /** @@ -174,7 +180,7 @@ class JUnitXmlTestsListener(val outputDir: String) extends TestsListener { def selector = null def throwable = new OptionalThrowable(t) } - testSuite.value.addEvent(event) + withTestSuite(_.addEvent(event)) writeSuite() } @@ -191,10 +197,11 @@ class JUnitXmlTestsListener(val outputDir: String) extends TestsListener { private[this] def normalizeName(s: String) = s.replaceAll("""\s+""", "-") private def writeSuite() = { - val file = new File(targetDir, s"${normalizeName(testSuite.value.name)}.xml").getAbsolutePath + val file = new File(targetDir, s"${normalizeName(withTestSuite(_.name))}.xml").getAbsolutePath // TODO would be nice to have a logger and log this with level debug // System.err.println("Writing JUnit XML test report: " + file) - XML.save(file, testSuite.value.stop(), "UTF-8", true, null) + XML.save(file, withTestSuite(_.stop()), "UTF-8", true, null) + testSuite.remove() } /**Does nothing, as we write each file after a suite is done.*/