* Expose Effect classes for BehaviorTestKit Java DSL - Share effect classes between java and scala dsl - make spawn adapter private - add message adapter effect - add tests for java behavior test kit * Mirror Effect factory in java and scala dsl
This commit is contained in:
parent
356415014f
commit
2a979fe296
9 changed files with 571 additions and 152 deletions
|
|
@ -4,13 +4,18 @@
|
|||
|
||||
package akka.actor.testkit.typed
|
||||
|
||||
import akka.annotation.DoNotInherit
|
||||
import akka.actor.typed.{ ActorRef, Behavior, Props }
|
||||
import akka.annotation.{ DoNotInherit, InternalApi }
|
||||
import akka.util.JavaDurationConverters._
|
||||
|
||||
import scala.compat.java8.FunctionConverters._
|
||||
import scala.concurrent.duration.FiniteDuration
|
||||
|
||||
/**
|
||||
* All tracked effects for the [[akka.actor.testkit.typed.scaladsl.BehaviorTestKit]] and
|
||||
* [[akka.actor.testkit.typed.javadsl.BehaviorTestKit]] must extend this type.
|
||||
*
|
||||
* Factories/types for effects are available through [[akka.actor.testkit.typed.scaladsl.Effects]]
|
||||
* Factories/types for effects are available through [[akka.actor.testkit.typed.javadsl.Effects]]
|
||||
* and [[akka.actor.testkit.typed.javadsl.Effects]]
|
||||
*
|
||||
* Not for user extension
|
||||
|
|
@ -18,3 +23,175 @@ import akka.annotation.DoNotInherit
|
|||
@DoNotInherit
|
||||
abstract class Effect private[akka] ()
|
||||
|
||||
object Effect {
|
||||
/**
|
||||
* The behavior spawned a named child with the given behavior (and optionally specific props)
|
||||
*/
|
||||
final class Spawned[T](val behavior: Behavior[T], val childName: String, val props: Props, val ref: ActorRef[T])
|
||||
extends Effect with Product3[Behavior[T], String, Props] with Serializable {
|
||||
|
||||
override def equals(other: Any) = other match {
|
||||
case o: Spawned[_] ⇒
|
||||
this.behavior == o.behavior &&
|
||||
this.childName == o.childName &&
|
||||
this.props == o.props
|
||||
case _ ⇒ false
|
||||
}
|
||||
override def hashCode: Int = (behavior.## * 31 + childName.##) * 31 + props.##
|
||||
override def toString: String = s"Spawned($behavior, $childName, $props)"
|
||||
|
||||
override def productPrefix = "Spawned"
|
||||
override def _1: Behavior[T] = behavior
|
||||
override def _2: String = childName
|
||||
override def _3: Props = props
|
||||
override def canEqual(o: Any) = o.isInstanceOf[Spawned[_]]
|
||||
}
|
||||
|
||||
object Spawned {
|
||||
def apply[T](behavior: Behavior[T], childName: String, props: Props = Props.empty): Spawned[T] = new Spawned(behavior, childName, props, null)
|
||||
def unapply[T](s: Spawned[T]): Option[(Behavior[T], String, Props)] = Some((s.behavior, s.childName, s.props))
|
||||
}
|
||||
|
||||
/**
|
||||
* The behavior spawned an anonymous child with the given behavior (and optionally specific props)
|
||||
*/
|
||||
final class SpawnedAnonymous[T](val behavior: Behavior[T], val props: Props, val ref: ActorRef[T])
|
||||
extends Effect with Product2[Behavior[T], Props] with Serializable {
|
||||
|
||||
override def equals(other: Any) = other match {
|
||||
case o: SpawnedAnonymous[_] ⇒ this.behavior == o.behavior && this.props == o.props
|
||||
case _ ⇒ false
|
||||
}
|
||||
override def hashCode: Int = behavior.## * 31 + props.##
|
||||
override def toString: String = s"SpawnedAnonymous($behavior, $props)"
|
||||
|
||||
override def productPrefix = "SpawnedAnonymous"
|
||||
override def _1: Behavior[T] = behavior
|
||||
override def _2: Props = props
|
||||
override def canEqual(o: Any) = o.isInstanceOf[SpawnedAnonymous[_]]
|
||||
}
|
||||
|
||||
object SpawnedAnonymous {
|
||||
def apply[T](behavior: Behavior[T], props: Props = Props.empty): SpawnedAnonymous[T] = new SpawnedAnonymous(behavior, props, null)
|
||||
def unapply[T](s: SpawnedAnonymous[T]): Option[(Behavior[T], Props)] = Some((s.behavior, s.props))
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL API
|
||||
* Spawning adapters is private[akka]
|
||||
*/
|
||||
@InternalApi
|
||||
private[akka] final class SpawnedAdapter[T](val name: String, val ref: ActorRef[T])
|
||||
extends Effect with Product1[String] with Serializable {
|
||||
|
||||
override def equals(other: Any) = other match {
|
||||
case o: SpawnedAdapter[_] ⇒ this.name == o.name
|
||||
case _ ⇒ false
|
||||
}
|
||||
override def hashCode: Int = name.##
|
||||
override def toString: String = s"SpawnedAdapter($name)"
|
||||
|
||||
override def productPrefix = "SpawnedAdapter"
|
||||
override def _1: String = name
|
||||
override def canEqual(o: Any) = o.isInstanceOf[SpawnedAdapter[_]]
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL API
|
||||
* Spawning adapters is private[akka]
|
||||
*/
|
||||
@InternalApi
|
||||
private[akka] object SpawnedAdapter {
|
||||
def apply[T](name: String): SpawnedAdapter[T] = new SpawnedAdapter(name, null)
|
||||
def unapply[T](s: SpawnedAdapter[T]): Option[Tuple1[String]] = Some(Tuple1(s.name))
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL API
|
||||
* The behavior spawned an anonymous adapter, through `ctx.spawnMessageAdapter`
|
||||
*/
|
||||
@InternalApi
|
||||
private[akka] final class SpawnedAnonymousAdapter[T](val ref: ActorRef[T])
|
||||
extends Effect with Product with Serializable {
|
||||
|
||||
override def equals(other: Any) = other match {
|
||||
case _: SpawnedAnonymousAdapter[_] ⇒ true
|
||||
case _ ⇒ false
|
||||
}
|
||||
override def hashCode: Int = Nil.##
|
||||
override def toString: String = "SpawnedAnonymousAdapter"
|
||||
|
||||
override def productPrefix = "SpawnedAnonymousAdapter"
|
||||
override def productIterator = Iterator.empty
|
||||
override def productArity = 0
|
||||
override def productElement(n: Int) = throw new NoSuchElementException
|
||||
override def canEqual(o: Any) = o.isInstanceOf[SpawnedAnonymousAdapter[_]]
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL API
|
||||
*/
|
||||
@InternalApi
|
||||
private[akka] object SpawnedAnonymousAdapter {
|
||||
def apply[T]() = new SpawnedAnonymousAdapter[T](null)
|
||||
def unapply[T](s: SpawnedAnonymousAdapter[T]): Boolean = true
|
||||
}
|
||||
|
||||
/**
|
||||
* The behavior create a message adapter for the messages of type clazz
|
||||
*/
|
||||
final case class MessageAdapter[A, T](messageClass: Class[A], adapt: A ⇒ T) extends Effect {
|
||||
/**
|
||||
* JAVA API
|
||||
*/
|
||||
def adaptFunction: java.util.function.Function[A, T] = adapt.asJava
|
||||
}
|
||||
|
||||
/**
|
||||
* The behavior stopped `childName`
|
||||
*/
|
||||
final case class Stopped(childName: String) extends Effect
|
||||
|
||||
/**
|
||||
* The behavior started watching `other`, through `ctx.watch(other)`
|
||||
*/
|
||||
final case class Watched[T](other: ActorRef[T]) extends Effect
|
||||
|
||||
/**
|
||||
* The behavior started watching `other`, through `ctx.unwatch(other)`
|
||||
*/
|
||||
final case class Unwatched[T](other: ActorRef[T]) extends Effect
|
||||
|
||||
/**
|
||||
* The behavior set a new receive timeout, with `msg` as timeout notification
|
||||
*/
|
||||
final case class ReceiveTimeoutSet[T](d: FiniteDuration, msg: T) extends Effect {
|
||||
/**
|
||||
* Java API
|
||||
*/
|
||||
def duration(): java.time.Duration = d.asJava
|
||||
}
|
||||
|
||||
final case object ReceiveTimeoutCancelled extends ReceiveTimeoutCancelled
|
||||
|
||||
sealed abstract class ReceiveTimeoutCancelled extends Effect
|
||||
|
||||
/**
|
||||
* The behavior used `ctx.schedule` to schedule `msg` to be sent to `target` after `delay`
|
||||
* FIXME what about events scheduled through the scheduler?
|
||||
*/
|
||||
final case class Scheduled[U](delay: FiniteDuration, target: ActorRef[U], msg: U) extends Effect {
|
||||
def duration(): java.time.Duration = delay.asJava
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to represent an empty list of effects - in other words, the behavior didn't do anything observable
|
||||
*/
|
||||
case object NoEffects extends NoEffects
|
||||
|
||||
/**
|
||||
* Used for NoEffects expectations by type
|
||||
*/
|
||||
sealed abstract class NoEffects extends Effect
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import akka.actor.ActorPath
|
|||
import akka.actor.typed.{ Behavior, PostStop, Signal, ActorRef }
|
||||
import akka.annotation.InternalApi
|
||||
import akka.actor.testkit.typed.Effect
|
||||
import akka.actor.testkit.typed.scaladsl.Effects._
|
||||
import akka.actor.testkit.typed.Effect._
|
||||
|
||||
import scala.annotation.tailrec
|
||||
import scala.collection.JavaConverters._
|
||||
|
|
|
|||
|
|
@ -5,14 +5,17 @@
|
|||
package akka.actor.testkit.typed.internal
|
||||
|
||||
import java.util.concurrent.ConcurrentLinkedQueue
|
||||
import java.util.function
|
||||
|
||||
import akka.actor.{ Cancellable, ActorPath }
|
||||
import akka.actor.{ ActorPath, Cancellable }
|
||||
import akka.actor.typed.{ ActorRef, Behavior, Props }
|
||||
import akka.annotation.InternalApi
|
||||
import akka.actor.testkit.typed.Effect
|
||||
import akka.actor.testkit.typed.scaladsl.Effects._
|
||||
import akka.actor.testkit.typed.Effect._
|
||||
|
||||
import scala.concurrent.duration.{ Duration, FiniteDuration }
|
||||
import scala.reflect.ClassTag
|
||||
import scala.compat.java8.FunctionConverters._
|
||||
|
||||
/**
|
||||
* INTERNAL API
|
||||
|
|
@ -26,18 +29,26 @@ import scala.concurrent.duration.{ Duration, FiniteDuration }
|
|||
effectQueue.offer(new SpawnedAnonymous(behavior, props, ref))
|
||||
ref
|
||||
}
|
||||
|
||||
override def spawnMessageAdapter[U](f: U ⇒ T): ActorRef[U] = {
|
||||
val ref = super.spawnMessageAdapter(f)
|
||||
effectQueue.offer(new SpawnedAnonymousAdapter(ref))
|
||||
ref
|
||||
}
|
||||
|
||||
override def spawnMessageAdapter[U](f: U ⇒ T, name: String): ActorRef[U] = {
|
||||
val ref = super.spawnMessageAdapter(f, name)
|
||||
effectQueue.offer(new SpawnedAdapter(name, ref))
|
||||
ref
|
||||
}
|
||||
override def messageAdapter[U: ClassTag](f: U ⇒ T): ActorRef[U] = {
|
||||
val ref = super.messageAdapter(f)
|
||||
effectQueue.offer(MessageAdapter(implicitly[ClassTag[U]].runtimeClass.asInstanceOf[Class[U]], f))
|
||||
ref
|
||||
}
|
||||
override def messageAdapter[U](messageClass: Class[U], f: function.Function[U, T]): ActorRef[U] = {
|
||||
val ref = super.messageAdapter(messageClass, f)
|
||||
effectQueue.offer(MessageAdapter[U, T](messageClass, f.asScala))
|
||||
ref
|
||||
}
|
||||
override def spawn[U](behavior: Behavior[U], name: String, props: Props = Props.empty): ActorRef[U] = {
|
||||
val ref = super.spawn(behavior, name, props)
|
||||
effectQueue.offer(new Spawned(behavior, name, props, ref))
|
||||
|
|
@ -64,7 +75,7 @@ import scala.concurrent.duration.{ Duration, FiniteDuration }
|
|||
super.setReceiveTimeout(d, msg)
|
||||
}
|
||||
override def cancelReceiveTimeout(): Unit = {
|
||||
effectQueue.offer(ReceiveTimeoutSet(Duration.Undefined, null))
|
||||
effectQueue.offer(ReceiveTimeoutCancelled)
|
||||
super.cancelReceiveTimeout()
|
||||
}
|
||||
override def schedule[U](delay: FiniteDuration, target: ActorRef[U], msg: U): Cancellable = {
|
||||
|
|
|
|||
|
|
@ -15,85 +15,69 @@ import akka.util.JavaDurationConverters._
|
|||
* actual effects to expected ones.
|
||||
*/
|
||||
object Effects {
|
||||
import akka.actor.testkit.typed.scaladsl.Effects._
|
||||
import akka.actor.testkit.typed.Effect._
|
||||
|
||||
/**
|
||||
* The behavior spawned a named child with the given behavior with no specific props
|
||||
*/
|
||||
def spawned[T](behavior: Behavior[T], childName: String): Effect = Spawned(behavior, childName)
|
||||
def spawned[T](behavior: Behavior[T], childName: String): Spawned[T] = Spawned(behavior, childName)
|
||||
/**
|
||||
* The behavior spawned a named child with the given behavior with no specific props
|
||||
*/
|
||||
def spawned[T](behavior: Behavior[T], childName: String, ref: ActorRef[T]): Effect = new Spawned(behavior, childName, Props.empty, ref)
|
||||
def spawned[T](behavior: Behavior[T], childName: String, ref: ActorRef[T]): Spawned[T] = new Spawned(behavior, childName, Props.empty, ref)
|
||||
/**
|
||||
* The behavior spawned a named child with the given behavior and specific props
|
||||
*/
|
||||
def spawned[T](behavior: Behavior[T], childName: String, props: Props): Effect = Spawned(behavior, childName, props)
|
||||
def spawned[T](behavior: Behavior[T], childName: String, props: Props): Spawned[T] = Spawned(behavior, childName, props)
|
||||
/**
|
||||
* The behavior spawned a named child with the given behavior and specific props
|
||||
*/
|
||||
def spawned[T](behavior: Behavior[T], childName: String, props: Props, ref: ActorRef[T]): Effect = new Spawned(behavior, childName, props, ref)
|
||||
def spawned[T](behavior: Behavior[T], childName: String, props: Props, ref: ActorRef[T]): Spawned[T] = new Spawned(behavior, childName, props, ref)
|
||||
/**
|
||||
* The behavior spawned an anonymous child with the given behavior with no specific props
|
||||
*/
|
||||
def spawnedAnonymous[T](behavior: Behavior[T]): Effect = SpawnedAnonymous(behavior)
|
||||
def spawnedAnonymous[T](behavior: Behavior[T]): SpawnedAnonymous[T] = SpawnedAnonymous(behavior)
|
||||
/**
|
||||
* The behavior spawned an anonymous child with the given behavior with no specific props
|
||||
*/
|
||||
def spawnedAnonymous[T](behavior: Behavior[T], ref: ActorRef[T]): Effect = new SpawnedAnonymous(behavior, Props.empty, ref)
|
||||
def spawnedAnonymous[T](behavior: Behavior[T], ref: ActorRef[T]): SpawnedAnonymous[T] = new SpawnedAnonymous(behavior, Props.empty, ref)
|
||||
/**
|
||||
* The behavior spawned an anonymous child with the given behavior with specific props
|
||||
*/
|
||||
def spawnedAnonymous[T](behavior: Behavior[T], props: Props): Effect = SpawnedAnonymous(behavior, props)
|
||||
def spawnedAnonymous[T](behavior: Behavior[T], props: Props): SpawnedAnonymous[T] = SpawnedAnonymous(behavior, props)
|
||||
/**
|
||||
* The behavior spawned an anonymous child with the given behavior with specific props
|
||||
*/
|
||||
def spawnedAnonymous[T](behavior: Behavior[T], props: Props, ref: ActorRef[T]): Effect = new SpawnedAnonymous(behavior, props, ref)
|
||||
/**
|
||||
* The behavior spawned an anonymous adapter, through `ctx.spawnMessageAdapter`
|
||||
*/
|
||||
def spawnedAnonymousAdapter(): Effect = SpawnedAnonymousAdapter[Any]()
|
||||
/**
|
||||
* The behavior spawned an anonymous adapter, through `ctx.spawnMessageAdapter`
|
||||
*/
|
||||
def spawnedAnonymousAdapter[T](ref: ActorRef[T]): Effect = new SpawnedAnonymousAdapter(ref)
|
||||
/**
|
||||
* The behavior spawned a named adapter, through `ctx.spawnMessageAdapter`
|
||||
*/
|
||||
def spawnedAdapter(name: String): Effect = SpawnedAdapter[Any](name)
|
||||
/**
|
||||
* The behavior spawned a named adapter, through `ctx.spawnMessageAdapter`
|
||||
*/
|
||||
def spawnedAdapter[T](name: String, ref: ActorRef[T]): Effect = new SpawnedAdapter(name, ref)
|
||||
def spawnedAnonymous[T](behavior: Behavior[T], props: Props, ref: ActorRef[T]): SpawnedAnonymous[T] = new SpawnedAnonymous(behavior, props, ref)
|
||||
/**
|
||||
* The behavior stopped `childName`
|
||||
*/
|
||||
def stopped(childName: String): Effect = Stopped(childName)
|
||||
def stopped(childName: String): Stopped = Stopped(childName)
|
||||
/**
|
||||
* The behavior started watching `other`, through `ctx.watch(other)`
|
||||
*/
|
||||
def watched[T](other: ActorRef[T]): Effect = Watched(other)
|
||||
def watched[T](other: ActorRef[T]): Watched[T] = Watched(other)
|
||||
|
||||
/**
|
||||
* The behavior started watching `other`, through `ctx.unwatch(other)`
|
||||
*/
|
||||
def unwatched[T](other: ActorRef[T]): Effect = Unwatched(other)
|
||||
def unwatched[T](other: ActorRef[T]): Unwatched[T] = Unwatched(other)
|
||||
|
||||
/**
|
||||
* The behavior set a new receive timeout, with `msg` as timeout notification
|
||||
*/
|
||||
def receiveTimeoutSet[T](d: Duration, msg: T): Effect = ReceiveTimeoutSet(d.asScala, msg)
|
||||
def receiveTimeoutSet[T](d: Duration, msg: T): ReceiveTimeoutSet[T] = ReceiveTimeoutSet(d.asScala, msg)
|
||||
|
||||
/**
|
||||
* The behavior used `ctx.schedule` to schedule `msg` to be sent to `target` after `delay`
|
||||
* FIXME what about events scheduled through the scheduler?
|
||||
*/
|
||||
def scheduled[U](delay: Duration, target: ActorRef[U], msg: U): Effect =
|
||||
def scheduled[U](delay: Duration, target: ActorRef[U], msg: U): Scheduled[U] =
|
||||
Scheduled(delay.asScala, target, msg)
|
||||
|
||||
/**
|
||||
* Used to represent an empty list of effects - in other words, the behavior didn't do anything observable
|
||||
*/
|
||||
def noEffects(): Effect = NoEffects
|
||||
def noEffects(): NoEffects = NoEffects
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,142 +5,77 @@
|
|||
package akka.actor.testkit.typed.scaladsl
|
||||
|
||||
import akka.actor.typed.{ ActorRef, Behavior, Props }
|
||||
import akka.actor.testkit.typed.Effect
|
||||
|
||||
import scala.concurrent.duration.{ Duration, FiniteDuration }
|
||||
import scala.concurrent.duration.FiniteDuration
|
||||
|
||||
/**
|
||||
* Types for behavior effects for [[BehaviorTestKit]], each effect has a suitable equals and can be used to compare
|
||||
* Factories for behavior effects for [[BehaviorTestKit]], each effect has a suitable equals and can be used to compare
|
||||
* actual effects to expected ones.
|
||||
*/
|
||||
object Effects {
|
||||
import akka.actor.testkit.typed.Effect._
|
||||
|
||||
/**
|
||||
* The behavior spawned a named child with the given behavior (and optionally specific props)
|
||||
* The behavior spawned a named child with the given behavior with no specific props
|
||||
*/
|
||||
final class Spawned[T](val behavior: Behavior[T], val childName: String, val props: Props, val ref: ActorRef[T])
|
||||
extends Effect with Product3[Behavior[T], String, Props] with Serializable {
|
||||
|
||||
override def equals(other: Any) = other match {
|
||||
case o: Spawned[_] ⇒
|
||||
this.behavior == o.behavior &&
|
||||
this.childName == o.childName &&
|
||||
this.props == o.props
|
||||
case _ ⇒ false
|
||||
}
|
||||
override def hashCode: Int = (behavior.## * 31 + childName.##) * 31 + props.##
|
||||
override def toString: String = s"Spawned($behavior, $childName, $props)"
|
||||
|
||||
override def productPrefix = "Spawned"
|
||||
override def _1: Behavior[T] = behavior
|
||||
override def _2: String = childName
|
||||
override def _3: Props = props
|
||||
override def canEqual(o: Any) = o.isInstanceOf[Spawned[_]]
|
||||
}
|
||||
object Spawned {
|
||||
def apply[T](behavior: Behavior[T], childName: String, props: Props = Props.empty): Spawned[T] = new Spawned(behavior, childName, props, null)
|
||||
def unapply[T](s: Spawned[T]): Option[(Behavior[T], String, Props)] = Some((s.behavior, s.childName, s.props))
|
||||
}
|
||||
|
||||
def spawned[T](behavior: Behavior[T], childName: String): Spawned[T] = Spawned(behavior, childName)
|
||||
/**
|
||||
* The behavior spawned an anonymous child with the given behavior (and optionally specific props)
|
||||
* The behavior spawned a named child with the given behavior with no specific props
|
||||
*/
|
||||
final class SpawnedAnonymous[T](val behavior: Behavior[T], val props: Props, val ref: ActorRef[T])
|
||||
extends Effect with Product2[Behavior[T], Props] with Serializable {
|
||||
|
||||
override def equals(other: Any) = other match {
|
||||
case o: SpawnedAnonymous[_] ⇒ this.behavior == o.behavior && this.props == o.props
|
||||
case _ ⇒ false
|
||||
}
|
||||
override def hashCode: Int = behavior.## * 31 + props.##
|
||||
override def toString: String = s"SpawnedAnonymous($behavior, $props)"
|
||||
|
||||
override def productPrefix = "SpawnedAnonymous"
|
||||
override def _1: Behavior[T] = behavior
|
||||
override def _2: Props = props
|
||||
override def canEqual(o: Any) = o.isInstanceOf[SpawnedAnonymous[_]]
|
||||
}
|
||||
object SpawnedAnonymous {
|
||||
def apply[T](behavior: Behavior[T], props: Props = Props.empty): SpawnedAnonymous[T] = new SpawnedAnonymous(behavior, props, null)
|
||||
def unapply[T](s: SpawnedAnonymous[T]): Option[(Behavior[T], Props)] = Some((s.behavior, s.props))
|
||||
}
|
||||
|
||||
def spawned[T](behavior: Behavior[T], childName: String, ref: ActorRef[T]): Spawned[T] = new Spawned(behavior, childName, Props.empty, ref)
|
||||
/**
|
||||
* The behavior spawned a named adapter, through `ctx.spawnMessageAdapter`
|
||||
* The behavior spawned a named child with the given behavior and specific props
|
||||
*/
|
||||
final class SpawnedAdapter[T](val name: String, val ref: ActorRef[T])
|
||||
extends Effect with Product1[String] with Serializable {
|
||||
|
||||
override def equals(other: Any) = other match {
|
||||
case o: SpawnedAdapter[_] ⇒ this.name == o.name
|
||||
case _ ⇒ false
|
||||
}
|
||||
override def hashCode: Int = name.##
|
||||
override def toString: String = s"SpawnedAdapter($name)"
|
||||
|
||||
override def productPrefix = "SpawnedAdapter"
|
||||
override def _1: String = name
|
||||
override def canEqual(o: Any) = o.isInstanceOf[SpawnedAdapter[_]]
|
||||
}
|
||||
object SpawnedAdapter {
|
||||
def apply[T](name: String): SpawnedAdapter[T] = new SpawnedAdapter(name, null)
|
||||
def unapply[T](s: SpawnedAdapter[T]): Option[Tuple1[String]] = Some(Tuple1(s.name))
|
||||
}
|
||||
|
||||
def spawned[T](behavior: Behavior[T], childName: String, props: Props): Spawned[T] = Spawned(behavior, childName, props)
|
||||
/**
|
||||
* The behavior spawned an anonymous adapter, through `ctx.spawnMessageAdapter`
|
||||
* The behavior spawned a named child with the given behavior and specific props
|
||||
*/
|
||||
final class SpawnedAnonymousAdapter[T](val ref: ActorRef[T])
|
||||
extends Effect with Product with Serializable {
|
||||
|
||||
override def equals(other: Any) = other match {
|
||||
case o: SpawnedAnonymousAdapter[_] ⇒ true
|
||||
case _ ⇒ false
|
||||
}
|
||||
override def hashCode: Int = Nil.##
|
||||
override def toString: String = "SpawnedAnonymousAdapter"
|
||||
|
||||
override def productPrefix = "SpawnedAnonymousAdapter"
|
||||
override def productIterator = Iterator.empty
|
||||
override def productArity = 0
|
||||
override def productElement(n: Int) = throw new NoSuchElementException
|
||||
override def canEqual(o: Any) = o.isInstanceOf[SpawnedAnonymousAdapter[_]]
|
||||
}
|
||||
object SpawnedAnonymousAdapter {
|
||||
def apply[T]() = new SpawnedAnonymousAdapter[T](null)
|
||||
def unapply[T](s: SpawnedAnonymousAdapter[T]): Boolean = true
|
||||
}
|
||||
def spawned[T](behavior: Behavior[T], childName: String, props: Props, ref: ActorRef[T]): Spawned[T] = new Spawned(behavior, childName, props, ref)
|
||||
/**
|
||||
* The behavior spawned an anonymous child with the given behavior with no specific props
|
||||
*/
|
||||
def spawnedAnonymous[T](behavior: Behavior[T]): SpawnedAnonymous[T] = SpawnedAnonymous(behavior)
|
||||
/**
|
||||
* The behavior spawned an anonymous child with the given behavior with no specific props
|
||||
*/
|
||||
def spawnedAnonymous[T](behavior: Behavior[T], ref: ActorRef[T]): SpawnedAnonymous[T] = new SpawnedAnonymous(behavior, Props.empty, ref)
|
||||
/**
|
||||
* The behavior spawned an anonymous child with the given behavior with specific props
|
||||
*/
|
||||
def spawnedAnonymous[T](behavior: Behavior[T], props: Props): SpawnedAnonymous[T] = SpawnedAnonymous(behavior, props)
|
||||
/**
|
||||
* The behavior spawned an anonymous child with the given behavior with specific props
|
||||
*/
|
||||
def spawnedAnonymous[T](behavior: Behavior[T], props: Props, ref: ActorRef[T]): SpawnedAnonymous[T] = new SpawnedAnonymous(behavior, props, ref)
|
||||
/**
|
||||
* The behavior stopped `childName`
|
||||
*/
|
||||
final case class Stopped(childName: String) extends Effect
|
||||
def stopped(childName: String): Stopped = Stopped(childName)
|
||||
/**
|
||||
* The behavior started watching `other`, through `ctx.watch(other)`
|
||||
*/
|
||||
final case class Watched[T](other: ActorRef[T]) extends Effect
|
||||
def watched[T](other: ActorRef[T]): Watched[T] = Watched(other)
|
||||
|
||||
/**
|
||||
* The behavior started watching `other`, through `ctx.unwatch(other)`
|
||||
*/
|
||||
final case class Unwatched[T](other: ActorRef[T]) extends Effect
|
||||
def unwatched[T](other: ActorRef[T]): Unwatched[T] = Unwatched(other)
|
||||
|
||||
/**
|
||||
* The behavior set a new receive timeout, with `msg` as timeout notification
|
||||
*/
|
||||
final case class ReceiveTimeoutSet[T](d: Duration, msg: T) extends Effect
|
||||
def receiveTimeoutSet[T](d: FiniteDuration, msg: T): ReceiveTimeoutSet[T] = ReceiveTimeoutSet(d, msg)
|
||||
|
||||
/**
|
||||
* The behavior used `ctx.schedule` to schedule `msg` to be sent to `target` after `delay`
|
||||
* FIXME what about events scheduled through the scheduler?
|
||||
*/
|
||||
final case class Scheduled[U](delay: FiniteDuration, target: ActorRef[U], msg: U) extends Effect
|
||||
def scheduled[U](delay: FiniteDuration, target: ActorRef[U], msg: U): Scheduled[U] =
|
||||
Scheduled(delay, target, msg)
|
||||
|
||||
/**
|
||||
* Used to represent an empty list of effects - in other words, the behavior didn't do anything observable
|
||||
*/
|
||||
case object NoEffects extends NoEffects
|
||||
def noEffects(): NoEffects = NoEffects
|
||||
|
||||
/**
|
||||
* Used for NoEffects expectations by type
|
||||
*/
|
||||
sealed trait NoEffects extends Effect
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,9 +16,6 @@ import java.util.concurrent.TimeUnit;
|
|||
import static akka.Done.done;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* Copyright (C) 2009-2018 Lightbend Inc. <http://www.lightbend.com>
|
||||
*/
|
||||
public class ActorTestKitTest extends JUnitSuite {
|
||||
|
||||
@ClassRule
|
||||
|
|
|
|||
|
|
@ -0,0 +1,298 @@
|
|||
/*
|
||||
* Copyright (C) 2018 Lightbend Inc. <https://www.lightbend.com>
|
||||
*/
|
||||
|
||||
package akka.actor.testkit.typed.javadsl;
|
||||
|
||||
import akka.Done;
|
||||
import akka.actor.testkit.typed.Effect;
|
||||
import akka.actor.typed.ActorRef;
|
||||
import akka.actor.typed.Behavior;
|
||||
import akka.actor.typed.Props;
|
||||
import akka.actor.typed.javadsl.Behaviors;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.scalatest.junit.JUnitSuite;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class BehaviorTestKitTest extends JUnitSuite {
|
||||
|
||||
public interface Command {
|
||||
}
|
||||
|
||||
public static class SpawnWatchAndUnWatch implements Command {
|
||||
private final String name;
|
||||
|
||||
public SpawnWatchAndUnWatch(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SpawnAndWatchWith implements Command {
|
||||
private final String name;
|
||||
|
||||
public SpawnAndWatchWith(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SpawnSession implements Command {
|
||||
private final ActorRef<ActorRef<String>> replyTo;
|
||||
private final ActorRef<String> sessionHandler;
|
||||
|
||||
public SpawnSession(ActorRef<ActorRef<String>> replyTo, ActorRef<String> sessionHandler) {
|
||||
this.replyTo = replyTo;
|
||||
this.sessionHandler = sessionHandler;
|
||||
}
|
||||
}
|
||||
|
||||
public static class KillSession implements Command {
|
||||
private final ActorRef<String> session;
|
||||
private final ActorRef<Done> replyTo;
|
||||
|
||||
public KillSession(ActorRef<String> session, ActorRef<Done> replyTo) {
|
||||
this.session = session;
|
||||
this.replyTo = replyTo;
|
||||
}
|
||||
}
|
||||
|
||||
public static class CreateMessageAdapter implements Command {
|
||||
private final Class<Object> clazz;
|
||||
private final Function<Object, Command> f;
|
||||
|
||||
public CreateMessageAdapter(Class clazz, Function<Object, Command> f) {
|
||||
this.clazz = clazz;
|
||||
this.f = f;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SpawnChildren implements Command {
|
||||
private final int numberOfChildren;
|
||||
|
||||
public SpawnChildren(int numberOfChildren) {
|
||||
this.numberOfChildren = numberOfChildren;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SpawnChildrenAnonymous implements Command {
|
||||
private final int numberOfChildren;
|
||||
|
||||
public SpawnChildrenAnonymous(int numberOfChildren) {
|
||||
this.numberOfChildren = numberOfChildren;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SpawnChildrenWithProps implements Command {
|
||||
private final int numberOfChildren;
|
||||
private final Props props;
|
||||
|
||||
public SpawnChildrenWithProps(int numberOfChildren, Props props) {
|
||||
this.numberOfChildren = numberOfChildren;
|
||||
this.props = props;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SpawnChildrenAnonymousWithProps implements Command {
|
||||
private final int numberOfChildren;
|
||||
private final Props props;
|
||||
|
||||
public SpawnChildrenAnonymousWithProps(int numberOfChildren, Props props) {
|
||||
this.numberOfChildren = numberOfChildren;
|
||||
this.props = props;
|
||||
}
|
||||
}
|
||||
|
||||
public interface Action {
|
||||
}
|
||||
|
||||
private static Behavior<Action> childInitial = Behaviors.ignore();
|
||||
|
||||
private static Props props = Props.empty().withDispatcherFromConfig("cat");
|
||||
|
||||
private static Behavior<Command> behavior = Behaviors.receive(Command.class)
|
||||
.onMessage(SpawnChildren.class, (ctx, msg) -> {
|
||||
IntStream.range(0, msg.numberOfChildren).forEach(i -> {
|
||||
ctx.spawn(childInitial, "child" + i);
|
||||
});
|
||||
return Behaviors.same();
|
||||
})
|
||||
.onMessage(SpawnChildrenAnonymous.class, (ctx, msg) -> {
|
||||
IntStream.range(0, msg.numberOfChildren).forEach(i -> {
|
||||
ctx.spawnAnonymous(childInitial);
|
||||
});
|
||||
return Behaviors.same();
|
||||
})
|
||||
.onMessage(SpawnChildrenWithProps.class, (ctx, msg) -> {
|
||||
IntStream.range(0, msg.numberOfChildren).forEach(i -> {
|
||||
ctx.spawn(childInitial, "child" + i, msg.props);
|
||||
});
|
||||
return Behaviors.same();
|
||||
})
|
||||
.onMessage(SpawnChildrenAnonymousWithProps.class, (ctx, msg) -> {
|
||||
IntStream.range(0, msg.numberOfChildren).forEach(i -> {
|
||||
ctx.spawnAnonymous(childInitial, msg.props);
|
||||
});
|
||||
return Behaviors.same();
|
||||
})
|
||||
.onMessage(CreateMessageAdapter.class, (ctx, msg) -> {
|
||||
ctx.messageAdapter(msg.clazz, msg.f);
|
||||
return Behaviors.same();
|
||||
})
|
||||
.onMessage(SpawnWatchAndUnWatch.class, (ctx, msg) -> {
|
||||
ActorRef<Action> c = ctx.spawn(childInitial, msg.name);
|
||||
ctx.watch(c);
|
||||
ctx.unwatch(c);
|
||||
return Behaviors.same();
|
||||
})
|
||||
.onMessage(SpawnAndWatchWith.class, (ctx, msg) -> {
|
||||
ActorRef<Action> c = ctx.spawn(childInitial, msg.name);
|
||||
ctx.watchWith(c, msg);
|
||||
return Behaviors.same();
|
||||
})
|
||||
.onMessage(SpawnSession.class, (ctx, msg) -> {
|
||||
ActorRef<String> session = ctx.spawnAnonymous(Behaviors.receiveMessage( m -> {
|
||||
msg.sessionHandler.tell(m);
|
||||
return Behaviors.same();
|
||||
}));
|
||||
msg.replyTo.tell(session);
|
||||
return Behaviors.same();
|
||||
})
|
||||
.onMessage(KillSession.class, (ctx, msg) -> {
|
||||
ctx.stop(msg.session);
|
||||
msg.replyTo.tell(Done.getInstance());
|
||||
return Behaviors.same();
|
||||
})
|
||||
.build();
|
||||
|
||||
|
||||
@Test
|
||||
public void allowAssertionsOnEffectType() {
|
||||
BehaviorTestKit<Command> test = BehaviorTestKit.create(behavior);
|
||||
test.run(new SpawnChildren(1));
|
||||
Effect.Spawned spawned = test.expectEffectClass(Effect.Spawned.class);
|
||||
assertEquals(spawned.childName(), "child0");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void allowExpectingNoEffects() {
|
||||
BehaviorTestKit<Command> test = BehaviorTestKit.create(behavior);
|
||||
test.expectEffect(Effects.noEffects());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void allowsExpectingNoEffectByType() {
|
||||
BehaviorTestKit<Command> test = BehaviorTestKit.create(behavior);
|
||||
test.expectEffectClass(Effect.NoEffects.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void returnEffectsThatHaveTakenPlace() {
|
||||
BehaviorTestKit<Command> test = BehaviorTestKit.create(behavior);
|
||||
assertFalse(test.hasEffects());
|
||||
test.run(new SpawnChildrenAnonymous(1));
|
||||
assertTrue(test.hasEffects());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("Not supported for Java API")
|
||||
public void allowAssertionsUsingPartialFunctions() {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void spawnChildrenWithNoProps() {
|
||||
BehaviorTestKit<Command> test = BehaviorTestKit.create(behavior);
|
||||
test.run(new SpawnChildren(2));
|
||||
List<Effect> allEffects = test.getAllEffects();
|
||||
assertEquals(
|
||||
Arrays.asList(Effects.spawned(childInitial, "child0"), Effects.spawned(childInitial, "child1", Props.empty())),
|
||||
allEffects
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void spawnChildrenWithProps() {
|
||||
BehaviorTestKit<Command> test = BehaviorTestKit.create(behavior);
|
||||
test.run(new SpawnChildrenWithProps(1, props));
|
||||
assertEquals(props, test.expectEffectClass(Effect.Spawned.class).props());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void spawnAnonChildrenWithNoProps() {
|
||||
BehaviorTestKit<Command> test = BehaviorTestKit.create(behavior);
|
||||
test.run(new SpawnChildrenAnonymous(2));
|
||||
List<Effect> allEffects = test.getAllEffects();
|
||||
assertEquals(
|
||||
Arrays.asList(Effects.spawnedAnonymous(childInitial), Effects.spawnedAnonymous(childInitial, Props.empty())),
|
||||
allEffects
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void spawnAnonChildrenWithProps() {
|
||||
BehaviorTestKit<Command> test = BehaviorTestKit.create(behavior);
|
||||
test.run(new SpawnChildrenAnonymousWithProps(1, props));
|
||||
assertEquals(props, test.expectEffectClass(Effect.SpawnedAnonymous.class).props());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createMessageAdapters() {
|
||||
BehaviorTestKit<Command> test = BehaviorTestKit.create(behavior);
|
||||
SpawnChildren adaptedMessage = new SpawnChildren(1);
|
||||
test.run(new CreateMessageAdapter(String.class, o -> adaptedMessage));
|
||||
Effect.MessageAdapter mAdapter = test.expectEffectClass(Effect.MessageAdapter.class);
|
||||
assertEquals(String.class, mAdapter.messageClass());
|
||||
assertEquals(adaptedMessage, mAdapter.adaptFunction().apply("anything"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void recordWatching() {
|
||||
BehaviorTestKit<Command> test = BehaviorTestKit.create(behavior);
|
||||
test.run(new SpawnWatchAndUnWatch("name"));
|
||||
ActorRef<Object> child = test.childInbox("name").getRef();
|
||||
test.expectEffectClass(Effect.Spawned.class);
|
||||
assertEquals(child, test.expectEffectClass(Effect.Watched.class).other());
|
||||
assertEquals(child, test.expectEffectClass(Effect.Unwatched.class).other());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void recordWatchWith() {
|
||||
BehaviorTestKit<Command> test = BehaviorTestKit.create(behavior);
|
||||
test.run(new SpawnWatchAndUnWatch("name"));
|
||||
ActorRef<Object> child = test.childInbox("name").getRef();
|
||||
test.expectEffectClass(Effect.Spawned.class);
|
||||
assertEquals(child, test.expectEffectClass(Effect.Watched.class).other());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void allowRetrievingAndKilling() {
|
||||
BehaviorTestKit<Command> test = BehaviorTestKit.create(behavior);
|
||||
TestInbox<ActorRef<String>> i = TestInbox.create();
|
||||
TestInbox<String> h = TestInbox.create();
|
||||
test.run(new SpawnSession(i.getRef(), h.getRef()));
|
||||
|
||||
ActorRef<String> sessionRef = i.receiveMessage();
|
||||
assertFalse(i.hasMessages());
|
||||
Effect.SpawnedAnonymous s = test.expectEffectClass(Effect.SpawnedAnonymous.class);
|
||||
assertEquals(sessionRef, s.ref());
|
||||
|
||||
BehaviorTestKit<String> session = test.childTestKit(sessionRef);
|
||||
session.run("hello");
|
||||
assertEquals(Collections.singletonList("hello"), h.getAllReceived());
|
||||
|
||||
TestInbox<Done> d = TestInbox.create();
|
||||
test.run(new KillSession(sessionRef, d.getRef()));
|
||||
|
||||
assertEquals(Collections.singletonList(Done.getInstance()), d.getAllReceived());
|
||||
test.expectEffectClass(Effect.Stopped.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -7,11 +7,14 @@ package akka.actor.testkit.typed.scaladsl
|
|||
import akka.Done
|
||||
import akka.actor.typed.scaladsl.Behaviors
|
||||
import akka.actor.typed.{ ActorRef, Behavior, Props }
|
||||
import akka.actor.testkit.typed.scaladsl.Effects.{ NoEffects, Spawned, SpawnedAdapter, SpawnedAnonymous, SpawnedAnonymousAdapter, Watched, Unwatched }
|
||||
import akka.actor.testkit.typed.Effect
|
||||
import akka.actor.testkit.typed.Effect._
|
||||
import akka.actor.testkit.typed.scaladsl.BehaviorTestKitSpec.{ Child, Father }
|
||||
import akka.actor.testkit.typed.scaladsl.BehaviorTestKitSpec.Father._
|
||||
import org.scalatest.{ Matchers, WordSpec }
|
||||
|
||||
import scala.reflect.ClassTag
|
||||
|
||||
object BehaviorTestKitSpec {
|
||||
object Father {
|
||||
|
||||
|
|
@ -25,6 +28,7 @@ object BehaviorTestKitSpec {
|
|||
case class SpawnAnonymousWithProps(numberOfChildren: Int, props: Props) extends Command
|
||||
case object SpawnAdapter extends Command
|
||||
case class SpawnAdapterWithName(name: String) extends Command
|
||||
case class CreateMessageAdapter[U](messageClass: Class[U], f: U ⇒ Command) extends Command
|
||||
case class SpawnAndWatchUnwatch(name: String) extends Command
|
||||
case class SpawnAndWatchWith(name: String) extends Command
|
||||
case class SpawnSession(replyTo: ActorRef[ActorRef[String]], sessionHandler: ActorRef[String]) extends Command
|
||||
|
|
@ -82,6 +86,10 @@ object BehaviorTestKitSpec {
|
|||
ctx.stop(session)
|
||||
replyTo ! Done
|
||||
Behaviors.same
|
||||
case CreateMessageAdapter(messageClass, f) ⇒
|
||||
ctx.messageAdapter(f)(ClassTag(messageClass))
|
||||
Behaviors.same
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -103,14 +111,14 @@ object BehaviorTestKitSpec {
|
|||
|
||||
class BehaviorTestKitSpec extends WordSpec with Matchers {
|
||||
|
||||
private val props = Props.empty
|
||||
private val props = Props.empty.withDispatcherFromConfig("cat")
|
||||
|
||||
"BehaviorTestKit" must {
|
||||
|
||||
"allow assertions on effect type" in {
|
||||
val testkit = BehaviorTestKit[Father.Command](Father.init)
|
||||
testkit.run(SpawnAnonymous(1))
|
||||
val spawnAnonymous = testkit.expectEffectType[Effects.SpawnedAnonymous[_]]
|
||||
val spawnAnonymous = testkit.expectEffectType[Effect.SpawnedAnonymous[_]]
|
||||
spawnAnonymous.props should ===(Props.empty)
|
||||
}
|
||||
|
||||
|
|
@ -209,6 +217,14 @@ class BehaviorTestKitSpec extends WordSpec with Matchers {
|
|||
}
|
||||
}
|
||||
|
||||
"BehaviorTestkit's messageAdapter" must {
|
||||
"create message adapters and record effects" in {
|
||||
val testkit = BehaviorTestKit[Father.Command](Father.init)
|
||||
testkit.run(CreateMessageAdapter(classOf[String], (_: String) ⇒ SpawnChildren(1)))
|
||||
testkit.expectEffectType[MessageAdapter[String, Command]]
|
||||
}
|
||||
}
|
||||
|
||||
"BehaviorTestkit's run" can {
|
||||
"run behaviors with messages without canonicalization" in {
|
||||
val testkit = BehaviorTestKit[Father.Command](Father.init)
|
||||
|
|
@ -224,9 +240,9 @@ class BehaviorTestKitSpec extends WordSpec with Matchers {
|
|||
testkit.run(SpawnAndWatchUnwatch("hello"))
|
||||
val child = testkit.childInbox("hello").ref
|
||||
testkit.retrieveAllEffects() should be(Seq(
|
||||
Spawned(Child.initial, "hello", Props.empty),
|
||||
Watched(child),
|
||||
Unwatched(child)
|
||||
Effects.spawned(Child.initial, "hello", Props.empty),
|
||||
Effects.watched(child),
|
||||
Effects.unwatched(child)
|
||||
))
|
||||
}
|
||||
|
||||
|
|
@ -235,8 +251,8 @@ class BehaviorTestKitSpec extends WordSpec with Matchers {
|
|||
testkit.run(SpawnAndWatchWith("hello"))
|
||||
val child = testkit.childInbox("hello").ref
|
||||
testkit.retrieveAllEffects() should be(Seq(
|
||||
Spawned(Child.initial, "hello", Props.empty),
|
||||
Watched(child)
|
||||
Effects.spawned(Child.initial, "hello", Props.empty),
|
||||
Effects.watched(child)
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
@ -250,7 +266,7 @@ class BehaviorTestKitSpec extends WordSpec with Matchers {
|
|||
|
||||
val sessionRef = i.receiveMessage()
|
||||
i.hasMessages shouldBe false
|
||||
val (s: SpawnedAnonymous[_]) :: Nil = testkit.retrieveAllEffects()
|
||||
val s = testkit.expectEffectType[SpawnedAnonymous[_]]
|
||||
// must be able to get the created ref, even without explicit reply
|
||||
s.ref shouldBe sessionRef
|
||||
|
||||
|
|
@ -262,6 +278,7 @@ class BehaviorTestKitSpec extends WordSpec with Matchers {
|
|||
testkit.run(KillSession(sessionRef, d.ref))
|
||||
|
||||
d.receiveAll shouldBe Seq(Done)
|
||||
testkit.expectEffectType[Stopped]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ package akka.actor.testkit.typed.scaladsl
|
|||
//#imports
|
||||
import akka.actor.typed._
|
||||
import akka.actor.typed.scaladsl._
|
||||
import akka.actor.testkit.typed.scaladsl.Effects._
|
||||
import akka.actor.testkit.typed.Effect._
|
||||
//#imports
|
||||
import org.scalatest.{ Matchers, WordSpec }
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue