NullPointerException when unit testing Spray route - scala

I am a Scala newbie, and I am moving my first steps with Spray.io. I have defined a bunch of routes that seem to work just fine when I manually run them through Curl. However, I do get a nasty NullPointerException when I try to unit test the 'GET /documents?q=' route using spray.testkit.Specs2RouteTest.
Here is the route definition:
trait MyService extends HttpService {
import DocumentJsonProtocol._
val searchService: SearchService
val myRoute =
path("documents") {
post {
entity(as[Document]) { doc =>
detach() {
val docId = searchService.indexDocument(doc)
complete(201, s"document created: $docId")
}
}
} ~
get {
parameter('q) { q =>
detach() {
val docs = searchService.matchingQuery(q)
complete(docs)
}
}
}
} ~
path("documents" / Segment ) { docId =>
get {
detach() {
searchService.getDocument(docId) match {
case Some(doc) => {
complete(doc)
}
case None => {
complete(404, s"Cannot find a document with id: $docId")
}
}
}
}
}
}
And here is the failing test:
package example.com
import org.specs2.mutable.Specification
import org.specs2.specification.Scope
import org.specs2.mock._
import spray.testkit.Specs2RouteTest
import spray.http._
import spray.httpx.marshalling._
import StatusCodes._
import com.example.services.SearchService
import com.example.data._
import DocumentJsonProtocol._
class MyServiceSpec extends Specification
with Specs2RouteTest
with Mockito
with MyService {
val searchService = mock[SearchService]
def actorRefFactory = system
trait testDoc extends Scope {
val docId = "test-id"
val testDoc =
Document(Some(docId), "test-title", "test-author", "body", None)
searchService.indexDocument(testDoc).returns(docId)
searchService.matchingQuery("test-title").returns(List(testDoc))
}
"MyService" should {
"allows to search documents by keyword" in new testDoc {
Get("/documents?q=hello-test") ~> myRoute ~> check {
Right(entity) === marshal(List(testDoc))
}
}
This fails with the following error:
[ERROR] [04/07/2014 23:56:50.689] [io-composable-MyServiceSpec-akka.actor.default-dispatcher-3] [ActorSystem(io-composable-MyServiceSpec)] Error during processing of request HttpRequest(GET,http://ex
ample.com/documents?q=hello-test,List(),Empty,HTTP/1.1)
java.lang.NullPointerException
at spray.json.CollectionFormats$$anon$1.write(CollectionFormats.scala:26)
at spray.json.CollectionFormats$$anon$1.write(CollectionFormats.scala:25)
at spray.httpx.SprayJsonSupport$$anonfun$sprayJsonMarshaller$1.apply(SprayJsonSupport.scala:43)
at spray.httpx.SprayJsonSupport$$anonfun$sprayJsonMarshaller$1.apply(SprayJsonSupport.scala:42)
at spray.httpx.marshalling.Marshaller$MarshallerDelegation$$anonfun$apply$1.apply(Marshaller.scala:58)
at spray.httpx.marshalling.Marshaller$MarshallerDelegation$$anonfun$apply$1.apply(Marshaller.scala:58)
at spray.httpx.marshalling.Marshaller$MarshallerDelegation$$anonfun$apply$2.apply(Marshaller.scala:61)
at spray.httpx.marshalling.Marshaller$MarshallerDelegation$$anonfun$apply$2.apply(Marshaller.scala:60)
at spray.httpx.marshalling.Marshaller$$anon$2.apply(Marshaller.scala:47)
at spray.httpx.marshalling.BasicToResponseMarshallers$$anon$1.apply(BasicToResponseMarshallers.scala:35)
at spray.httpx.marshalling.BasicToResponseMarshallers$$anon$1.apply(BasicToResponseMarshallers.scala:22)
at spray.httpx.marshalling.ToResponseMarshaller$$anonfun$compose$1.apply(Marshaller.scala:69)
at spray.httpx.marshalling.ToResponseMarshaller$$anonfun$compose$1.apply(Marshaller.scala:69)
at spray.httpx.marshalling.ToResponseMarshaller$$anon$3.apply(Marshaller.scala:81)
at spray.httpx.marshalling.ToResponseMarshallable$$anon$6.marshal(Marshaller.scala:141)
at spray.httpx.marshalling.ToResponseMarshallable$$anon$7.apply(Marshaller.scala:145)
at spray.httpx.marshalling.ToResponseMarshallable$$anon$7.apply(Marshaller.scala:144)
at spray.routing.RequestContext.complete(RequestContext.scala:235)

The problem I could see after reading your code is that you mock matchingQuery function with "test-title" argument and make request with "hello-test" query parameter which leads mock to return null.

Related

No such method error akka.util.Helpers$.toRootLowerCase(Ljava/lang/String;)Ljava/lang/String;

I am trying to run the following program
import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport
import akka.http.scaladsl.marshalling.ToResponseMarshallable
import akka.http.scaladsl.model.{ContentTypes, HttpEntity}
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.directives.BasicDirectives
import akka.io.IO
import akka.stream.ActorMaterializer
import com.typesafe.config.ConfigFactory
import spray.json.DefaultJsonProtocol
import scala.concurrent.duration._
import scala.concurrent.Await
trait JsonSupport extends SprayJsonSupport with DefaultJsonProtocol {
implicit val itemFormat = jsonFormat2(Item)
}
final case class Item(name: String, id: Long)
object Main extends App with RestInterface {
val config = ConfigFactory.load()
val host = config.getString("http.host")
val port = config.getInt("http.port")
implicit val system = ActorSystem("My-ActorSystem")
implicit val executionContext = system.dispatcher
implicit val materializer = ActorMaterializer()
//implicit val timeout = Timeout(10 seconds)
val api = routes
Http().bindAndHandle(api, host, port) map {
binding => println(s"The binding local address is ${binding.localAddress}")
}
// recover
// { case ex => println(s"some shit occurred and it is"+ex.getMessage) }
// sys.addShutdownHook {
// system.log.info("Shutting down Spray HTTP in 10 seconds...")
// // NOTE(soakley): We are waiting to unbind to allow the VIP time to query healthcheck status.
// Thread.sleep(10000)
// system.log.info("Shutting down Spray HTTP and allowing 10 seconds for connections to drain...")
// val unbindFuture = Http.unbind(10.seconds)
//
// Await.ready(unbindFuture, 10.seconds)
// }
}
case class Stringer(str1 : String, str2 : String, str3 : String)
trait RestInterface extends Resource {
val routes = questionroutes ~ mydirectiveroute01 ~ mydirectiveroute02
}
trait Resource extends QuestionResource with mydirective01 with mydirective02
trait QuestionResource {
val questionroutes = {
path("hi") {
get {
val stringer_instance = Stringer("questionairre created","whatever","whatever-whatever")
complete(ToResponseMarshallable(stringer_instance.toString()))
}
}
}
}
trait mydirective01 extends BasicDirectives {
val getandputdirective = get | put
val mydirectiveroute01 = {
path("customhi" / IntNumber) {
passednumber1 => {
path(IntNumber) {
passednumber2 => {
getandputdirective {
ctx =>
ctx.complete("Testing get and put directive" + s"The passed string is " + passednumber2 + passednumber1)
}
}
}
}
}
}
}
trait mydirective02 extends BasicDirectives with JsonSupport {
val mydirectiveroute02 =
path("hello") {
get {
complete(HttpEntity(
ContentTypes.`text/html(UTF-8)`,
"<h1>Say hello to akka-http</h1>"))
}
} ~
path("randomitem") {
get {
// will marshal Item to JSON
complete(Item("thing", 42))
}
} ~
path("saveitem") {
post {
// will unmarshal JSON to Item
entity(as[Item]) { item =>
println(s"Server saw Item : $item")
complete(item)
}
}
}
}
But I get the following error
Exception in thread "main" java.lang.NoSuchMethodError: akka.util.Helpers$.toRootLowerCase(Ljava/lang/String;)Ljava/lang/String;
The error seems to be because of this line
implicit val materializer = ActorMaterializer()
May I know where I am going wrong. I have identical pom.xml file and the program in another module and it seems to run fine. I dont understand where I am going wrong. Thanks
I get errors like that when something that should have been re-compiled has not been re-compiled. clean" followed by "compile" in sbt resolves it.
The issue is due to the conflict in dependencies make sure you are using same version for all the related packages you are importing.
example:
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-http-core_2.11</artifactId>
<version>10.0.0</version>
</dependency>
2.11 make sure you have other dependencies with same version
then make a clean build.
Your project dependencies have conflicting versions. The version that has that function gets discarded, and the other version included in the jar (or classpath - depending on how you execute).
Please provide your dependencies file (i.e. sbt.build or gradle.build etc.)

Mock functional argument of the function

I'm developing web app using Scala, Play Framework. And I need to test controller with the custom action. Please, take a look on the code:
package controllers.helpers
import play.api.mvc.{ActionBuilder, Request, Result}
import scala.concurrent.Future
class CustomAction extends ActionBuilder[Request] {
override def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]): Future[Result] = {
// do some stuff
block(request)
}
}
package controllers
import javax.inject.Singleton
import play.api.mvc.Controller
#Singleton
class SomeController #Inject() (customAction: CustomAction
) extends Controller {
def foo() = customAction(parse.json) { implicit request =>
// do some stuff and create result
}
}
And below you can find a code of the test class. I use Specs2 and I got org.mockito.exceptions.misusing.InvalidUseOfMatchersException on the line with customeActionMock.invokeBlock(any[Request[_]], any[(Request[_]) => Future[Result]]) returns mock[Future[Result]]
package controllers
import controllers.helpers.CustomAction
import org.specs2.mock.Mockito
import play.api.mvc.{Request, Result}
import play.api.test.{FakeHeaders, FakeRequest, PlaySpecification}
import scala.concurrent.Future
class SomeControllerSpec extends PlaySpecification with Mockito {
private val customeActionMock = mock[CustomAction]
customeActionMock.invokeBlock(any[Request[_]], any[(Request[_]) => Future[Result]]) returns mock[Future[Result]] //this doesn't work, exception is thrown there
"SomController" should {
"respond Ok on valid request" in {
val result = new UserController(customeActionMock).foo()(FakeRequest())
status(result) shouldEqual OK
}
}
}
I understand that I mock block parameter of the CustomAction incorrectly. Can someone help me to do it properly?
My project uses Play 2.5.x. I use scalatest. This is how I test controllers.
import org.scalatestplus.play.OneAppPerSuite
import org.scalatest._
import org.scalatest.time.{Millis, Seconds, Span}
import org.scalatest.concurrent.ScalaFutures
import scala.concurrent.Future
class SomeControllerSpec extends FlatSpec with Matchers with ScalaFutures with OneAppPerSuite {
private val customeActionMock = new CustomAction // create an instance of a class
implicit val defaultPatience = PatienceConfig(timeout = Span(5,Seconds), interval = Span(500, Millis))
it should "respond Ok on valid request" in {
val resultF : Future[Result] = new UserController(customeActionMock).foo()(FakeRequest())
whenReady(resultF) { resultR =>
resultR.header.status shouldBe 200
}
}
}
Don't mock the CustomAction :
class SomeControllerSpec extends PlaySpecification with Mockito {
private val customeActionMock = new CustomAction
"SomController" should {
"respond Ok on valid request" in {
val result = new UserController(customeActionMock).foo()(FakeRequest())
status(result) shouldEqual OK
}
}
}

