From 3ba5e89433aaee47f42f54b1649d9af7629ee796 Mon Sep 17 00:00:00 2001 From: Alexander Aumann Date: Sat, 31 Oct 2020 23:21:41 +0100 Subject: [PATCH] Fix BehaviorTestKit.signal false alarm in thread check #29779 --- .../typed/internal/BehaviorTestKitImpl.scala | 4 + .../typed/scaladsl/BehaviorTestKitSpec.scala | 150 ++++++++++-------- 2 files changed, 87 insertions(+), 67 deletions(-) diff --git a/akka-actor-testkit-typed/src/main/scala/akka/actor/testkit/typed/internal/BehaviorTestKitImpl.scala b/akka-actor-testkit-typed/src/main/scala/akka/actor/testkit/typed/internal/BehaviorTestKitImpl.scala index 2c2f7ac93c..579557249b 100644 --- a/akka-actor-testkit-typed/src/main/scala/akka/actor/testkit/typed/internal/BehaviorTestKitImpl.scala +++ b/akka-actor-testkit-typed/src/main/scala/akka/actor/testkit/typed/internal/BehaviorTestKitImpl.scala @@ -145,9 +145,13 @@ private[akka] final class BehaviorTestKitImpl[T](_path: ActorPath, _initialBehav override def signal(signal: Signal): Unit = { try { + context.setCurrentActorThread() currentUncanonical = Behavior.interpretSignal(current, context, signal) current = Behavior.canonicalize(currentUncanonical, current, context) } catch handleException + finally { + context.clearCurrentActorThread() + } } override def hasEffects(): Boolean = !context.effectQueue.isEmpty diff --git a/akka-actor-testkit-typed/src/test/scala/akka/actor/testkit/typed/scaladsl/BehaviorTestKitSpec.scala b/akka-actor-testkit-typed/src/test/scala/akka/actor/testkit/typed/scaladsl/BehaviorTestKitSpec.scala index ffb994234f..7adf5f46a2 100644 --- a/akka-actor-testkit-typed/src/test/scala/akka/actor/testkit/typed/scaladsl/BehaviorTestKitSpec.scala +++ b/akka-actor-testkit-typed/src/test/scala/akka/actor/testkit/typed/scaladsl/BehaviorTestKitSpec.scala @@ -16,7 +16,7 @@ import akka.actor.testkit.typed.{ CapturedLogEvent, Effect } import akka.actor.testkit.typed.Effect._ import akka.actor.testkit.typed.scaladsl.BehaviorTestKitSpec.{ Child, Parent } import akka.actor.testkit.typed.scaladsl.BehaviorTestKitSpec.Parent._ -import akka.actor.typed.{ ActorRef, Behavior, Props } +import akka.actor.typed.{ ActorRef, Behavior, Props, Terminated } import akka.actor.typed.receptionist.{ Receptionist, ServiceKey } import akka.actor.typed.scaladsl.Behaviors @@ -43,75 +43,81 @@ object BehaviorTestKitSpec { case class Log(what: String) extends Command case class RegisterWithReceptionist(name: String) extends Command - val init: Behavior[Command] = Behaviors.receive[Command] { (context, message) => - message match { - case SpawnChild => - context.spawn(Child.initial, "child") - Behaviors.same - case SpawnChildren(numberOfChildren) if numberOfChildren > 0 => - 0.until(numberOfChildren).foreach { i => - context.spawn(Child.initial, s"child$i") - } - Behaviors.same - case SpawnChildrenWithProps(numberOfChildren, props) if numberOfChildren > 0 => - 0.until(numberOfChildren).foreach { i => - context.spawn(Child.initial, s"child$i", props) - } - Behaviors.same - case SpawnAnonymous(numberOfChildren) if numberOfChildren > 0 => - 0.until(numberOfChildren).foreach { _ => - context.spawnAnonymous(Child.initial) - } - Behaviors.same - case SpawnAnonymousWithProps(numberOfChildren, props) if numberOfChildren > 0 => - 0.until(numberOfChildren).foreach { _ => - context.spawnAnonymous(Child.initial, props) - } - Behaviors.same - case StopChild(child) => - context.stop(child) - Behaviors.same - case SpawnAdapter => - context.spawnMessageAdapter { (r: Reproduce) => - SpawnAnonymous(r.times) - } - Behaviors.same - case SpawnAdapterWithName(name) => - context.spawnMessageAdapter({ (r: Reproduce) => - SpawnAnonymous(r.times) - }, name) - Behaviors.same - case SpawnAndWatchUnwatch(name) => - val c = context.spawn(Child.initial, name) - context.watch(c) - context.unwatch(c) - Behaviors.same - case m @ SpawnAndWatchWith(name) => - val c = context.spawn(Child.initial, name) - context.watchWith(c, m) - Behaviors.same - case SpawnSession(replyTo, sessionHandler) => - val session = context.spawnAnonymous[String](Behaviors.receiveMessage { message => - sessionHandler ! message + val init: Behavior[Command] = Behaviors + .receive[Command] { (context, message) => + message match { + case SpawnChild => + context.spawn(Child.initial, "child") Behaviors.same - }) - replyTo ! session - Behaviors.same - case KillSession(session, replyTo) => - context.stop(session) - replyTo ! Done - Behaviors.same - case CreateMessageAdapter(messageClass, f) => - context.messageAdapter(f)(ClassTag(messageClass)) - Behaviors.same - case Log(what) => - context.log.info(what) - Behaviors.same - case RegisterWithReceptionist(name: String) => - context.system.receptionist ! Receptionist.Register(ServiceKey[Command](name), context.self) + case SpawnChildren(numberOfChildren) if numberOfChildren > 0 => + 0.until(numberOfChildren).foreach { i => + context.spawn(Child.initial, s"child$i") + } + Behaviors.same + case SpawnChildrenWithProps(numberOfChildren, props) if numberOfChildren > 0 => + 0.until(numberOfChildren).foreach { i => + context.spawn(Child.initial, s"child$i", props) + } + Behaviors.same + case SpawnAnonymous(numberOfChildren) if numberOfChildren > 0 => + 0.until(numberOfChildren).foreach { _ => + context.spawnAnonymous(Child.initial) + } + Behaviors.same + case SpawnAnonymousWithProps(numberOfChildren, props) if numberOfChildren > 0 => + 0.until(numberOfChildren).foreach { _ => + context.spawnAnonymous(Child.initial, props) + } + Behaviors.same + case StopChild(child) => + context.stop(child) + Behaviors.same + case SpawnAdapter => + context.spawnMessageAdapter { (r: Reproduce) => + SpawnAnonymous(r.times) + } + Behaviors.same + case SpawnAdapterWithName(name) => + context.spawnMessageAdapter({ (r: Reproduce) => + SpawnAnonymous(r.times) + }, name) + Behaviors.same + case SpawnAndWatchUnwatch(name) => + val c = context.spawn(Child.initial, name) + context.watch(c) + context.unwatch(c) + Behaviors.same + case m @ SpawnAndWatchWith(name) => + val c = context.spawn(Child.initial, name) + context.watchWith(c, m) + Behaviors.same + case SpawnSession(replyTo, sessionHandler) => + val session = context.spawnAnonymous[String](Behaviors.receiveMessage { message => + sessionHandler ! message + Behaviors.same + }) + replyTo ! session + Behaviors.same + case KillSession(session, replyTo) => + context.stop(session) + replyTo ! Done + Behaviors.same + case CreateMessageAdapter(messageClass, f) => + context.messageAdapter(f)(ClassTag(messageClass)) + Behaviors.same + case Log(what) => + context.log.info(what) + Behaviors.same + case RegisterWithReceptionist(name: String) => + context.system.receptionist ! Receptionist.Register(ServiceKey[Command](name), context.self) + Behaviors.same + } + } + .receiveSignal { + case (context, Terminated(_)) => + context.log.debug("Terminated") Behaviors.same } - } } object Child { @@ -277,6 +283,16 @@ class BehaviorTestKitSpec extends AnyWordSpec with Matchers with LogCapturing { } } + "BehaviorTestKit's signal" must { + "not throw thread validation errors when context log is accessed" in { + val other = TestInbox[String]() + val testkit = BehaviorTestKit[Parent.Command](Parent.init) + noException should be thrownBy { + testkit.signal(Terminated(other.ref)) + } + } + } + "BehaviorTestKit’s watch" must { "record effects for watching and unwatching" in { val testkit = BehaviorTestKit(Parent.init)