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:
parent
cc11ed40b5
commit
3b01e08904
2 changed files with 156 additions and 8 deletions
|
|
@ -5,7 +5,7 @@ package akka.typed.testkit
|
||||||
|
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue
|
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.annotation.tailrec
|
||||||
import scala.collection.immutable
|
import scala.collection.immutable
|
||||||
|
|
@ -20,7 +20,12 @@ import scala.concurrent.duration.{ Duration, FiniteDuration }
|
||||||
abstract class Effect
|
abstract class Effect
|
||||||
|
|
||||||
object 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 Stopped(childName: String) extends Effect
|
||||||
@SerialVersionUID(1L) final case class Watched[T](other: ActorRef[T]) 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
|
@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] = {
|
override def spawnAnonymous[U](behavior: Behavior[U], props: Props = Props.empty): ActorRef[U] = {
|
||||||
val ref = super.spawnAnonymous(behavior)
|
val ref = super.spawnAnonymous(behavior, props)
|
||||||
effectQueue.offer(Spawned(ref.path.name))
|
effectQueue.offer(SpawnedAnonymous(props))
|
||||||
ref
|
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)
|
val ref = super.spawnAdapter(f, name)
|
||||||
effectQueue.offer(Spawned(ref.path.name))
|
effectQueue.offer(SpawnedAdapter)
|
||||||
ref
|
ref
|
||||||
}
|
}
|
||||||
override def spawn[U](behavior: Behavior[U], name: String, props: Props = Props.empty): ActorRef[U] = {
|
override def spawn[U](behavior: Behavior[U], name: String, props: Props = Props.empty): ActorRef[U] = {
|
||||||
effectQueue.offer(Spawned(name))
|
effectQueue.offer(Spawned(name, props))
|
||||||
super.spawn(behavior, name)
|
super.spawn(behavior, name, props)
|
||||||
}
|
}
|
||||||
override def stop[U](child: ActorRef[U]): Boolean = {
|
override def stop[U](child: ActorRef[U]): Boolean = {
|
||||||
effectQueue.offer(Stopped(child.path.name))
|
effectQueue.offer(Stopped(child.path.name))
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue