Testing a snippet in Lift - scala

I am making a simple snippet that should pass a Box[String] with the requests user-agent to a helper class that passes back the css classes that should be added to the html element. I am doing this since it seems tricky to get Lift to supply a html respons with conditional comments like those in html5boilerplate. This is what I have now and it works:
class LiftBoilerplate {
def render = "html [class+]" #> getClassForUserAgent(S.request)
private def getClassForUserAgent(request:Box[Req]) = request match {
case Full(r) => LiftBoilerplateHelper.getHtmlClass(r.userAgent)
case _ => ""
}
}
My problem is that I'd like to write a unit test for this like:
object LiftBoilerplateSpecs extends Specification {
val session = new LiftSession("", randomString(20), Empty)
"LiftBoilerplate" should {
"add 'no-js' to the class of an html tag element" in {
val snippet = new LiftBoilerplate
val result = snippet.render(<html><head></head><body>test</body></html>)
result must ==/(<html class="no-js"><head></head><body>test</body></html>)
}
}
}
This test fails since S.request is Empty. What should I do to supply the snippet with a mocked request with a userAgent in it?
So far I have looked at http://www.assembla.com/spaces/liftweb/wiki/Unit_Testing_Snippets_With_A_Logged_In_User
and
http://www.assembla.com/spaces/liftweb/wiki/Mocking_HTTP_Requests
but I do not understand how to achive my goal.

To make the request and apply it automatically in each test example you will need to use the Trait AroundExample to wrap each test in a S.init call:
object LiftBoilerplateSpecs extends Specification with AroundExample {
val session = new LiftSession("", randomString(20), Empty)
def makeReq = {
val mockRequest = new MockHttpServletRequest("http://localhost")
mockRequest.headers = Map("User-Agent" -> List("Safari"))
new Req(Req.NilPath, "", GetRequest, Empty, new HTTPRequestServlet(mockRequest, null),
System.nanoTime, System.nanoTime, false,
() => ParamCalcInfo(Nil, Map(), Nil, Empty), Map())
}
def around[T <% Result](t: => T) = S.init(makeReq, session)(t)
"LiftBoilerplate" should {
"add 'no-js' to the class of an html tag element" in {
val snippet = new LiftBoilerplate
val result = snippet.render(<html><head></head><body>test</body></html>)
result must ==/(<html class="no-js"><head></head><body>test</body></html>)
}
}
}

Related

Passing a list of functions to a method to be executed later with data supplied

