Typed test kit improvements #23360

* Call right overloaded super method in spawn and spawnAnonymous (avoiding infinite recursion)
* Add Effects for each type of Spawning
This commit is contained in:
Josep Prat 2017-07-28 09:53:37 +02:00 committed by Johan Andrén
parent cc11ed40b5
commit 3b01e08904
2 changed files with 156 additions and 8 deletions

View file

@ -5,7 +5,7 @@ package akka.typed.testkit
import java.util.concurrent.ConcurrentLinkedQueue
import akka.typed.{ ActorContext, ActorRef, ActorSystem, Behavior, EmptyProps, PostStop, Props, Signal }
import akka.typed.{ ActorContext, ActorRef, ActorSystem, Behavior, PostStop, Props, Signal }
import scala.annotation.tailrec
import scala.collection.immutable
@ -20,7 +20,12 @@ import scala.concurrent.duration.{ Duration, FiniteDuration }
abstract class Effect
object Effect {
@SerialVersionUID(1L) final case class Spawned(childName: String) extends Effect
abstract class SpawnedEffect extends Effect
@SerialVersionUID(1L) final case class Spawned(childName: String, props: Props) extends SpawnedEffect
@SerialVersionUID(1L) final case class SpawnedAnonymous(props: Props) extends SpawnedEffect
@SerialVersionUID(1L) final case object SpawnedAdapter extends SpawnedEffect
@SerialVersionUID(1L) final case class Stopped(childName: String) extends Effect
@SerialVersionUID(1L) final case class Watched[T](other: ActorRef[T]) extends Effect
@SerialVersionUID(1L) final case class Unwatched[T](other: ActorRef[T]) extends Effect
@ -78,18 +83,23 @@ class EffectfulActorContext[T](_name: String, _initialBehavior: Behavior[T], _ma
}
override def spawnAnonymous[U](behavior: Behavior[U], props: Props = Props.empty): ActorRef[U] = {
val ref = super.spawnAnonymous(behavior)
effectQueue.offer(Spawned(ref.path.name))
val ref = super.spawnAnonymous(behavior, props)
effectQueue.offer(SpawnedAnonymous(props))
ref
}
override def spawnAdapter[U](f: U T, name: String = ""): ActorRef[U] = {
override def spawnAdapter[U](f: U T): ActorRef[U] = {
spawnAdapter(f, "")
}
override def spawnAdapter[U](f: U T, name: String): ActorRef[U] = {
val ref = super.spawnAdapter(f, name)
effectQueue.offer(Spawned(ref.path.name))
effectQueue.offer(SpawnedAdapter)
ref
}
override def spawn[U](behavior: Behavior[U], name: String, props: Props = Props.empty): ActorRef[U] = {
effectQueue.offer(Spawned(name))
super.spawn(behavior, name)
effectQueue.offer(Spawned(name, props))
super.spawn(behavior, name, props)
}
override def stop[U](child: ActorRef[U]): Boolean = {
effectQueue.offer(Stopped(child.path.name))

View file

@ -0,0 +1,138 @@
/**
* Copyright (C) 2014-2017 Lightbend Inc. <http://www.lightbend.com>
*/
package akka.typed.testkit
import akka.typed.scaladsl.Actor
import akka.typed.testkit.Effect.{ Spawned, SpawnedAdapter, SpawnedAnonymous }
import akka.typed.testkit.EffectfulActorContextSpec.Father
import akka.typed.testkit.EffectfulActorContextSpec.Father._
import akka.typed.{ ActorSystem, Behavior, Props }
import org.scalatest.{ FlatSpec, Matchers }
object EffectfulActorContextSpec {
object Father {
case class Reproduce(times: Int)
sealed trait Command
case class SpawnChildren(numberOfChildren: Int) extends Command
case class SpawnChildrenWithProps(numberOfChildren: Int, props: Props) extends Command
case class SpawnAnonymous(numberOfChildren: Int) extends Command
case class SpawnAnonymousWithProps(numberOfChildren: Int, props: Props) extends Command
case object SpawnAdapter extends Command
case class SpawnAdapterWithName(name: String) extends Command
def behavior: Behavior[Command] = init()
def init(): Behavior[Command] = Actor.immutable[Command] { (ctx, msg)
msg match {
case SpawnChildren(numberOfChildren) if numberOfChildren > 0
0.until(numberOfChildren).foreach { i
ctx.spawn(Child.initial, s"child$i")
}
Actor.same
case SpawnChildrenWithProps(numberOfChildren, props) if numberOfChildren > 0
0.until(numberOfChildren).foreach { i
ctx.spawn(Child.initial, s"child$i", props)
}
Actor.same
case SpawnAnonymous(numberOfChildren) if numberOfChildren > 0
0.until(numberOfChildren).foreach { _
ctx.spawnAnonymous(Child.initial)
}
Actor.same
case SpawnAnonymousWithProps(numberOfChildren, props) if numberOfChildren > 0
0.until(numberOfChildren).foreach { _
ctx.spawnAnonymous(Child.initial, props)
}
Actor.same
case SpawnAdapter
ctx.spawnAdapter {
r: Reproduce SpawnAnonymous(r.times)
}
Actor.same
case SpawnAdapterWithName(name)
ctx.spawnAdapter({
r: Reproduce SpawnAnonymous(r.times)
}, name)
Actor.same
}
}
}
object Child {
sealed trait Action
def initial: Behavior[Action] = Actor.immutable[Action] { (_, msg)
msg match {
case _
Actor.empty
}
}
}
}
class EffectfulActorContextSpec extends FlatSpec with Matchers {
private val props = Props.empty.withMailboxCapacity(10)
"EffectfulActorContext's spawn" should "create children when no props specified" in {
val system = ActorSystem.create(Father.init(), "father-system")
val ctx = new EffectfulActorContext[Father.Command]("father-test", Father.init(), 100, system)
ctx.run(SpawnChildren(2))
val effects = ctx.getAllEffects()
effects should contain only (Spawned("child0", Props.empty), Spawned("child1", Props.empty))
}
it should "create children when props specified and record effects" in {
val system = ActorSystem.create(Father.init(), "father-system")
val ctx = new EffectfulActorContext[Father.Command]("father-test", Father.init(), 100, system)
ctx.run(SpawnChildrenWithProps(2, props))
val effects = ctx.getAllEffects()
effects should contain only (Spawned("child0", props), Spawned("child1", props))
}
"EffectfulActorContext's spawnAnonymous" should "create children when no props specified and record effects" in {
val system = ActorSystem.create(Father.init(), "father-system")
val ctx = new EffectfulActorContext[Father.Command]("father-test", Father.init(), 100, system)
ctx.run(SpawnAnonymous(2))
val effects = ctx.getAllEffects()
effects shouldBe Seq(SpawnedAnonymous(Props.empty), SpawnedAnonymous(Props.empty))
}
it should "create children when props specified and record effects" in {
val system = ActorSystem.create(Father.init(), "father-system")
val ctx = new EffectfulActorContext[Father.Command]("father-test", Father.init(), 100, system)
ctx.run(SpawnAnonymousWithProps(2, props))
val effects = ctx.getAllEffects()
effects shouldBe Seq(SpawnedAnonymous(props), SpawnedAnonymous(props))
}
"EffectfulActorContext's spawnAdapter" should "create adapters without name and record effects" in {
val system = ActorSystem.create(Father.init(), "father-system")
val ctx = new EffectfulActorContext[Father.Command]("father-test", Father.init(), 100, system)
ctx.run(SpawnAdapter)
val effects = ctx.getAllEffects()
effects shouldBe Seq(SpawnedAdapter)
}
it should "create adapters with name and record effects" in {
val system = ActorSystem.create(Father.init(), "father-system")
val ctx = new EffectfulActorContext[Father.Command]("father-test", Father.init(), 100, system)
ctx.run(SpawnAdapterWithName("adapter"))
val effects = ctx.getAllEffects()
effects shouldBe Seq(SpawnedAdapter)
}
}