From 296fc4148f3679dc96b9fd25ed79b4a98155ba3e Mon Sep 17 00:00:00 2001 From: Anvar Kiekbaev Date: Thu, 2 May 2019 20:46:53 +0300 Subject: [PATCH] Testing user interpreter --- .../chepiov/tomodoro/actors/UserActor.scala | 4 +- .../interpreters/UserInterpreterSpec.scala | 91 +++++++++++++++++++ 2 files changed, 93 insertions(+), 2 deletions(-) create mode 100644 src/test/scala/org/chepiov/tomodoro/interpreters/UserInterpreterSpec.scala diff --git a/src/main/scala/org/chepiov/tomodoro/actors/UserActor.scala b/src/main/scala/org/chepiov/tomodoro/actors/UserActor.scala index 715e4f8..0f23f4b 100644 --- a/src/main/scala/org/chepiov/tomodoro/actors/UserActor.scala +++ b/src/main/scala/org/chepiov/tomodoro/actors/UserActor.scala @@ -133,9 +133,9 @@ case object UserActor { ): Props = Props(new UserActor(chatId, chat, timeUnit, defaultSettings, snapshotInterval)) - final case class CommandMsg(cmd: Command, ask: () => Unit) + final case class CommandMsg(cmd: Command, ack: () => Unit) - final case class QueryMsg(query: UserInfoQuery, ask: () => Unit) + final case class QueryMsg(query: UserInfoQuery, ack: () => Unit) final case class MessageSentEvent(message: TSendMessage) diff --git a/src/test/scala/org/chepiov/tomodoro/interpreters/UserInterpreterSpec.scala b/src/test/scala/org/chepiov/tomodoro/interpreters/UserInterpreterSpec.scala new file mode 100644 index 0000000..4cff444 --- /dev/null +++ b/src/test/scala/org/chepiov/tomodoro/interpreters/UserInterpreterSpec.scala @@ -0,0 +1,91 @@ +package org.chepiov.tomodoro.interpreters + +import akka.actor.{Actor, ActorRef, ActorSystem, Props} +import akka.testkit.{ImplicitSender, TestKit} +import cats.Id +import cats.effect.{ContextShift, IO} +import cats.syntax.flatMap._ +import com.typesafe.config.ConfigFactory +import io.chrisdavenport.log4cats.Logger +import io.chrisdavenport.log4cats.slf4j.Slf4jLogger +import org.chepiov.tomodoro.actors.UserActor.{CommandMsg, QueryMsg} +import org.chepiov.tomodoro.algebras.User.{Continue, GetState} +import org.scalatest.{BeforeAndAfterAll, Matchers, WordSpecLike} + +import scala.concurrent.ExecutionContext +import scala.concurrent.duration._ + +//noinspection AppropriateActorConstructorNotFound +@SuppressWarnings( + Array( + "org.wartremover.warts.NonUnitStatements", + "org.wartremover.warts.Product", + "org.wartremover.warts.Serializable" + ) +) +class UserInterpreterSpec + extends TestKit(ActorSystem("test-system", ConfigFactory.load("application-persistence-test"))) with WordSpecLike + with Matchers with BeforeAndAfterAll with ImplicitSender { + import UserInterpreterSpec._ + + override def afterAll: Unit = { + TestKit.shutdownActorSystem(system) + } + + val userActor: ActorRef = system.actorOf(Props(classOf[SuccessUserActor], testActor)) + val badUserActor: ActorRef = system.actorOf(Props[FailureUserActor]) + + implicit val cs: ContextShift[IO] = IO.contextShift(ExecutionContext.global) + + implicit def logger: Logger[IO] = Slf4jLogger.getLogger[IO] + + "User" should { + "deliver actions to actor" in { + val program: IO[Unit] = for { + user <- UserInterpreter[Id, IO](1L, userActor) + _ <- user.advance(Continue(0)) + _ <- user.info(GetState) + } yield { + expectMsgAllOf(Continue(0), GetState) + () + } + program.unsafeRunSync() + } + } + + it should { + "handle errors" in { + val program: IO[Unit] = for { + user <- UserInterpreter[Id, IO](1L, badUserActor) + advance <- IO.race(user.advance(Continue(0)), IO.timer(ExecutionContext.global).sleep(3.seconds)) + query <- IO.race(user.info(GetState), IO.timer(ExecutionContext.global).sleep(3.seconds)) + } yield { + advance.isRight shouldBe true + query.isRight shouldBe true + () + } + program.unsafeRunSync() + } + } +} + +@SuppressWarnings(Array("org.wartremover.warts.Any", "org.wartremover.warts.Throw")) +case object UserInterpreterSpec { + class SuccessUserActor(probe: ActorRef) extends Actor { + override def receive: Receive = { + case CommandMsg(cmd, ack) => + probe ! cmd + ack() + case QueryMsg(query, ack) => + probe ! query + ack() + } + } + + class FailureUserActor extends Actor { + override def receive: Receive = { + case CommandMsg(_, _) => throw new RuntimeException() + case QueryMsg(_, _) => throw new RuntimeException() + } + } +}