Play Framework Anorm withConnection Error

I have the following case class and class in Play Framework 2.5. Since the DB object has been deprecated I'm trying to use the new dependency inject methodology but not understanding why my code does not compile. The old method works fine, the new method has compilation error.
missing parameter type on the implicit connection =>
package models
import javax.inject.{Inject, Singleton}
import play.db._
import anorm.SqlParser._
import anorm._
import play.api.db.DB
import play.api.Play.current
case class Department(id: Int,
name: String)
#Singleton
class DepartmentDao #Inject() (dBApi: DBApi) {
private val db = dBApi.getDatabase("default")
val simple = {
get[Int]("department.id") ~
get[String]("department.name") map {
case id ~ name => Department(id, name)
}
}
def getDepartments = DB.withConnection { implicit connection =>
SQL("SELECT * FROM DEPARTMENT")
}
def getDepartmentsNew = db.withConnection { implicit connection =>
SQL("SELECT * FROM DEPARMTMENT")
}
}
UPDATE:
I've placed what the code looked like before was I was originally trying to get it working. Unless I am missing something this code should run. It is identical to code I've seen in multiple sample projects.
#Singleton
class DepartmentDao #Inject() (dBApi: DBApi) {
private val db = dBApi.getDatabase("default")
val simple = {
get[Int]("department.id") ~
get[String]("department.name") map {
case id ~ name => Department(id, name)
}
}
def getDepartments: Seq[Department] = db.withConnection { implicit connection =>
SQL("SELECT * FROM DEPARMTMENT").as(simple.*)
}
}

