Hi. I’m running into the following problem.
I don’t know if I’m missing something, or I’m hitting a bug.
I have a typed actor-behaviour like this:
case class GreetMe(message: String, replyTo: ActorRef[Greet])
case class Greet(response: String)
val greetBehaviour: Behavior[GreetMe] = Behaviors.receive {
case (ctx, GreetMe(m, to)) => to ! Greet(m)
Behaviors.same
}
Then I have a htttp-route that should, on an incoming request, create a response which contains a ‘Greet’ (coming from the actor).
The route uses the ask-pattern to ask a ‘Greet’ from an actorRef[GreetMe].
This is the route:
implicit val scheduler: Scheduler
implicit val timeout: Timeout
implicit val ec: ExecutionContext
val greetActor: ActorRef[GreetMe]
val route = onComplete(getGreet){
case scala.util.Success(msg) => complete(msg)
case scala.util.Failure(exception) => complete(exception.getMessage)
}
def getGreet: Future[String] = {
val fut: Future[Greet] = greetActor ? (replyTo => GreetMe("hello", replyTo))
fut.map(resp => {
resp.response
})
}
All of this works fine and as expected.
But the problem is when I create a test for this route.
The test checks whether the actorRef[GreetMe] received the expected ‘GreetMe’ message.
The actual receiving of the ‘Greet’-reply is not checked because this test doesn’t have such an actor, only an inbox. The correctness of the Behaviour[GreetMe] is tested in another test.
class RoutesSpec extends WordSpec with Matchers with ScalatestRouteTest with Routes {
val inbox: TestInbox[GreetMe] = TestInbox[GreetMe]()
override val greetActor: ActorRef[GreetMe] = inbox.ref
implicit override val ec = system.dispatcher
implicit val scheduler: Scheduler = system.scheduler
implicit val timeout: Timeout = Timeout(3.seconds)
"the greeter" should {
"return a greet" in {
val request = HttpRequest(uri = "/hi")
request ~> route ~> check {
val receivedMesssage = inbox.receiveMessage()
receivedMesssage.isInstanceOf[GreetMe] shouldBe true
}
}
}
}
It fails with this exception, which is thrown on the line of the ask:
09:48:58.754 [th-RoutesSpec-akka.actor.default-dispatcher-2] ERROR akka.actor.ActorSystemImpl - Error during processing of request: 'no provider'. Completing with 500 Internal Server Error response. To change default exception handling behavior, provide a custom ExceptionHandler.
java.lang.UnsupportedOperationException: no provider
at akka.actor.testkit.typed.internal.FunctionRef.provider(StubbedActorContext.scala:48)
at akka.actor.typed.scaladsl.AskPattern$PromiseRef.<init>(AskPattern.scala:127)
at akka.actor.typed.scaladsl.AskPattern$.akka$actor$typed$scaladsl$AskPattern$$askUntyped(AskPattern.scala:138)
at akka.actor.typed.scaladsl.AskPattern$Askable$.ask$extension(AskPattern.scala:99)
at akka.actor.typed.scaladsl.AskPattern$Askable$.$qmark$extension(AskPattern.scala:63)
at th.Routes.getGreet(RouteTest.scala:34)
at th.Routes.getGreet$(RouteTest.scala:33)
at th.RoutesSpec.getGreet(RouteTest.scala:40)
at th.Routes.$anonfun$route$1(RouteTest.scala:29)
at akka.http.scaladsl.server.directives.FutureDirectives.$anonfun$onComplete$2(FutureDirectives.scala:37)
at akka.http.scaladsl.server.directives.ExecutionDirectives.$anonfun$handleExceptions$2(ExecutionDirectives.scala:32)
at akka.http.scaladsl.testkit.RouteTest$TildeArrow$$anon$1.apply(RouteTest.scala:161)
at akka.http.scaladsl.testkit.RouteTest$TildeArrow$$anon$1.apply(RouteTest.scala:149)
at akka.http.scaladsl.testkit.RouteTest$WithTransformation2.$tilde$greater(RouteTest.scala:124)
at th.RoutesSpec.$anonfun$new$2(RouteTest.scala:49)
at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
It refers to this line: https://github.com/akka/akka/blob/v2.5.23/akka-actor-testkit-typed/src/main/scala/akka/actor/testkit/typed/internal/StubbedActorContext.scala#L48
Knowing that it actually works in the application, I’m thinking that I’m missing something in the setup of the test. But there are no compile warnings/errors.
Thanks for any input!