Best way to manipulate elements in foreach

6,448 views
Skip to first unread message

Matthew Royer

unread,
Jan 9, 2014, 1:03:35 PM1/9/14
to gat...@googlegroups.com
I want to be able to use .split() on the current element in a foreach for a scenario. Is that possible? For example, I have the following code:

=====

.exec(http("request_18")
  .get("/" + site + "//Main/portal/lists/index.cfm?list=tasks")
  .check(css("#column_packet_nm.listPageTableCell > a", "href").findAll.saveAs("tasks")))
.exec { session =>

  val myTaskID = session("tasks").as[Seq[String]]
  session.set("tasks", myTaskID)
}
.pause(4)
.foreach("${tasks}", "task") {
  exec(http("${task}")
  .get("/" + site + "/Main/portal/lists/index.cfm?list=tasks"))
}

=====

This gives me my strings in the sequence just find. But I want to be able to only grab a certain piece from the string later on.

I'm not sure how to do that with the interpolated string. I have tried a few different things:

=====

exec(http("${task}".split(""""\,"""")(1))
---> Which produces my full string with the split attached as a string.

exec(http("${task.split(',')(1)}")
---> Which gives me a message that my string plus .split(',')(1) is an attribute that can't be found

===== 

Any help with this would be appreciated. I'm sure, once again, I'm missing something simple.

Stéphane Landelle

unread,
Jan 9, 2014, 2:14:54 PM1/9/14
to gat...@googlegroups.com
You can't use Gatling EL and Scala code together!

http(_("task").validate[String].map(_.split(""""\,"""")(1)))


2014/1/9 Matthew Royer <matthe...@gmail.com>

--
You received this message because you are subscribed to the Google Groups "Gatling User Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to gatling+u...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Matthew Royer

unread,
Jan 9, 2014, 3:20:43 PM1/9/14
to gat...@googlegroups.com
Thank you! That worked.

I wanted to know why it worked though. What does the _("task") part do? Also why do I need to use .map()?

Sorry, I'm still learning Scala.

Nicolas Rémond

unread,
Jan 9, 2014, 3:27:58 PM1/9/14
to gat...@googlegroups.com
Underscore is a Scala shortcut for a closure. 
An expended version would be : 
  http(session => session("task").validate[String].map(_.split(""""\,"""")(1)))

Then, session("task").validate[String] produce a Validation[String]. So, to transform it, you can use .map() function on it.

clearer ?

Matthew Royer

unread,
Jan 9, 2014, 3:42:46 PM1/9/14
to gat...@googlegroups.com
Oh, that makes a lot more sense than what I was thinking.

Sorry about that. Thank you for taking the time to make that clear.

Nicolas Rémond

unread,
Jan 9, 2014, 3:45:40 PM1/9/14
to gat...@googlegroups.com
No prob.


Stéphane Landelle

unread,
Jan 9, 2014, 3:57:22 PM1/9/14
to gat...@googlegroups.com
Sure (sorry, I should have explained better, this will be detailed properly in Gatling 2 documentation).

1) Gatling EL syntax is very limited, you have to stick to the documentation. You can't mix it with Scala code. What happens is that Gatling DSL methods actually expects functions. The reason you can pass Strings instead is that there's an implicit conversion that parses the String and turn it into a function that manipulates the Session.

2) Regarding what I wrote:
Please have a look at Gatling 2 Session and Validation APIs:

The expected function signature is Session => Validation[String] (input is Session, output is Validation[String]), so:

session: Session => session("task").validate[String].map(task => task.split("""\"""")(1)))

session("task").validate[String] returns a Validation[String] Validation is a container (monad) and with map, you can create a new container of the same type, but with a new content, that's obtained here by splitting the string.

This function can be written more shortly.

Get it?


2014/1/9 Matthew Royer <matthe...@gmail.com>

Matthew Royer

unread,
Jan 14, 2014, 7:56:45 AM1/14/14
to gat...@googlegroups.com
Thank you for that explanation.

So, does that mean I can't declare var's or val's inside of the .foreach()?

I've been trying to do that because I'm curious if it would work. It would make a lot of things simpler. If not, I'll figure out another way to get what I need.

Matthew Royer

unread,
Jan 14, 2014, 8:51:17 AM1/14/14
to gat...@googlegroups.com
Oh, looks like I can create a var of the current task with no split or anything done to it. But I am not sure how to save the manipulated form. So I guess I didn't understand this as well as I thought.

I have tried .validate[String], .map(_.split()), and using the _("doc"). They all produce errors. The follow is the only way that doesn't produce errors right away, but after trying to run the scenario it stops with the error that the array index is out of bounds:

.foreach("${tasks}", "task") {
  var taskType = "${task}".split("""\,""")(0)
  val taskID = "${task}".split("""\,""")(1)
  val taskName = "${task}".split("""\,""")(2)
  val taskPacketStep = "${task}".split("""\,""")(4)
  val taskParallelID = "${task}".split("""\,""")(7)

  exec(http("request_21")
    .get("/" + site + "/main/portal/lists/listDetail.cfm?var1=${taskType}&var2=${taskID}&var3=${taskName}&var4=${taskPacketStep}&var5=&var6=1&var7=module:docs&var8=${taskParallelID}")
    .check(status.is(200)))

Stéphane Landelle

unread,
Jan 14, 2014, 3:49:03 PM1/14/14
to gat...@googlegroups.com
First, once again, "${task}".split("""\,""") just means "try to split the "${task}" String". There's no magic that would make it work the way you'd like.

Then, foreach content is only evaluated once, when building the scenario. That's the parameters of DSL methods, like request(DYNAMIC_HERE).get(DYNAMIC_HERE) that gets evaluated every time.


2014/1/14 Matthew Royer <matthe...@gmail.com>

Matthew Royer

unread,
Jan 16, 2014, 10:50:43 AM1/16/14
to gat...@googlegroups.com
Hmm... So is there any way for each user to have different GET actions based on an array of values that I get from doing the SaveAs() in the session?

The way our system works is we have some links in the page that brings up different task actions for each user via JavaScript. I can catch the task JavaScript (which holds IDs, task names, and other task info) with the SaveAs().

Each link (task) on the page has an href with all the task info in a JavaScript function. So it is saved into an array of strings. This is for each user. They all have different tasks, with different IDs, names, etc...

I'm trying to cut up those strings and then do a http(get()) with them. But I'm doing a .foreach() and want each individual task in the array split into its separate parts (ID, task name, packet name, etc..) so that they are in that get request each. All of them would get their own request.

Would doing some type of .repeat() work better to do this? Hopefully I'm making sense.

Stéphane Landelle

unread,
Jan 16, 2014, 11:09:16 AM1/16/14
to gat...@googlegroups.com

Hmm... So is there any way for each user to have different GET actions based on an array of values that I get from doing the SaveAs() in the session?

 

The way our system works is we have some links in the page that brings up different task actions for each user via JavaScript. I can catch the task JavaScript (which holds IDs, task names, and other task info) with the SaveAs().

Each link (task) on the page has an href with all the task info in a JavaScript function. So it is saved into an array of strings. This is for each user. They all have different tasks, with different IDs, names, etc...

I'm trying to cut up those strings and then do a http(get()) with them. But I'm doing a .foreach() and want each individual task in the array split into its separate parts (ID, task name, packet name, etc..) so that they are in that get request each. All of them would get their own request.

cut up = probably add a exec(function), like:

exec(session =>
    session("array").validate[String].map { array
        val parts = array.split(", ") // or a regex, or whatever you like
        session.setAll("ID" -> parts(0), "taskName" -> part(1), "packerName" -> part(2)) // store the parts
    }
)
 

Would doing some type of .repeat() work better to do this? Hopefully I'm making sense.

No, I think foreach is the way to go:
  • first multiple results (.findAll)
  • loop on those with foreach
  • on each iteration, split current element and store the parts

Matthew Royer

unread,
Jan 16, 2014, 5:07:36 PM1/16/14
to gat...@googlegroups.com
Success!!!! Thank you. Exactly what I needed! I didn't realize I would need another .exec(session)...

I've been toying around with it for a while now and have come up with some pretty interesting scripts because of this.

Thank you so much. I believe that's all of my major issues you've solved.

--Matt Royer

Stéphane Landelle

unread,
Jan 16, 2014, 5:22:49 PM1/16/14
to gat...@googlegroups.com
Glad to hear!

Hopefully we'll write a comprehensive documentation so that people will waste less time with trials and errors...


2014/1/16 Matthew Royer <matthe...@gmail.com>
Reply all
Reply to author
Forward
0 new messages