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])
Related
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.
using play 2.5 and guice i have managed to successfully inject applicationConfig into a singleton class and reference a config variable inside it,
trait TMongoFactory{
val SERVER: String
val PORT: Int
val DATABASE: String
val connection: MongoClient
val collection: MongoDB
}
#Singleton
class MongoFactory #Inject()(val configuration: Configuration) extends TMongoFactory{
val SERVER = "localhost"
val PORT = 27017
val DATABASE = configuration.underlying.getString("connectionString")
val connection = MongoClient(SERVER, PORT)
val collection = connection(DATABASE)
}
class MongoModule extends AbstractModule {
def configure() = {
bind(classOf[TMongoFactory]).to(classOf[MongoFactory])
}
}
I can then pass this singleton to a repository class like so
#Singleton
class MongoRemainingAllowanceRepository #Inject()(MongoFactory: TMongoFactory) extends RemainingAllowanceRepository{
val context = MongoFactory.collection("remainingAllowance")
def save(remainingAllowance: RemainingAllowance): Unit ={
context.save(RemainingAllowance.convertToMongoObject(remainingAllowance))
}
This all works fine and as expected, but the problem is i need to call this repository in the test suite so i dont want it to have to take any arguments (specifically injected ones).
So i tried to change it to use an injector inside the body like so
#Singleton
class MongoRemainingAllowanceRepository extends RemainingAllowanceRepository{
val injector = Guice.createInjector(new MongoModule)
val mongoFactory = injector.getInstance(classOf[TMongoFactory])
val context = mongoFactory.collection("remainingAllowance")
def save(remainingAllowance: RemainingAllowance): Unit ={
context.save(RemainingAllowance.convertToMongoObject(remainingAllowance))
}
This feels like it should work and it compiles fine, but then on test or run it throws an error
Could not find a suitable constructor in play.api.Configuration. Classes
must have either one (and only one) constructor annotated with #Inject
or a zero-argument constructor that is not private. at
play.api.Configuration.class(Configuration.scala:173) while locating
play.api.Configuration
Apologies for the long post but i feel i needed to include most of this.
Does anyone know why this happens on an injector? Do i need to bind the configuration manually also now im referencing the custom module?
Any help appreciated
Thanks
Jack
When you create your class you can pass in the configuration yourself. Say you need key apiKey and its value...
val sampleConfig = Map("apiKey" ->"abcd1234")
val mongoFactory = new MongoFactory(Configuration.from(sampleConfig))
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.
for creating datasource I have
object MyDataSource {
priavte lazy val dataSource: javax.sql.DataSource = {
val ds = new BasicDataSource
val conf = ConfigFactory.load()
val url = conf.getString("jdbc-url")
val driver = conf.getString("jdbc-driver")
val username = conf.getString("db-username")
val password = conf.getString("db-password")
val port = conf.getString("db-port")
val maxActive = conf.getInt("max-active")
val maxIdle = conf.getInt("max-idle")
val initSize = conf.getInt("init-size")
ds.setDriverClassName(driver)
ds.setUsername(username)
ds.setPassword(password)
ds.setMaxActive(maxActive)
ds.setMaxIdle(maxIdle)
ds.setInitialSize(initSize)
ds.setUrl(url)
ds
}
lazy val database = Database.forDataSource(dataSource)
}
MyDataSource is used as below
def insertCompany = {
MyDataSource.database.withSession{ implicit session =>
company.insert(companyRow)
}
}
Now for testing I have trait DatabaseSpec which loads test database(pointing to test db) config and has following fixture
def withSession(testCode: Session => Any) {
val session = postgres.createSession()
session.conn.setAutoCommit(false)
try {
testCode(session)
} finally {
session.rollback()
session.close()
}
}
And test code can then mix in DatabaseSpec and use withSession to test transactional code.
Now question is what's the best practice in keeping MyDataSource.database.withSession abstracted away from DataSource in insertCompany so that method can be tested with DatabaseSpec and pointing to test db?
The best way to be able to exchange a value, .e.g for prod and testing is by parameterizing your code in that value. E.g.
def insertCompany(db: Database) = db.withSession(company.insert(companyRow)(_))
or
class DAO(db:Database){
def insertCompany = db.withSession(company.insert(companyRow)(_))
}
Keep it simple. Avoid unnecessary complexity like the Cake pattern, DI frameworks or mixin composition for this.
If you need to pass multiple values around... aggregate them into a "config"-class. Compose multiple config classes with different purposes to target different things, if you want to avoid writing one huge config class as stuff accumulates.
If you find yourself passing config objects to all your functions, you can mark them as implicit, that saves you at least the call-site code overhead. Or you can use something like scalaz's monadic function composition to avoid call site and definition site code overhead for passing config around. It is sometimes called the Reader monad, but it is simply for-comprehension enabled composition of 1-argument functions.
Slick 2.2 will ship with something like that out-of-the-box and make what you want very easy.
Also, here is an approach I am currently playing around with, a composable configuration object "TMap". This code example shows step by step how you get from global imports over parameterized functions and making them implicit to using TMap and removing most boilerplate: https://github.com/cvogt/slick-action/blob/0.1/src/test/scala/org/cvogt/di/TMapTest.scala#L49
I'm trying to execute (in IntelliJ IDE or from sbt command-line) this very basic dispatch snippet from behind a proxy :
import dispatch._
val svc = url("http://api.hostip.info/country.php")
val country = Http(svc > as.String)
println(country())
and all I can get is an exception :
java.net.ConnectException: Connection timed out: no further information to
http://api.hostip.info/country.php java.util.concurrent.ExecutionException:
java.net.ConnectException: Connection timed out: no further information
to http://api.hostip.info/country.php
I tried with no conclusive result to set the usual vm parameters :
-Dhttp.proxyHost=_my_proxy_host_ -Dhttp.proxyPort=80
and still got the same exception.
On the other hand, the following snippet does work well :
import dispatch._
val svc = url("http://api.hostip.info/country.php") setProxyServer(new com.ning.http.client.ProxyServer(myproxyhost,80))
val country = Http(svc > as.String)
println(country())
Since it does not seem quite aesthetic nor scala-ish, I wonder if it is really what I am supposed to do in such a case.
Any help would be welcome, thanks in advance.
http.proxyHost and http.proxyPort will be used if you set this parameter:
-Dcom.ning.http.client.AsyncHttpClientConfig.useProxyProperties=true
Additionaly there are parameters:
-Dcom.ning.http.client.AsyncHttpClientConfig.proxy.user=user
-Dcom.ning.http.client.AsyncHttpClientConfig.proxy.password=password
-Dcom.ning.http.client.AsyncHttpClientConfig.proxy.protocol=NTLM
Looks like my question wasn't very inspiring.
I did a little exercie in the pimp my library style :
package dispatch
package object ext {
import com.ning.http.client.ProxyServer
class DefaultPoxyVerbs(override val subject: Req) extends ProxyVerbs
object NoProxy extends ProxyServer("",0)
object Proxy {
def apply(host: String,port: Int) = new ProxyServer(host,port)
}
trait ProxyVerbs extends RequestVerbs {
def through(proxy : ProxyServer) =
if (NoProxy == proxy) subject else subject.setProxyServer(proxy)
def ||>(proxy : ProxyServer) = through(proxy)
}
implicit def implyProxyVerbs(builder: Req) =
new DefaultPoxyVerbs(builder)
}
Now I can write :
import dispatch._
import dispatch.ext._
val svc = url("http://api.hostip.info/country.php") through Proxy("blah blah blah",80)
val country = Http(svc > as.String)
println(country())
which is a little bit more eye pleasing and coherent regarding dispatch api style.
While it was an interesting exercise, I still don't know by now if i was originally using the api the way I was supposed to nor why setting http.proxyHost and http.proxyPort properties didn't work since it seems to work for others.