From 9eb32a4486ee3583b79dad32d0a43fabef0161ba Mon Sep 17 00:00:00 2001 From: Patrik Nordwall Date: Fri, 17 Jan 2014 15:52:20 +0100 Subject: [PATCH] =act #3738 Fix memory leaks in tests * afterAll not called when all tests marked as ignore, invokeBeforeAllAndAfterAllEvenIfNoTestsAreExpected = true should solve that, but changed to pending in Ticket1978 anyway * Try to shutdown when ActorSystem init fails. It is difficult to cover all scenarios, but this should improve the situation. This was the reason why DeployerSpec leaked. * missing shutdown in some tests --- .../src/main/scala/akka/actor/ActorSystem.scala | 16 +++++++++++++--- .../scala/akka/camel/ProducerFeatureTest.scala | 2 +- .../persistence/PersistencePluginDocSpec.scala | 11 ++++++++--- .../PersistenceSerializerDocSpec.scala | 11 ++++++++--- .../remote/Ticket1978CommunicationSpec.scala | 4 ++-- .../src/test/scala/akka/testkit/AkkaSpec.scala | 2 ++ 6 files changed, 34 insertions(+), 12 deletions(-) diff --git a/akka-actor/src/main/scala/akka/actor/ActorSystem.scala b/akka-actor/src/main/scala/akka/actor/ActorSystem.scala index 3840415309..33b9696375 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorSystem.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorSystem.scala @@ -18,7 +18,7 @@ import scala.annotation.tailrec import scala.collection.immutable import scala.concurrent.duration.{ FiniteDuration, Duration } import scala.concurrent.{ Await, Awaitable, CanAwait, Future, ExecutionContext, ExecutionContextExecutor } -import scala.util.{ Failure, Success } +import scala.util.{ Failure, Success, Try } import scala.util.control.{ NonFatal, ControlThrowable } object ActorSystem { @@ -568,7 +568,7 @@ private[akka] class ActorSystemImpl(val name: String, applicationConfig: Config, val scheduler: Scheduler = createScheduler() - val provider: ActorRefProvider = { + val provider: ActorRefProvider = try { val arguments = Vector( classOf[String] -> name, classOf[Settings] -> settings, @@ -576,6 +576,10 @@ private[akka] class ActorSystemImpl(val name: String, applicationConfig: Config, classOf[DynamicAccess] -> dynamicAccess) dynamicAccess.createInstanceFor[ActorRefProvider](ProviderClass, arguments).get + } catch { + case NonFatal(e) ⇒ + Try(stopScheduler()) + throw e } def deadLetters: ActorRef = provider.deadLetters @@ -602,7 +606,7 @@ private[akka] class ActorSystemImpl(val name: String, applicationConfig: Config, def /(actorName: String): ActorPath = guardian.path / actorName def /(path: Iterable[String]): ActorPath = guardian.path / path - private lazy val _start: this.type = { + private lazy val _start: this.type = try { // the provider is expected to start default loggers, LocalActorRefProvider does this provider.init(this) if (settings.LogDeadLetters > 0) @@ -611,6 +615,12 @@ private[akka] class ActorSystemImpl(val name: String, applicationConfig: Config, loadExtensions() if (LogConfigOnStart) logConfiguration() this + } catch { + case NonFatal(e) ⇒ + try { + shutdown() + } catch { case NonFatal(_) ⇒ Try(stopScheduler()) } + throw e } def start(): this.type = _start diff --git a/akka-camel/src/test/scala/akka/camel/ProducerFeatureTest.scala b/akka-camel/src/test/scala/akka/camel/ProducerFeatureTest.scala index 57177404d8..27f06b745c 100644 --- a/akka-camel/src/test/scala/akka/camel/ProducerFeatureTest.scala +++ b/akka-camel/src/test/scala/akka/camel/ProducerFeatureTest.scala @@ -24,7 +24,7 @@ import akka.actor.Status.Failure /** * Tests the features of the Camel Producer. */ -class ProducerFeatureTest extends TestKit(ActorSystem("test", AkkaSpec.testConf)) with WordSpecLike with BeforeAndAfterAll with BeforeAndAfterEach with Matchers { +class ProducerFeatureTest extends TestKit(ActorSystem("ProducerFeatureTest", AkkaSpec.testConf)) with WordSpecLike with BeforeAndAfterAll with BeforeAndAfterEach with Matchers { import ProducerFeatureTest._ implicit def camel = CamelExtension(system) diff --git a/akka-docs/rst/scala/code/docs/persistence/PersistencePluginDocSpec.scala b/akka-docs/rst/scala/code/docs/persistence/PersistencePluginDocSpec.scala index 80ece71cf1..84265deb50 100644 --- a/akka-docs/rst/scala/code/docs/persistence/PersistencePluginDocSpec.scala +++ b/akka-docs/rst/scala/code/docs/persistence/PersistencePluginDocSpec.scala @@ -10,8 +10,9 @@ import scala.collection.immutable.Seq //#plugin-imports import com.typesafe.config._ - import org.scalatest.WordSpec +import scala.concurrent.duration._ +import akka.testkit.TestKit import akka.actor.ActorSystem //#plugin-imports @@ -69,8 +70,12 @@ class PersistencePluginDocSpec extends WordSpec { //#snapshot-store-plugin-config """ - val system = ActorSystem("doc", ConfigFactory.parseString(providerConfig).withFallback(ConfigFactory.parseString(PersistencePluginDocSpec.config))) - val extension = Persistence(system) + val system = ActorSystem("PersistencePluginDocSpec", ConfigFactory.parseString(providerConfig).withFallback(ConfigFactory.parseString(PersistencePluginDocSpec.config))) + try { + Persistence(system) + } finally { + TestKit.shutdownActorSystem(system, 10.seconds, false) + } } } diff --git a/akka-docs/rst/scala/code/docs/persistence/PersistenceSerializerDocSpec.scala b/akka-docs/rst/scala/code/docs/persistence/PersistenceSerializerDocSpec.scala index f8d036f5f2..0c23ee3efb 100644 --- a/akka-docs/rst/scala/code/docs/persistence/PersistenceSerializerDocSpec.scala +++ b/akka-docs/rst/scala/code/docs/persistence/PersistenceSerializerDocSpec.scala @@ -5,11 +5,11 @@ package docs.persistence import com.typesafe.config._ - +import scala.concurrent.duration._ import org.scalatest.WordSpec - import akka.actor.ActorSystem import akka.serialization.{ Serializer, SerializationExtension } +import akka.testkit.TestKit class PersistenceSerializerDocSpec extends WordSpec { @@ -29,7 +29,12 @@ class PersistenceSerializerDocSpec extends WordSpec { //#custom-serializer-config """.stripMargin - SerializationExtension(ActorSystem("doc", ConfigFactory.parseString(customSerializerConfig))) + val system = ActorSystem("PersistenceSerializerDocSpec", ConfigFactory.parseString(customSerializerConfig)) + try { + SerializationExtension(system) + } finally { + TestKit.shutdownActorSystem(system, 10.seconds, false) + } } class MyPayload diff --git a/akka-remote/src/test/scala/akka/remote/Ticket1978CommunicationSpec.scala b/akka-remote/src/test/scala/akka/remote/Ticket1978CommunicationSpec.scala index e15c15c527..3469468f77 100644 --- a/akka-remote/src/test/scala/akka/remote/Ticket1978CommunicationSpec.scala +++ b/akka-remote/src/test/scala/akka/remote/Ticket1978CommunicationSpec.scala @@ -160,8 +160,8 @@ abstract class Ticket1978CommunicationSpec(val cipherConfig: CipherConfig) exten } } else { - "not be run when the cipher is not supported by the platform this test is currently being executed on" ignore { - + "not be run when the cipher is not supported by the platform this test is currently being executed on" in { + pending } } diff --git a/akka-testkit/src/test/scala/akka/testkit/AkkaSpec.scala b/akka-testkit/src/test/scala/akka/testkit/AkkaSpec.scala index a1b8dbef2b..bb6cf3b7f1 100644 --- a/akka-testkit/src/test/scala/akka/testkit/AkkaSpec.scala +++ b/akka-testkit/src/test/scala/akka/testkit/AkkaSpec.scala @@ -65,6 +65,8 @@ abstract class AkkaSpec(_system: ActorSystem) val log: LoggingAdapter = Logging(system, this.getClass) + override val invokeBeforeAllAndAfterAllEvenIfNoTestsAreExpected = true + final override def beforeAll { startCoroner atStartup()