I am trying to build a multi level Validator object that is fairly generic. The idea being you have levels of validations if Level 1 passes then you do Level 2, etc. but I am struggling with one specific area: creating a function call but not executing it until a later point.
Data:
case class FooData(alpha: String, beta: String) extends AllData
case class BarData(gamma: Int, delta: Int) extends AllData
ValidationError:
case class ValidationError(code: String, message: String)
Validator:
object Validator {
def validate(validations: List[List[Validation]]): List[ValidationError] = {
validations match {
case head :: nil => // Execute the functions and get the results back
// Recursively work down the levels (below syntax may be incorrect)
case head :: tail => validate(head) ... // if no errors then validate(tail) etc.
...
}
}
}
Sample Validator:
object CorrectNameFormatValidator extends Validation {
def validate(str: String): Seq[ValidationError] = {
...
}
}
How I wish to use it:
object App {
def main(args: Array[String]): Unit = {
val fooData = FooData(alpha = "first", beta = "second")
val levelOneValidations = List(
CorrectNameFormatValidator(fooData.alpha),
CorrectNameFormatValidator(fooData.beta),
SomeOtherValidator(fooData.beta)
)
// I don't want these to execute as function calls here
val levelTwoValidations = List(
SomeLevelTwoValidator (fooData.alpha),
SomeLevelTwoValidator(fooData.beta),
SomeOtherLevelValidator(fooData.beta),
SomeOtherLevelValidator(fooData.alpha)
)
val validationLevels = List(levelOneValidations, levelTwoValidations)
Validator.validate(validationLevels)
}
}
Am I doing something really convoluted when I don't need to be or am I just missing a component?
Essentially I want to define when a function will be called and with which parameters but I don't want the call to happen until I say within the Validator. Is this something that's possible?
You can use lazy val or def when defining levelOneValidation, levelTwoValidations and validationLevel:
object App {
def main(args: Array[String]): Unit = {
val fooData = FooData(alpha = "first", beta = "second")
lazy val levelOneValidations = List(
CorrectNameFormatValidator(fooData.alpha),
CorrectNameFormatValidator(fooData.beta),
SomeOtherValidator(fooData.beta)
)
// I don't want these to execute as function calls here
lazy val levelTwoValidations = List(
SomeLevelTwoValidator (fooData.alpha),
SomeLevelTwoValidator(fooData.beta),
SomeOtherLevelValidator(fooData.beta),
SomeOtherLevelValidator(fooData.alpha)
)
lazy val validationLevels = List(levelOneValidations, levelTwoValidations)
Validator.validate(validationLevels)
}
}
You also need to change validate method to get the validations ByName and not
ByValue using : => :
object Validator {
def validate(validations: => List[List[Validation]]): List[ValidationError] = {
validations match {
case head :: nil => // Execute the functions and get the results back
// Recursively work down the levels (below syntax may be incorrect)
case head :: tail => validate(head) ... // if no errors then validate(tail) etc.
...
}
}
}
Anyway, I think you can implement it differently by just using some OOP design patterns, like Chain of Responsibility.

missing FromRequestUnmarshaller[Entity] on akka post route