How do you set the viewport, width, with phantomjs with play 2 framework

I have been struggling with this for a while, I can't find a way to instruct phantomjs about the viewport. I am using play 2.2 (code is based on: Set Accept-Language on PhantomJSDriver in a Play Framework Specification )
package selenium
import org.specs2.mutable.Around
import org.specs2.specification.Scope
import play.api.test.{TestServer, TestBrowser, FakeApplication}
import org.openqa.selenium.remote.DesiredCapabilities
import org.specs2.execute.{Result, AsResult}
import play.api.test.Helpers._
import scala.Some
import org.openqa.selenium.phantomjs.PhantomJSDriver
import org.openqa.selenium.NoSuchElementException
import java.io.File
import java.io.PrintWriter
import java.util.concurrent.TimeUnit
import collection.JavaConversions._
abstract class WithPhantomJS(val additionalOptions: Map[String, String] = Map()) extends Around with Scope {
implicit def app = FakeApplication()
implicit def port = play.api.test.Helpers.testServerPort
// for phantomjs
lazy val browser: TestBrowser = {
val defaultCapabilities = DesiredCapabilities.phantomjs
print(defaultCapabilities.toString)
val additionalCapabilities = new DesiredCapabilities(mapAsJavaMap(additionalOptions))
val capabilities = new DesiredCapabilities(defaultCapabilities, additionalCapabilities)
val driver = new PhantomJSDriver(capabilities)
val br = TestBrowser(driver, Some("http://localhost:" + port))
br.webDriver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS)
br
}
override def around[T: AsResult](body: => T):Result = {
try {
running(TestServer(port, FakeApplication()))(AsResult.effectively(body))
} catch {
case e: Exception => {
val fn: String = "/tmp/test_" + e.getClass.getCanonicalName;
browser.takeScreenShot(fn + ".png")
val out = new PrintWriter(new File(fn + ".html"), "UTF-8");
try {
out.print(browser.pageSource())
} finally {
out.close
}
throw e;
}
} finally {
browser.quit()
}
}
}
and the actual test looks like this:
class ChangeName extends Specification {
"User" should {
"be able to change his name in account settings" in new WithPhantomJS() {
// ... this throws
I'd like the exception handler to render the site, which works, however, i can see the with matching a mobile device (narrow).
How can I change the width?
This seems to work:
import org.openqa.selenium.Dimension
...
browser.webDriver.manage().window().setSize(new Dimension(1280, 800))

Exception when using elastic4s with elastic-search and spray-routing

I'm trying to write a little REST api using Scala, Spray.io, Elastic4s and ElasticSearch.
My ES instance is running with default parameters, I just changed the parameter network.host to 127.0.0.1.
Here is my spray routing definition
package com.example
import akka.actor.Actor
import spray.routing._
import com.example.core.control.CrudController
class ServiceActor extends Actor with Service {
def actorRefFactory = context
def receive = runRoute(routes)
}
trait Service extends HttpService {
val crudController = new CrudController()
val routes = {
path("ads" / IntNumber) {
id =>
get {
ctx =>
ctx.complete(
crudController.getFromElasticSearch
)
}
}
}
}
My crudController :
package com.example.core.control
import com.example._
import org.elasticsearch.action.search.SearchResponse
import scala.concurrent._
import scala.util.{Success, Failure}
import ExecutionContext.Implicits.global
class CrudController extends elastic4s
{
def getFromElasticSearch : String = {
val something: Future[SearchResponse] = get
something onComplete {
case Success(p) => println(p)
case Failure(t) => println("An error has occured: " + t)
}
"GET received \n"
}
}
And a trait elastic4s who is encapsulating the call to elastic4s
package com.example
import com.sksamuel.elastic4s.ElasticClient
import com.sksamuel.elastic4s.ElasticDsl._
import scala.concurrent._
import org.elasticsearch.action.search.SearchResponse
trait elastic4s {
def get: Future[SearchResponse] = {
val client = ElasticClient.remote("127.0.0.1", 9300)
client execute { search in "ads"->"categories" }
}
}
This code runs well, and gives me this output :
[INFO] [03/26/2014 11:41:50.957] [on-spray-can-akka.actor.default-dispatcher-4] [akka://on-spray-can/user/IO-HTTP/listener-0] Bound to localhost/127.0.0.1:8080
But when a try to access to the route "localhost/ads/8" with my browser, the case Failure is always triggered and I got this error output on my intellij console :
An error has occured: org.elasticsearch.transport.RemoteTransportException: [Skinhead][inet[/127.0.0.1:9300]][search]
(No console output with elasticSearch running on my terminal)
Is this exception related to ElasticSearch, or am I doing wrong with my Future declaration ?
I suppose you should use ElasticClient.local in this case, as specified in elastic4s docs:
https://github.com/sksamuel/elastic4s
To specify settings for the local node you can pass in a settings object like this:
val settings = ImmutableSettings.settingsBuilder()
.put("http.enabled", false)
.put("path.home", "/var/elastic/")
val client = ElasticClient.local(settings.build)