I am using requests-scala module to make HTTP requests as shown below:
object AEMUtility {
....
def getJWTToken() {
....
val response = requests.post(
s"$imsExp/ims/exchange/jwt/",
headers = Map(
"Content-Type" -> "application/x-www-form-urlencoded"
),
params = Map(
"client_id" -> clientId,
"client_secret" -> clientSecret,
"jwt_token" -> token
)
)
}
}
I want to mock the post request function for writing a Unit test by:
checking the arguments passed in the Mock function and returning a dummy response.
Is there a way to mock installed dependency in scala?
I tried :
"authorize" should "return JWT token if request is valid" in {
val postMock = mock[requests.post]
}
but this gives me error:
Cannot resolve symbol post
The error you got is because requests.post is an instance of Requester (see in source code), mock expects a type parameter. You can't pass an object to it, you can mock its classes, traits, etc. So what you should probably do is trying to mock the case class:
val requester = mock[requests.Requester]
Or the BaseSession trait, which contains the post, get and other methods.
val session = mock[requests.BaseSession]
Or the Session case class, which is the implementation of the BaseSession trait.
val session = mock[requests.Session]
I'm not sure anyways, the library doesn't look test-friendly to me.
Related
I have a test that I have to change due to a change that I did in an S3Repository class
to use putObject method. I had to change the client from the type of AmazonS3Client that is deprecated to AmazonS3. That's how I did it:
The method is uploadCsvToS3:
val creds = DefaultAWSCredentialsProviderChain.getInstance()
val awsRegion: Regions = Regions.fromName(configuration.get[String]("aws.s3.region"))
val client: AmazonS3 = AmazonS3ClientBuilder.standard().withRegion(awsRegion).withCredentials(creds).build()
val fileName = produceFileNameForVersion(params_to_this_method)
client.putObject(AWSS3Bucket, fileName, file.toFile)
I know that the solution works, but there is a test that is not working:
I have a mock and override:
val client = mock[AmazonS3]
override def fakeApplication(): Application = new GuiceApplicationBuilder()
.overrides(bind[AmazonS3].toInstance(client))
and This is the test (positive case):
Mockito.when(client.putObject(MockitoMatchers.eq(s3Bucket), MockitoMatchers.anyString(), MockitoMatchers.eq(file))) thenReturn new PutObjectResult
val s3Repository : S3Repository = app.injector.instanceOf[S3Repository]
val s3Location = s3Repository.uploadCsvToS3(file.toPath).futureValue
assert(s3Location.fileName.nonEmpty)
I get this error:
Access Denied (Service: Amazon S3; Status Code: 403; Error Code: AccessDenied; Request ID:...
I tried a lot of solutions like configuration of access and secret key, PowerMockito and others.
Thanks for any help.
EDIT - Solution:
I found that this method is not testable because there is an instantiation of a client, but the purpose is to mock the client in order to test this method.
The solution was to create a Provider - AmazonS3ClientProvider, and override the method get. There, the client will be instantiate the same way. Then:
bind(classOf[AmazonS3]).toProvider(classOf[AmazonS3ClientProvider])
My play application has an endpoint for receiving webhooks from Stripe.
In order to verify the webhooks, the request body needs to be compared against a signature and a signing key. This requires that I have access to the raw request body, as sent.
However, it seems that Play alters the request body, and I can't get access to the raw contents. This causes the computed signature to change, and the verification fails. More info: https://stackoverflow.com/a/43894244/49153
Here's my code:
#Singleton
class WebhookController #Inject()(cc : ControllerComponents,
env: Env)
(implicit ec: ExecutionContext)
extends AbstractController(cc) {
private val log = Logger("WebhookController")
def index(): Action[AnyContent] = Action.async { implicit req =>
val signature =
req.headers.headers.find(_._1 == "Stripe-Signature").map(_._2).getOrElse("").trim
if (verifySignature(req.body.toString, signature, env.webhookSecretKey))
Future.successful(ok("ok"))
else
Future.successful(ok("Couldn't verify signature"))
}
}
Here I'm trying to access the body using req.body.toString but it looks to be the deserialized json rather than the raw body.
Using req.body.asRaw returns a none.
Any ideas?
Solved this by using Action.async(parse.raw) and then doing req.body.asBytes().map(_.utf8String).getOrElse("") to obtain the raw string of the body. Some more info: https://www.playframework.com/documentation/2.7.x/ScalaBodyParsers
My Scala level is a beginner and I saw an action method clearly demonstrating a declaration implicit request=>. And my question is under what types of situation should we declare clearly? I also have seen methods which don't declare implicit request=> or request=>.
Could anyone explain the advantage?
I will not cover the meaning of implicit in scala itself as it has already been answered on stackoverflow here. The play documentation also explains the use of request => here but does not give examples of a useful implicit request.
TL; DR : when in doubt, use implicit request as it may be needed by some components.
Action without request
If the request does not change the result your block of code will return, it can be omitted and you can write.
def myAction = Action { Ok("Hello World") }
With Request
If on the other hand you need to use the content of the request (header or body), then you have to add a request parameter. A common example of this is parsing the body of the request :
Action(parse.json) { request => // it works without implicit
request.body.validate[MyClass].fold(/* do something */)
}
With implicit request
The play documentation encourages us to mark the request parameter as implicit because even if you do not use the request directly, one component you use may need it as an implicit. If you ever get a missing implicit error in one of your action, it probably boils down to the fact that you forgot to make your request implicit.
I think a good example you might encounter in play is the internationalization API. To sum up, it allows to automatically inject localized messages in your templates depending on the Accept-Language header in the request. All you have to do is add the I18nSupport trait to your controller and inject a messagesApi: MessagesApi parameter (and obviously define your internationalized messages). Then, in your twirl template, you can use the localized messages. For instance :
Template :
#()(implicit messages: Messages)
#*
message will be in english, spanish, klingon... depending on the supported
languages and request Accept-Language header
*#
#messages("say-hello")
Controller :
class MyController #Inject() (val messageApi: MessageApi) extends Controller with I18nSupport {
def myAction = Action {implicit request =>
// We do not have to bother about how messages are injected
// The I18nSupport trait does the work for us
Ok(html.myTemplate())
}
}
To be able to do this, the I18nSupport trait contains a def :
implicit def request2Messages(implicit request: RequestHeader): Messages = /* ... */
It allows to get an instance of Messages automatically (the compiler will implicitly call request2Messages(yourRequest) when needed but you need to have an implicit request (or request header) in scope.
Another example I have seen is automatically getting a user instance in the scope of the action when using some security frameworks in play.
Side note
A annoying gotcha with this kind of implicit chain is that if you forget to make your request implicit, the compiler will probably complain about a missing implicit Messages in scope while the real problem is a missing implicit request.
implicit in Scala has many use cases - one of them being passing parameters implicitly to functions that define implicit parameters.
For example:
def withImplicitParameter(greeting: String)(implicit name: String): Unit = {
println(greeting + " " + name)
}
// Using implicits
implicit val name = "Bob"
withImplicitParameter("Hello") // "Bob" is passed in implicitly for name parameter. Prints "Hello Bob"
withImplicitParameter("Bye")("Joe") // "Joe" is passed in explicitly for name parameter. Prints "Bye Joe"
Therefore unless one of the functions you're calling has an implicit parameter of the type Request you don't need { implicit request => ... }
More info can be found in Scala's official documentation on implicit parameters
Another example with similar API to play's implicit req => ...
case class ClassName(name: String)
def log(msg: String)(implicit className: ClassName) =
System.out.println(s"message=`$msg` className=`${className.name}`")
val cls = Option(ClassName("ImplicitClass"))
cls.foreach { implicit name =>
log("explicit message")
}
Produces
message=`explicit message` className=`ImplicitClass`
I am trying to use the http4s library. I am trying to make a POST request to a REST web service with some json payload.
when I read the documentation http://http4s.org/docs/0.15/ I can only see a GET method example.
does anyone know how to make a POST?
It looks like the get/getAs methods mentioned in the example are just convenience wrappers for the fetch method. See https://github.com/http4s/http4s/blob/a4b52b042338ab35d89d260e0bcb39ccec1f1947/client/src/main/scala/org/http4s/client/Client.scala#L116
Use the Request constructor and pass Method.POST as the method.
fetch(Request(Method.POST, uri))
https4s version: 0.14.11
The hard part is how to set the post body. When you dive into the code, you may find type EntityBody = Process[Task, ByteVector]. But wtf is it? However, if you have not been ready to dive into scalaz, just use withBody.
object Client extends App {
val client = PooledHttp1Client()
val httpize = Uri.uri("http://httpize.herokuapp.com")
def post() = {
val req = Request(method = Method.POST, uri = httpize / "post").withBody("hello")
val task = client.expect[String](req)
val x = task.unsafePerformSync
println(x)
}
post()
client.shutdownNow()
}
P.S. my helpful post about http4s client(Just skip the Chinese and read the scala code): http://sadhen.com/blog/2016/11/27/http4s-client-intro.html
import org.http4s.circe._
import org.http4s.dsl._
import io.circe.generic.auto._
case class Name(name: String)
implicit val nameDecoder: EntityDecoder[Name] = jsonOf[Name]
def routes: PartialFunction[Request, Task[Response]] = {
case req # POST -> Root / "hello" =>
req.decode[Name] { name =>
Ok(s"Hello, ${name.name}")
}
Hope this helps.
I'm trying to do some RESTFull Web service POC using Play 2.1.3
I have the following class:
case class Student(id: Long,firstName: String,lastName: String)
Now I would like to create RESTfull URI which will get Json serialised Student POJO and return the same POJO in response.
implicit val studentReads = Json.reads[Student]
implicit val studentWrites = Json.writes[Student]
def updateStudent = Action(parse.json){
request=>request.body.validate[Student].map{
case xs=>Ok(xs)}.recoverTotal{
e => BadRequest("Detected error:"+ JsError.toFlatJson(e))
}
}
But I'm getting compilation Error -
Cannot write an instance of entities.Student to HTTP response. Try to define a
Writeable[entities.Student]
I just provided Writes[A] as an implicit variable.
What else am I missing?
I think the problem is that the Ok() method cannot figure out the Student needs to be transformed to json, as the arguments to Ok() may vary.
You may return an Ok(Json.toJson(xs))
You may explicitly point the desired type: Ok(xs: JsValue)
And be sure all implicits are in scope