Let me start by saying that i am very new to akka-http, none of the books i have covered the marsheling topic well. So it is bit of a blackbox for me. I was able to obtain the following (Un)Marsheller which is capable of returning both json and protobuf based on a request header.
This part of the code works fine and i have a get route defined in akka-http and it works fine.
trait PBMarshaller {
private val protobufContentType = ContentType(MediaType.applicationBinary("octet-stream", Compressible, "proto"))
private val applicationJsonContentType = ContentTypes.`application/json`
implicit def PBFromRequestUnmarshaller[T <: GeneratedMessage with Message[T]](companion: GeneratedMessageCompanion[T]): FromEntityUnmarshaller[T] = {
Unmarshaller.withMaterializer[HttpEntity, T](_ => implicit mat => {
case entity#HttpEntity.Strict(`applicationJsonContentType`, data) =>
val charBuffer = Unmarshaller.bestUnmarshallingCharsetFor(entity)
FastFuture.successful(JsonFormat.fromJsonString(data.decodeString(charBuffer.nioCharset().name()))(companion))
case entity#HttpEntity.Strict(`protobufContentType`, data) =>
FastFuture.successful(companion.parseFrom(CodedInputStream.newInstance(data.asByteBuffer)))
case entity =>
Future.failed(UnsupportedContentTypeException(applicationJsonContentType, protobufContentType))
})
}
implicit def PBToEntityMarshaller[T <: GeneratedMessage]: ToEntityMarshaller[T] = {
def jsonMarshaller(): ToEntityMarshaller[T] = {
val contentType = applicationJsonContentType
Marshaller.withFixedContentType(contentType) { value =>
HttpEntity(contentType, JsonFormat.toJsonString(value))
}
}
def protobufMarshaller(): ToEntityMarshaller[T] = {
Marshaller.withFixedContentType(protobufContentType) { value =>
HttpEntity(protobufContentType, value.toByteArray)
}
}
Marshaller.oneOf(protobufMarshaller(), jsonMarshaller())
}
}
the issue i am facing is on the post route.
(post & entity(as[PropertyEntity])) { propertyEntity =>
complete {
saveProperty(propertyEntity)
}
}
During compilation time, i get the following error
Error:(20, 24) could not find implicit value for parameter um: akka.http.scaladsl.unmarshalling.FromRequestUnmarshaller[PropertyEntity]
(post & entity(as[PropertyEntity])) { propertyEntity =>
I am not sure exactly what i am missing. Do i need to define an implicit FromRequestUnmarshaller ? if so what should it have?
i was able to hack something together that works for the moment, but i still don't know how to create a general Unmarshaller that can decode any ScalaPB case class
implicit val um:Unmarshaller[HttpEntity, PropertyEntity] = {
Unmarshaller.byteStringUnmarshaller.mapWithCharset { (data, charset) =>
val charBuffer = Unmarshaller.bestUnmarshallingCharsetFor(data)
JsonFormat.fromJsonString(data.decodeString(charBuffer.nioCharset().name()))(PropertyEntity)
/*PropertyEntity.parseFrom(CodedInputStream.newInstance(data.asByteBuffer))*/
}
}
even this i don't know how to have both decoders enabled at the same time. so i have commented one out.

Starting another Future call from within a Future.traverse

I am having trouble calling out to another function which returns a Future from within a Future.traverse. The scenario is that I have a Seq[Document] from which I need to turn them into a Future[Seq[NewsArticle]]. However, in order to do this I need to take the doc.categoryID and use it to call out to another API to build the NewsCategory, which will be returned as a Future[NewsCategory]. My problem is not knowing how to squish this in to the Future.traverse after it has returned.
Here is my scala code so far:
object NewsArticle {
def buildNewsArticles(docs:Seq[Document]):Future[Seq[NewsArticle]] = {
Future.traverse(docs) { doc =>
val categoryID = doc.catID
val title = doc.title
val pdf = doc.pdfLink
val image = doc.imageUrl
val body = doc.body
//need to call NewsCategory.buildNewsCategory(categoryID)
//but it returns a Future[NewsCategory]
//can't use for-yield because it still only yields
//a Future
future(NewsArticle( ??? ,title, pdf, image, body)
}
}
}
object NewsCategory {
def buildNewsCategory(catID:String):Future[NewsCategory] = {
// Calls external api across the wire and
// Returns a Future[NewsCategory]
}
}
// CASE CLASSES
case class NewsArticle(
category:NewsCategory,
title:String,
pdf:String,
image:String,
body:String)
case class NewsCategory(
id:String,
name:String
description:String)
Thanks for helping
It sounds like you want to create a NewsArticle instance based on the NewsCategory returned in the future from buildNewsCategory, which means that you were on the right track. I think the following will do what you want:
Future.traverse(docs) { doc =>
val categoryID = doc.catID
val title = doc.title
val pdf = doc.pdfLink
val image = doc.imageUrl
val body = doc.body
// This could be a for-yield instead as you note.
NewsCategory.buildNewsCategory(categoryID).map { category =>
NewsArticle(category, title, pdf, image, body)
}
}
Maybe try this:
object NewsArticle {
def buildNewsArticles(docs:Seq[Document]):Future[Seq[NewsArticle]] = {
Future.traverse(docs) { doc =>
val categoryID = doc.catID
val title = doc.title
val pdf = doc.pdfLink
val image = doc.imageUrl
val body = doc.body
for {
cat <- NewsCategory.buildNewsCategory(categoryID)
} yield new NewsArticle(cat, title, pdf, image, body)
}
}
}

Play Framework, Specs2 - Calling controller method directly from unit test

I have a method in my controller that I'd like to call directly. It takes in a POSTed form, validates it, then returns something. I want to test this directly - i.e. not go through the routes helper.
This is my Form code (FormFields is just a case class)
val searchForm = Form(
mapping(
"foo" -> nonEmptyText,
"filter" -> optional(text).verifying("Filter text must be 'published' or 'unpublished'",
x => x.isEmpty || x.get == "published" || x.get == "unpublished")
)(FormFields.apply)(FormFields.unapply)
)
This is my controller call.
def doThings() = IsAuthenticated {
username => implicit request => {
searchForm.bindFromRequest().fold(
formWithErrors => BadRequest(s"Incorrect data: ${formWithErrors.errors.map(x => s"${x.key} ${x.message}").mkString}."),
form => {
OK("Test text here")
}
)
}
}
If I call this via my routes file, as below - This works as expected. Form gets posted, verified, returns OK("Test...") as expected.
ie. The below works (using Specs2)
val request = FakeRequest(POST, "notarealurl")
.withFormUrlEncodedBody(
"filter" -> "published",
"foo" -> "Test"
).withSession("email" -> "testuser")
val Some(result) = route(request)
status(result) must equalTo(OK)
However, whatever I try to call the method directly fails - The failure happens on the form validation step. It tells me that "foo" is missing a value when I run the unit test. This is how I'm attempting to do this.
val request = FakeRequest()
.withFormUrlEncodedBody(
"filter" -> "published",
"foo" -> "Test"
).withSession("email" -> "testuser")
//val Some(result) = route(request)
val result = Search.searchProducts()(request)
println(contentAsString(result))
status(result) must equalTo(OK)
The text printed is "Incorrect search: foo error.required." I think I'm not doing the call properly, but I don't know where I'm going wrong.
Note : The code here represents my problem but has been cut down to just illustrate the issue.
I mimicked your logic, and it runs fine. I replaced some of your code with copy-paste from Play documentation just to keep it minimal. I tested it on top of a setup I'm working on now
so you'll see artifacts foreign to the default Play setup. This setup is more or less identical to the one described in the article I linked originally. I wouldn't know how to get more direct than this:
In controller:
import play.api.data._
import play.api.data.Forms._
case class UserData(name: String, age: Int)
val userFormConstraints2 = Form(
mapping(
"name" -> nonEmptyText,
"age" -> number(min = 0, max = 100)
)(UserData.apply)(UserData.unapply)
)
def test = Action {
implicit request => {
userFormConstraints2.bindFromRequest().fold(
formWithErrors => BadRequest("bad"),
userData => {
Ok(userData.name + userData.age)
}
)
}
}
Test:
class TempSpec extends Specification with MyHelpers {
"1" can {
"direct access to controller while posting" in new TestServer {
// `in new TestServer` spawns dependencies (`server`)
val controller = new controllers.Kalva(server)
// I instantiate the controller passing the dependency
val request = FakeRequest(POST, "bla")
.withFormUrlEncodedBody(
"name" -> "Richard",
"age" -> "1"
)
val result = controller.test()(request)
status(result) must equalTo(OK)
contentAsString(result) must contain("Richard");
val request_bad = FakeRequest(POST, "bla")
.withFormUrlEncodedBody(
"name" -> "",
"age" -> "-1"
)
val result_bad = controller.test()(request_bad)
status(result_bad) must equalTo(400)
contentAsString(result_bad) must contain("bad");
}
}
}
Global.scala:
object Global extends GlobalSettings {
private lazy val injector = Guice.createInjector(new TestModule)
override def getControllerInstance[A](controller: Class[A]) = {
injector.getInstance(controller)
}
}
TestModule:
import com.google.inject._
import com.tzavellas.sse.guice.ScalaModule
class TestModule extends ScalaModule {
def configure() {
#Provides
def getServer:Server = {
...
}
}
}
Within routes file:
POST /bla #controllers.Kalva.test
// the `#` prefix is needed because of how we fetch controllers
Original answer below:
class TranslateSpec extends Specification {
"Translate" should {
// The normal Play! way
"accept a name, and return a proper greeting" in {
running(FakeApplication()) {
val translated = route(FakeRequest(GET, "/greet/Barney")).get
status(translated) must equalTo(OK)
contentType(translated) must beSome.which(_ == "text/html")
contentAsString(translated) must contain ("Barney")
}
}
// Providing a fake Global, to explitly mock out the injector
object FakeTranslatorGlobal extends play.api.GlobalSettings {
override def getControllerInstance[A](clazz: Class[A]) = {
new Translate(new FakeTranslator).asInstanceOf[A]
}
}
"accept a name, and return a proper greeting (explicitly mocking module)" in {
running(FakeApplication(withGlobal = Some(FakeTranslatorGlobal))) {
val home = route(FakeRequest(GET, "/greet/Barney")).get
contentAsString(home) must contain ("Hello Barney")
}
}
// Calling the controller directly, without creating a new FakeApplication
// (This is the fastest)
"accept a name, and return a proper greeting (controller directly, no FakeApplication!)" in {
val controller = new Translate(new FakeTranslator)
val result = controller.greet(name = "Barney")(FakeRequest())
contentAsString(result) must contain ("Hello Barney")
}
}
}
The code above is quite self-descriptive and it shows the default testing workflow and how it can be improved with Dependency Injection. It's a quote from this article.
This particular excerpt is from the "Why should I use DI with Play?" section. The article is about setting up Google Guice with Play2 and the possibilities it opens up. It's a practical read.
As you can see above, "The normal Play! way" is fine, but by embracing DI you can get away with so much more in your tests (and development in general of course).
As is described in the article, using Guice with Play involves making minor changes to Play's default set-up and it's well worth it. I've been doing it this way for a long time now, and haven't looked back.

scala: easier way to wrap an object inside another object

In a play 2.1 application I have the following code (it's just a request wrapper that gets rid of any trailing slash):
class NormalizedRequest(request: RequestHeader) extends RequestHeader {
val headers = request.headers
val id = request.id
val method = request.method
val queryString = request.queryString
val remoteAddress = request.remoteAddress
val tags = request.tags
val version = request.version
// strip first part of path and uri if it matches http.path config
val path = if (request.path == "/") "/" else request.path.stripSuffix("/")
val uri = path + {
if(request.rawQueryString == "") ""
else "?" + request.rawQueryString
}
}
object NormalizedRequest {
def apply(request: RequestHeader) = new NormalizedRequest(request)
}
This kind of code is pretty common, you just wrap an object inside another
I was wondering if there's an easier way to acomplish it, ideally it would be something like (pseudo code inspired on case classes):
object NormalizedRequest {
def apply(request: RequestHeader) = {
val path = if (request.path == "/") "/" else request.path.stripSuffix("/")
val uri = path + {
if(request.rawQueryString == "") ""
else "?" + request.rawQueryString
}
request.copy(path = path, uri = uri)
}
}
If I understand correctly, you're asking for a more concise version of the Decorator pattern in scala. You still need your "wrapper" to be the same type as you inner class (by extending it or a common base/trait) in order to be able to pass it over to some function that expects to receive an instance of the inner class (or of the common base/trait).
What you wrote in your pseudo code is actually almost legal scala, you just have to change the definition of apply in NormalizedRequest to return an anonymous class that extends RequestHeader.
I.e. instead of
class NormalizedRequest(request: RequestHeader) extends RequestHeader {
//.... "decorated" logic here
}
object NormalizedRequest {
def apply(request: RequestHeader) = new NormalizedRequest(request)
}
you would have
object NormalizedRequest {
def apply(request: RequestHeader) = new RequestHeader {
// ...
// instead of having a separate NormalizedRequest class
// define its behaviour here in anonymous form
}
}
A simplified example:
// our inner class and companion object
// (a simplified version of your RequestHeader)
class Inner() {def test="hello"}; object Inner {
def apply() = new Inner()
}
// our wrapper
object Outer {
def apply(inner: Inner) = new Inner {
override def test=inner.test + "!"
}
}
however, although it saves you a few keystrokes, I really think you would lose in readability.