Feeder value not updated in gatling test - scala

I am new to scala and gatling . I am trying to fetch values from feeder and post zip file to service . but ${extensionId} is not been updated with fetched value instead it remain as ${extensionId} . Could some one please help me know If I miss some thing here .
def installExtension() =
exec(http("template - Install Extension")
.post(url + "/v1/extensions")
.basicAuth("jack", "password")
.headers(namespaceHeader)
// using testUtils to get InputStream conte
.body(InputStreamBody(TestUtils.toStream(hashMap.get("${extensionId}").getOrElse(null))))
.check(status.is( 201)))
class extmgrSimulations extends Simulation {
val extensionIds = csv(s"${Configuration.dataDirectory}/extensionId.csv").circular
val extMgrScenerio = scenario("extensionMgr - Scenario")
.during(Configuration.duration) {
exitBlockOnFail(
group("load-test") {
exec(
pace(Configuration.paceFrom, Configuration.paceTo),
feed(extensionIds),feed(extensionIds)
randomSwitch(
50.00 -> group("Install and delete") {
exec(
extmgrChain.installExtension(),
extmgrChain.deleteExtension(),
)
},
50.00 -> extmgrChain.listExtension()
)
)
}
)
}

That can't work. Gatling EL (the ${} syntax in strings) doesn't magically work anywhere. This is explained in the documentation.
Warning
This Expression Language only works on String values being passed to Gatling DSL methods. Such Strings are parsed only once, when the Gatling simulation is being instantiated.
For example queryParam("latitude", session => "${latitude}") wouldn’t work because the parameter is not a String, but a function that returns a String.
Also, queryParam("latitude", "${latitude}".toInt) wouldn’t because the toInt would happen before passing the parameter to the queryParam method.
The solution here would be to pass a function:
session => session("latitude").validate[Int].

Related

How to test the arguments passed to a function of ScalarDB

I am using ScalarDB. It provides ACID capabilities over Cassandra. - https://scalar-labs.github.io/scalardb/javadoc/
ScalarDB is Java based and I am using it in Scala code
The way to insert a value in Cassandra using Scalardb is to call Put method. Eg.
def add() = {
val putAnswer: Put = new Put(pAnswerKey)
.forNamespace(keyspaceName)
.forTable(tablename)
.withCondition(mutationCondition)
.withValue(new TextValue("answer_id", answer.answer_id.get.toString))
.withValue(new TextValue("image", convertImageToString(imageData)))
.withValue(new TextValue("answer", convertAnswersFromModelToString(answer.answer)))
.withValue(new BigIntValue("creation_year", answer.creationYear.getOrElse(0)))
.withValue(new BigIntValue("creation_month", answer.creationMonth.getOrElse(0)))
.withValue(new TextValue("notes", answer.notes.getOrElse("")))
logger.trace(s"putting answer ${putAnswer}")
transaction.put(putAnswer)
....
}
I want to unit test the add method by capturing the argument passed to put. I am stuck at a point where I don't know how to get the Value passed to put. How do I type cast to required values?
repository.add(repoTestEnv.mockDistributedTransaction,repoTestEnv.answerTestEnv.answerOfAPracticeQuestion)
val argumentCaptor = ArgumentCaptor.forClassPut,Put
verify(repoTestEnv.mockDistributedTransaction,times(1)).put(argumentCaptor.capture())
val argumentsInvoked = argumentCaptor.getAllValues
argumentsInvoked.size mustBe 1
val argument = argumentsInvoked.get(0)
val values = argument.getValues //this is util.Map[String,Value[_]]
logger.trace(s"arguments were ${argument.getValues}") //this prints the following
{answer_id=TextValue{name=answer_id, value=Optional[11111111-1111-1111-1111-111111111111]}, image=TextValue{name=image, value=Optional[{"image":["image1binarydata","image2binarydata"]}]}, answer=TextValue{name=answer, value=Optional[{"answer":[{"filename":"c.js","answer":"some answer"}]}]}, creation_year=BigIntValue{name=creation_year, value=2019}, creation_month=BigIntValue{name=creation_month, value=12}, notes=TextValue{name=notes, value=Optional[some notes]}}
Problem - I don't know how to further pick each value and compare it.
As Value is an interface, I had to typecast it like follows.
val value = values.get("answer_id").asInstanceOf[TextValue]
value.getString.isPresent mustBe true
value.getString.get() mustBe "11111111-1111-1111-1111-111111111111"
Why don't you create an expected Put and verify with Mockito?

How to pass multiParams in scalatra

If I want to read a single parameter in a get request in scalatra I can do it as follows:
get("mypath/:id") {
val id = params("id")
...
}
According to the scalatra documentation I can also use multiParams to get a sequence of parameters:
val ids = multiParams("ids")
But it does not say how the URL should be formed should I wish to pass more than one parameter. So if I wanted to pass multiple ids what is the format for the URL?
I have tried it with ampersands, commas and semi-colons but to no avail: e.g.
../mypath/id1&id2
Check the docs: http://scalatra.org/guides/2.4/http/routes.html
As an example, let’s hit a URL with a GET like this:
/articles/52?foo=uno&bar=dos&baz=three&foo=anotherfoo
Look closely: there are two “foo” keys in there.
Assuming there’s a matching route at /articles/:id, we get the
following results inside the action:
get("/articles/:id") {
params("id") // => "52"
params("foo") // => "uno" (discarding the second "foo" parameter value)
params("unknown") // => generates a NoSuchElementException
params.get("unknown") // => None - this is what Scala does with unknown keys in a Map
multiParams("id") // => Seq("52")
multiParams("foo") // => Seq("uno", "anotherfoo")
multiParams("unknown") // => an empty Seq
}
So you would need to name each param. e.g. /mypath/?ids=id1&ids=id2&ids=id3
You can embed multiple same name parameters in the path and get them through multiParams:
// http://localhost:8080/articles/id1/id2
get("/articles/:id/:id"){
println(multiParams("id")) // => Seq("id1", "id2")
}

Scala - how to use variables in a multi-line string literal

I want to call value of 'myActionID' variable. How do I do that?
If i pass static value like "actionId":1368201 to myActionID then it works, but If I use "actionId" : ${actionIdd} it gives error.
Here's the relevant code:
class LaunchWorkflow_Act extends Simulation {
val scenarioRepeatCount = 1
val userCount = 1
val myActionID = "13682002351"
val scn = scenario("LaunchMyFile")
.repeat (scenarioRepeatCount) {
exec(session => session.set("counter", (globalVar.getAndIncrement+" "+timeStamp.toString())))
.exec(http("LaunchRequest")
.post("""/api/test""")
.headers(headers_0)
.body(StringBody(
"""{ "actionId": ${myActionID} ,
"jConfig": "{\"wflow\":[{\"Wflow\":{\"id\": \"13500145349\"},\"inherit-variables\": true,\"workflow-context-variable\": [{\"variable-name\": \"externalFilePath\",\"variable-value\": \"/var/nem/nem/media/mount/assets/Test.mp4\"},{\"variable-name\": \"Name\",\"variable-value\": \"${counter}\"}]}]}"
}""")))
.pause(pause)
}
}
setUp(scn.inject(atOnceUsers(userCount))).protocols(httpProtocol)
Everything works fine If I put value 13682002351 instead of myActionID. While executing this script in Gatling I am Getting this error
ERROR i.g.http.action.HttpRequestAction - 'httpRequest-3' failed to
execute: No attribute named 'myActionID' is defined
Scala has various mechanisms for String Interpolation (see docs), which can be used to embed variables in strings. All of them can be used in conjunction with the triple quotes """ used to create multi-line strings.
In this case, you can use:
val counter = 12
val myActionID = "13682002351"
val str = s"""{
"actionId": $myActionID ,
"jConfig": "{\"wflow\":[{\"Wflow\":{\"id\": \"13500145349\"},\"inherit-variables\": true,\"workflow-context-variable\": [{\"variable-name\": \"externalFilePath\",\"variable-value\": \"/var/nem/nem/media/mount/assets/Test.mp4\"},{\"variable-name\": \"Name\",\"variable-value\": \"${counter}\"}]}]}"
}"""
Notice the s prepended to the string literal, and the dollar sign prepended to the variable names.
Using S interpolated String we can do this easily:
s"""Hello Word , Welcome Back!
How are you doing ${userName}"""

Parse Json array response in scala\Play

There is a web service returning array of something
{"apps": [{"name": "one"}, {"name": "two"}]}
In my code I want to iterate every name
val request = WS.url(s"http://localhost:9000/getData")
val json = request.get.map { response =>
(response.json \ "apps" \\ "name")
}
json.foreach(println)
However all my attempts return single record
// Expect
one
two
// Actual
ListBuffer("one", "two")
First of all, the neat solution here would be:
val request = WS.url(s"http://localhost:9000/getData")
request.get.map { response =>
val names = (response.json \ "apps" \\ "name")
names.foreach(println)
}
Secondly, if you don't want to get confused about the types, you should change your naming standards. For a Future object, you may start with the prefix future, for an Option, it could start with maybe, etc. If you do so, the problem in your example will be more obvious:
val request = WS.url(s"http://localhost:9000/getData")
val futureJson = request.get.map { response =>
(response.json \ "apps" \\ "name")
}
futureJson.foreach(println) // you call foreach for a Future, not for a List
Thirdly, why would Future trait have a method called foreach? I think that's confusing for beginners and even mid-level developers. We know from other languages that, foreach means iterate over a list of objects. In Scala, it is considered part of "Monadic operations" which is still a gray area for me :), but the comment for Future.foreach in Scala source is this:
/** Asynchronously processes the value in the future once the value becomes available.
*
* Will not be called if the future fails.
*/
def foreach[U]
Your value of json is actually a Future[Seq[JsValue]], so when you foreach over the future you get the entire list back. You would need an additional foreach to iterate over the list of values.

Passing arguments between Gatling scenarios and simulation

I'm current creating some Gatling simulation to test a REST API. I don't really understand Scala.
I've created a scenario with several exec and pause;
object MyScenario {
val ccData = ssv("cardcode_fr.csv").random
val nameData = ssv("name.csv").random
val mobileData = ssv("mobile.csv").random
val emailData = ssv("email.csv").random
val itemData = ssv("item_fr.csv").random
val scn = scenario("My use case")
.feed(ccData)
.feed(nameData)
.feed(mobileData)
.feed(emailData)
.feed(itemData)
.exec(
http("GetCustomer")
.get("/rest/customers/${CardCode}")
.headers(Headers.headers)
.check(
status.is(200)
)
)
.pause(3, 5)
.exec(
http("GetOffers")
.get("/rest/offers")
.queryParam("customercode", "${CardCode}")
.headers(Headers.headers)
.check(
status.is(200)
)
)
}
And I've a simple Simulation :
class MySimulation extends Simulation {
setUp(MyScenario.scn
.inject(
constantUsersPerSec (1 ) during (1)))
.protocols(EsbHttpProtocol.httpProtocol)
.assertions(
global.successfulRequests.percent.is(100))
}
The application I'm trying to simulate is a multilocation mobile App, so I've prepared a set of samples data for each Locale (US, FR, IT...)
My REST API handles all the locales, therefore I want to make the simulation concurrently execute several instances of MyScenario, each with a different locale sample, to simulate the global load.
Is it possible to execute my simulation without having to create/duplicate the scenario and change the val ccData = ssv("cardcode_fr.csv").random for each one?
Also, each locale has its own load, how can I create a simulation that takes a single scenario and executes it several times concurrently with a different load and feeders?
Thanks in advance.
From what you've said, I think this may be a good approach:
Start by grouping your data in such a way that you can look up each item you want to send based on the current locale. For this, I would recommend using a Map that matches a locale string (such as "FR") to the item that matches that locale for the field you're looking to fill in. Then, at the start of each iteration of the scenario, you just pick which locale you want to use for the current iteration from a list. It would look something like this:
val locales = List("US", "FR", "IT")
val names = Map( "US" -> "John", "FR" -> "Pierre", "IT" -> "Guillame")
object MyScenario {
//These two lines pick a random locale from your list
val random_index = rand.nextInt(locales.length);
val currentLocale = locales(random_index);
//This line gets the name
val name = names(currentLocale)
//Do the rest of your logic here
}
This is a very simplified example - you'll have to figure out how you actually want to retrieve the data from files and put it into a Map structure, as I assume you don't want to hard code every item for every field into your code.