I have the following spec2 test
import akka.testkit._
import akka.actor.ActorSystem
import com.github.nfldb.config.{NflDbApiActorSystemConfig, NflDbApiDbConfigTest}
import org.scalatest.MustMatchers
import org.specs2.mutable.Specification
import spray.testkit.Specs2RouteTest
import spray.routing.HttpService
import spray.http.StatusCodes._
import spray.json.DefaultJsonProtocol._
import spray.httpx.SprayJsonSupport._
import concurrent.duration._
/**
* Created by chris on 8/25/15.
*/
class NflPlayerScoringSvcTest extends Specification with Specs2RouteTest with NflPlayerScoringService
with NflDbApiDbConfigTest with NflDbApiActorSystemConfig {
import PlayerScoreProtocol.playerScoreProtocol
implicit def actorRefFactory = actorSystem
implicit def default(implicit system: ActorSystem) = RouteTestTimeout(new DurationInt(5).second.dilated(system))
"NflPlayerScoringSvc" should {
"return hello" in {
Get("/hello") ~> nflPlayerScoringServiceRoutes ~> check {
responseAs[String] must contain("Say hello")
}
}
"calculate a player's score for a given week" in {
import PlayerScoreProtocol.playerScoreProtocol
Get("/playerScore?playerId=00-0031237&gsisId=2015081551") ~> nflPlayerScoringServiceRoutes ~> check {
val playerScore : DfsNflScoringEngineComponent.PlayerScore = responseAs[DfsNflScoringEngineComponent.PlayerScore]
println(playerScore.playerId == "00-0031237") //evaluates to true
playerScore.playerId must be ("00-0031237")
}
}
}
}
As you can see in my comment, my println statement asking for the equivalence of playerScore.playerId == "00-0031237 evalutes to true. However on the next line, my test fails saying that
[error] '00-0031237' is not the same as '00-0031237' (NflPlayerScoringSvcTest.scala:37)
How is this happening?
Did you tried this:
playerScore.playerId must beEqualTo("00-0031237")
Related
I have a simple test case which is using TestActorRef and eventually to verify a timeout call of a method. Here is details of 3 file sources:
TestRestUtility.scala
import play.api.http.HttpVerbs
import play.api.libs.ws.WSClient
import javax.inject.Inject
import scala.concurrent.Future
class TestRestUtility #Inject()(ws: WSClient) extends HttpVerbs {
import scala.concurrent.ExecutionContext.Implicits.global
def getHealthStatus(): Future[Int] = {
ws.url("https://www.google.com").get().map { response =>
response.status
}
}
}
TestHealthCheckActor.scala
import akka.actor.{Actor, ActorLogging, Props}
import play.api.http.Status
import javax.inject.Inject
import scala.concurrent.Future
import scala.concurrent.duration.{DurationInt, FiniteDuration}
import scala.util.{Failure, Success}
object TestHealthCheckActor {
def props(testRestUtility: TestRestUtility): Props = {
Props(new TestHealthCheckActor(testRestUtility: TestRestUtility))
}
}
class TestHealthCheckActor #Inject()(testRestUtility: TestRestUtility)
extends Actor with ActorLogging with Status {
import context.dispatcher
val checkPeriod: FiniteDuration = 1.seconds
var apiStatus: Int = _
override def preStart(): Unit = {
context.system.scheduler.scheduleWithFixedDelay(
0.milliseconds,
checkPeriod,
self,
RefreshHealthStatus
)
}
override def receive: Receive = {
case RefreshHealthStatus =>
val health: Future[Int] = testRestUtility.getHealthStatus()
health.onComplete({
case Success(result) =>
result match {
case OK => apiStatus = Status.OK
case _ => apiStatus = Status.REQUEST_TIMEOUT
}
case Failure(e) =>
println(e)
})
}
}
TestSpec.scala
import akka.actor.{ActorSystem, PoisonPill}
import akka.testkit.{ImplicitSender, TestActorRef, TestKit}
import org.mockito.Mockito
import org.mockito.Mockito.{times, verify, when}
import org.scalatest
import org.scalatest.{BeforeAndAfterAll, BeforeAndAfterEach}
import org.scalatest.concurrent.Eventually
import org.scalatest.matchers.should.Matchers
import org.scalatest.time.Span
import org.scalatest.wordspec.AnyWordSpecLike
import org.scalatestplus.mockito.MockitoSugar
import play.api.http.Status
import scala.concurrent.Future
class TestSpec extends TestKit(ActorSystem("HealthCheckActorSpec")) with AnyWordSpecLike with Matchers
with BeforeAndAfterEach with MockitoSugar with ImplicitSender with Eventually with BeforeAndAfterAll with Status with TestHarnessConstants {
import scala.concurrent.ExecutionContext.Implicits.global
var mockTestRestUtility: TestRestUtility = _
"HealthCheckActor" should {
"time out and call subscription api" in {
mockTestRestUtility = mock[TestRestUtility]
when(mockTestRestUtility.getHealthStatus()).thenReturn(Future(OK)).thenReturn(Future(OK)).thenReturn(Future(OK))
val healthCheckActorShortPeriod: TestActorRef[TestHealthCheckActor] = TestActorRef(TestHealthCheckActor.props(mockTestRestUtility))
eventually(timeout(Span(9, scalatest.time.Seconds)), interval(Span(1, scalatest.time.Seconds))) {
verify(mockTestRestUtility, Mockito.atLeast(3)).getHealthStatus()
}
healthCheckActorShortPeriod ! PoisonPill
}
}
}
As description about eventually in "scalatest-core_2.12-3.2.3-sources.jar", it tolerates unsuccessful attempts before giving up, so the test case is expected to have 3 calls the method getHealthStatus() to be successful as the returned value from mock. But I got a failed test case with below error message. I don't know why the method was called only one time:
testRestUtility.getHealthStatus();
Wanted *at least* 3 times:
-> at com.deere.isg.ingest.supporttool.testharness.TestSpec.$anonfun$new$8(TestSpec.scala:44)
But was 1 time:
-> at com.deere.isg.ingest.supporttool.testharness.TestHealthCheckActor$$anonfun$receive$1.applyOrElse(TestHealthCheckActor.scala:36)
org.mockito.exceptions.verification.TooFewActualInvocations:
testRestUtility.getHealthStatus();
Wanted *at least* 3 times:
-> at com.deere.isg.ingest.supporttool.testharness.TestSpec.$anonfun$new$8(TestSpec.scala:44)
But was 1 time:
-> at com.deere.isg.ingest.supporttool.testharness.TestHealthCheckActor$$anonfun$receive$1.applyOrElse(TestHealthCheckActor.scala:36)
Future(OK) will be considered successful by eventually because it doesn't throw an exception (technically neither would a failed Future, unless you unwrapped it in the eventually). Since the first call succeeded, eventually won't make any attempts after the first.
Basically I trying to get data from database using akka http. if i pass (EmployeeRepo.findAll()) directly in api then it show all data but while using actor it shows cast error....
here problem for data fetching only please solve it
this is my EmployeeRepo-----------------------------------
package org.repo
import org.data.Employee
import org.db.DbConfig
import org.mongodb.scala.MongoCollection
import org.utils.JsonUtils
import org.mongodb.scala.bson.conversions.Bson
import org.mongodb.scala.model.Filters.equal
import org.mongodb.scala.model.FindOneAndUpdateOptions
import org.mongodb.scala.model.Updates.{combine, set}
import scala.concurrent.Future
object EmployeeRepo extends JsonUtils{
private val employeeDoc:MongoCollection[Employee]=DbConfig.employees
def createCollection()={
DbConfig.database.createCollection("employee").subscribe(
(result)=>println(s"$result"),
e=>println(e.getLocalizedMessage),
()=>println("complete")
)
}
def insertData(emp:Employee)={
employeeDoc.insertOne(emp).toFuture()
}
def findAll()= employeeDoc.find().toFuture()
def update(emp:Employee,id:String)=
employeeDoc
.findOneAndUpdate(equal("_id", id),
setBsonValue(emp),
FindOneAndUpdateOptions().upsert(true)).toFuture()
def delete(id:String)=
employeeDoc.deleteOne(equal("_id",id)).toFuture()
private def setBsonValue(emp:Employee)={
combine(
set("name",emp.name),
set("dateOfBirth",emp.dateOfBirth)
)
}
}
============EMployeeService------------
package org.service
import java.time.LocalDate
import java.time.format.DateTimeFormatter
import java.util.UUID
import akka.NotUsed
import akka.actor.ActorSystem
import akka.stream.ActorMaterializer
import akka.stream.scaladsl.Source
import org.data.Employee
import org.domain.EmployeeRequest
import org.repo.EmployeeRepo
import scala.concurrent.Future
class EmployeeService {
implicit val system=ActorSystem("Employeee")
implicit val materializer=ActorMaterializer
import system.dispatcher
def saveEmployeeData= (employeeRequest:EmployeeRequest) => {
val employeeDoc:Employee=employeeMapperWithNewId(employeeRequest)
EmployeeRepo.insertData(employeeDoc)
}
def findAll={
EmployeeRepo.findAll()
}
def update(employeeRequest: EmployeeRequest,id:String)={
val employeeDoc=employeeMapperWithNewId(employeeRequest)
EmployeeRepo.update(emp = employeeDoc,id)
}
def delete(id:String)=EmployeeRepo.delete(id)
private def employeeMapperWithNewId(employee:EmployeeRequest)={
Employee(name=employee.name,dateOfBirth = LocalDate.parse(employee.dateOfBirth, DateTimeFormatter.ISO_DATE),
_id=UUID.randomUUID.toString)
}
}
-----------------EmployeeActor------
package org.actor
import akka.actor.{Actor, ActorLogging}
import org.actor.EmployeeActor.{Delete, Save, SearchAll, Update}
import org.data.Employee
import org.domain.EmployeeRequest
import org.service.EmployeeService
object EmployeeActor {
case class Save(emp: EmployeeRequest)
case object SearchAll
case class Update(emp: EmployeeRequest, id: String)
case class Delete(id: String)
}
class
EmployeeActor extends Actor with ActorLogging {
private val employeeService: EmployeeService = new EmployeeService()
override def receive: Receive = {
case Save(emp) =>
log.info(s"recevied msg saved with employee :$emp")
sender() ! employeeService.saveEmployeeData(emp)
case SearchAll =>
log.info("received msg find ALL")
sender() ! employeeService.findAll
case Update(emp, id) =>
log.info(s"received update msg for id $id and employee $emp")
sender() ! employeeService.update(emp, id)
case Delete(id) =>
log.info(s"received msg for deleting employee of id $id")
sender() ! employeeService.delete(id)
case _ =>
log.debug("Unhandled msg")
}
}
---------------EmployeeRoute----
package org
import akka.actor.{ActorSystem, Props}
import akka.http.scaladsl.model.{ContentTypes, HttpEntity, StatusCodes}
import akka.stream.ActorMaterializer
import org.actor.EmployeeActor
import org.utils.{JsonUtils, TimeUtils}
import akka.http.scaladsl.server.Directives._
import akka.{NotUsed, util}
import akka.util.{ByteString, Timeout}
import org.data.Employee
import org.domain.EmployeeRequest
import akka.pattern.{Patterns, ask}
import akka.stream.scaladsl.Source
import org.actor.EmployeeActor.{Delete, Save, SearchAll, Update}
import org.service.EmployeeService
import scala.concurrent.duration._
import spray.json._
import scala.concurrent.{Await, Future}
class EmployeeRoute extends JsonUtils{
implicit val system=ActorSystem("Employee")
implicit val materializer=ActorMaterializer
import system.dispatcher
val actor=system.actorOf(Props[EmployeeActor],"employeeActor")
val employeeService=new EmployeeService()
implicit val timeOut=Timeout(5.seconds)
val getRoute={
pathPrefix("employee"){
(pathEndOrSingleSlash & get){
complete((actor ? SearchAll).mapTo[Seq[EmployeeRequest]])
}~
( path("update") & put & parameter("id".as[String])){id=>
entity(as[EmployeeRequest]){employee=>
complete((actor ? Update(employee,id)).map(_=>StatusCodes.OK))
}
}~
post{
entity(as[EmployeeRequest]) { employee =>
complete((actor ? Save(employee)).map(_ => StatusCodes.OK))
}
}~
delete{
(path(Segment) |parameter("id".as[String])){id=>
complete((actor ? Delete(id)).map(_=>StatusCodes.OK))
}
}
}
}
}
=================Error===============
[ERROR] [09/09/2020 19:46:48.551] [web-app-akka.actor.default-dispatcher-4] [akka.actor.ActorSystemImpl(web-app)] Error during processing of request: 'Cannot cast scala.concurrent.impl.Promise$Transformation to scala.collection.immutable.Seq'. Completing with 500 Internal Server Error response. To change default exception handling behavior, provide a custom ExceptionHandler.
java.lang.ClassCastException: Cannot cast scala.concurrent.impl.Promise$Transformation to scala.collection.immutable.Seq
at java.base/java.lang.Class.cast(Class.java:3734)
at scala.concurrent.Future.$anonfun$mapTo$1(Future.scala:464)
at scala.concurrent.impl.Promise$Transformation.run(Promise.scala:430)
at scala.concurrent.ExecutionContext$parasitic$.execute(ExecutionContext.scala:164)
at scala.concurrent.impl.Promise$Transformation.submitWithValue(Promise.scala:392)
at scala.concurrent.impl.Promise$DefaultPromise.submitWithValue(Promise.scala:299)
at scala.concurrent.impl.Promise$DefaultPromise.tryComplete0(Promise.scala:249)
at scala.concurrent.impl.Promise$DefaultPromise.tryComplete(Promise.scala:242)
at akka.pattern.PromiseActorRef.$bang(AskSupport.scala:615)
at org.actor.EmployeeActor$$anonfun$receive$1.applyOrElse(EmployeeActor.scala:32)
at akka.actor.Actor.aroundReceive(Actor.scala:537)
at akka.actor.Actor.aroundReceive$(Actor.scala:535)
at org.actor.EmployeeActor.aroundReceive(EmployeeActor.scala:22)
at akka.actor.ActorCell.receiveMessage(ActorCell.scala:577)
at akka.actor.ActorCell.invoke(ActorCell.scala:547)
at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:270)
at akka.dispatch.Mailbox.run(Mailbox.scala:231)
at akka.dispatch.Mailbox.exec(Mailbox.scala:243)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1016)
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1665)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1598)
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:183)
please help me out..
You analyzed almost everything. EmployeeRepo.findAll is your problem. You should not use Futures in akka actors. pipeTo should be used instead.
Please try to update EmployeeActor
case SearchAll =>
log.info("received msg find ALL")
employeeService.findAll.pipeTo(sender())
I'm using a Silhouette v4.0 library with play framework 2.5.
And have been trying to write test code using play specs2.
But, I get the following error with my test class as below.
Error Message
[error] could not find implicit value for parameter env: com.mohiva.play.silhouette.api.Environment[utils.auth.DefaultEnv]
.withAuthenticator[DefaultEnv](identity.loginInfo)
^
Here's the test class
package controllers
import com.google.inject.AbstractModule
import org.joda.time.DateTime
import org.specs2.specification.Scope
import org.specs2.matcher._
import org.specs2.mock._
import play.api.test._
import play.api.libs.json._
import play.api.libs.json.Json
import play.api.libs.json.Reads._
import play.api.libs.functional.syntax._
import play.api.libs.concurrent.Execution.Implicits._
import play.api.libs.mailer.{ MailerClient, Email }
import play.api.inject.guice.GuiceApplicationBuilder
import play.api.inject.bind
import com.mohiva.play.silhouette.test._
import com.mohiva.play.silhouette.api._
import com.mohiva.play.silhouette.api.repositories.AuthInfoRepository
import com.mohiva.play.silhouette.api.util._
import com.mohiva.play.silhouette.impl.providers._
import net.codingwell.scalaguice.ScalaModule
import utils.auth.DefaultEnv
class TestControllerSpec extends PlaySpecification with Mockito {
"case" in new Context {
new WithApplication(application) {
val request = FakeRequest(POST, "/api/test")
.withAuthenticator[DefaultEnv](identity.loginInfo) // <-
val result = route(app, request).get
status(result) must be equalTo OK
}
}
trait Context extends Scope {
val identity = User(
loginInfo = LoginInfo(..)
..
)
implicit val env = FakeEnvironment[DefaultEnv](Seq(identity.loginInfo -> identity))
class FakeModule extends AbstractModule with ScalaModule {
def configure() = {
bind[Environment[DefaultEnv]].toInstance(env)
}
}
lazy val application = new GuiceApplicationBuilder()
.overrides(new FakeModule)
.build
}
}
There are some other test classes similar to this class are properly able to compile and execute.
It's kind of implicit problem with scope..
Therefore, I tried to import all the same as another test class which's able to compile properly. But, still unable to compile.
Missing some import?
As the compiler states, you're missing an implicit value. Use the following, which is modeled after one of Silhouette's specs:
class TestControllerSpec extends PlaySpecification with Mockito {
"the POST request" should {
"return an OK response" in new Context {
new WithApplication(application) {
val identity = User(LoginInfo(...))
implicit val env = FakeEnvironment[DefaultEnv](Seq(identity.loginInfo -> identity))
val request = FakeRequest(POST, "/api/test")
.withAuthenticator(identity.loginInfo)
val result = route(app, request).get
status(result) must be equalTo OK
}
}
}
trait Context extends Scope {
...
}
}
Sorry for my bad english!
I'm newbie in scala language, I'm compiling a project with some modifications and getting the error
"scala value is not member of"... some body can help me? follow my code:
Command.scala
package com.bla.cms.domain
import scala.collection.Map
import redis.clients.jedis.Jedis
sealed trait CommandResult
object Success extends CommandResult
object Failure extends CommandResult
object Unauthorized extends CommandResult
trait Command {
def captchaValidator:Validator
def logger:Logging
val properties = PropertiesHandler.readProperties(System.getProperty(PropertiesHandler.configFileNameKey))
}
RedisIcrementCommand.scala
package com.bla.cms
package domain
import scala.collection.Map
import redis.clients.jedis.JedisPool
import dispatch._
import org.apache.log4j.Logger
import redis.clients.jedis.Jedis
class RedisIncrementCommand(database: Jedis, val captchaValidator:Validator, val logger:Logging) extends Command {
def execute(parameters: Map[String,String]):CommandResult = {
captchaValidator.validate(parameters) match {
case Right(params) =>
executeInDatabase(params)
case Left(status) =>
logger.info("Falha ao tentar executar comando. Captcha inválido. Status: " + status)
Failure
}
}
def executeInDatabase(parameters: Map[String,String]):CommandResult = {
parameters.get("selectedAnswer") match {
case Some(selectedAnswer) =>
database.incr(selectedAnswer)
database.sadd(Answers.key, selectedAnswer)
logger.info("Incremento recebido com sucesso. Opção: " + selectedAnswer)
Success
case None =>
logger.info("Falha ao tentar computar incremento. Alternativa não informada.")
Failure
}
}
}
PollServle.scala
package com.bla.cms
import javax.servlet.http._
import redis.clients.jedis.JedisPool
import scala.collection.JavaConverters._
import scala.collection.JavaConversions._
import com.bla.cms.domain.Logging
import org.apache.log4j.Logger
import scala.util.matching.Regex
class PollServlet extends HttpServlet with RequiresConnection {
import com.bla.cms.domain._
import URLHandler._
override def doPost(request:HttpServletRequest, response:HttpServletResponse):Unit = {
val parametersMap = new ServletApiAdapter(request,response).parameters
val outcome = newIncrementCommand(request).execute(parametersMap)
redirect(request, response, outcome)
}
}
And when I compile, I've got:
[error]PollServlet.scala:19: value execute is nota member of com.bla.cms.domain.Command
val outcome = newIncrementCommand(request).execute(parametersMap)
Somebody can help me please?
You can:
Add def execute(parameters: Map[String,String]):CommandResult to Command trait.
Change newIncrementCommand(request) to return RedisIncrementCommand instead of Command.
Cast result of newIncrementCommand(request) to RedisIncrementCommand using asInstanceOf.
I prefer 1 which would be:
trait Command {
val captchaValidator: Validator
val logger: Logging
val properties = PropertiesHandler.readProperties(System.getProperty(PropertiesHandler.configFileNameKey))
def execute(parameters: Map[String,String]): CommandResult
def executeInDatabase(parameters: Map[String,String]): CommandResult
}
I'm using the scala IDE for development. I have a few actors which I'm testing out. I wrote one scala test suite with the following definition and didn't have any problems:
import org.scalatest._
import akka.testkit._
import akka.actor.ActorSystem
import org.scalatest.BeforeAndAfterAll
import org.scalatest._
import scala.concurrent.duration._
import akka.actor.Props
import filters._
class ReaderSourceTest( _system: ActorSystem ) extends TestKit( _system ) with FunSuiteLike with BeforeAndAfterAll with ImplicitSender {
import ReaderSource._
//Must have a zero argument constructor
def this() = this( ActorSystem( "ReaderSourceSuite" ) )
override def afterAll = TestKit.shutdownActorSystem( system )
test( "Reader should be alive as an actor" ) {
val reader = system.actorOf( Props( classOf[ ReaderSource ], "dummy/file/name" ), "tstReaderA" )
reader ! Ping( "Hello" )
expectMsg( Pong( "Hello" ) )
}
}
I then created another test file to test another actor which goes like this:
import socketclient._
import org.scalatest._
import akka.testkit._
import akka.actor.ActorSystem
import org.scalatest.BeforeAndAfterAll
import scala.concurrent.duration._
import akka.actor.Props
import org.scalatest.fixture.FunSuiteLike
import java.net.InetAddress
import org.kdawg.CommProtocol.CommMessages._
import org.kdawg.CommProtocol.CommMessages
class NetworkTest( _system: ActorSystem ) extends TestKit( _system ) with FunSuiteLike with BeforeAndAfterAll with ImplicitSender
{
import NetworkTalker._
def this() = this( ActorSystem( "NetworkTalkerTest") )
override def afterAll = TestKit.shutdownActorSystem( system )
test( "Can Send a Packet" )
{
val net = system.actorOf( NetworkTalker.props("10.1.0.5", 31000), "TestA" )
val pktBuilder = CommMessage.newBuilder
pktBuilder.setType( MessageType.STATUS_REQUEST )
pktBuilder.setStatusRequest( CommProtocol.CommandsProtos.StatusRequest.newBuilder() )
val pkt = pktBuilder.build
net ! PktSend(1, pkt)
expectMsg( PktSent(1) )
}
}
I keep getting the following error on the last line of the above class
Multiple markers at this line
- type mismatch; found : org.kdawg.socketclient.NetworkTalker.PktSent required: NetworkTalkerTest.this.FixtureParam =>
Any
- type mismatch; found : org.kdawg.socketclient.NetworkTalker.PktSent required: NetworkTalkerTest.this.FixtureParam =>
Can anyone help me figure this out ?
Changing imports from
import org.scalatest.fixture.FunSuiteLike
to
import org.scalatest.FunSuiteLike
worked