Looping for each char in string

Hi,

I am trying to send a request for each char in a String (in order to test an autocomplete service), but no request is sent:

var tmp = “”
val autocompleteMobile: ChainBuilder = exec(session => {
session(“text”).as[String].foreach { c =>
tmp = tmp.concat(c.toString)
println("Mot: " + tmp)
exec(http(“Autocomplete MOBILE”)
.get(“my_url/autocomplete?text=${tmp}”)
}
session
})

this ChainBuilder (autocompleteMobile) is called at a scenario level in another file like this:
val mobileAutocomplete: ScenarioBuilder = scenario(“Mobile autocomplete”)
.randomSwitch(
20d → feed(cl1).feed(search_word).exec(autocompleteMobile),
20d → feed(cl2).feed(search_word).exec(autocompleteMobile),
20d → feed(cl3).feed(search_word).exec(autocompleteMobile),
20d → feed(cl4).feed(search_word).exec(autocompleteMobile),
20d → feed(cl5).feed(search_word).exec(autocompleteMobile)
)

When I execute this, I can see the expected behaviour but no request is sent:

logs:

Simulation simulations.Nominal started…
Mot: p
Mot: pa
Mot: par
Mot: parm
Mot: parme
Mot: parmes
Mot: parmesa
Mot: parmesan

[…] There were no requests sent during the simulation, reports won’t be generated

Any idea on what could have happenned?

Thank you in advance,

Terry

This e-mail and any attachment are confidential and intended solely for the use of the individual to whom it is addressed. If you are not the intended recipient, please telephone or email the sender and delete this message and any attachment from your system. Unauthorized publication, use, dissemination, forwarding, printing or copying of this e-mail and its associated attachments is strictly prohibited.

Let’s respect the environment together. Only print this message if necessary.

That can’t work.

https://gatling.io/docs/gatling/reference/current/general/scenario/#exec

Gatling DSL components are immutable ActionBuilder(s) that have to be chained altogether and are only built once on startup. The result is a workflow chain of Action(s). These builders don’t do anything by themselves, they don’t trigger any side effect, they are just definitions. As a result, creating such DSL components at runtime in functions is completely meaningless. If you want conditional paths in your execution flow, use the proper DSL components (doIf, randomSwitch, etc)

You have to use a proper Gatling DSL loop, not a scala loop inside a function.

Thank you Stéphane,

I try doing this in a Gatling’s foreach loop, but I can’t make it work because foreach expects scala.collection.immutable.Seq and I give him a String. I need to loop for each char. I am trying some other stuff.

@sujinsa, thank you too ! But this is not what I want to do.
For a given word (let’s say “banana”), I want to iterate over each char, and send multiple requests sequentially:
req1 with ‘b’
req2 with ‘ba’
req3 with ‘ban’
etc…

Hi,
I try to find a solution but I still can’t find one.
Is this possible ?

For now I simply try to print a session atrribute but this won’t work:

var tmp = “”
var list: Seq[String] = SeqString

val autocompleteMobile: ChainBuilder = exec { session =>
session(“text”).as[String].foreach { c => //getting value from feeder
tmp = tmp.concat(c.toString)
list = list :+ tmp
}
println("out loop: " + list) // prints : “out loop: List(c, cr, cri, cris, crist, crista, cristal, cristali, cristalin, cristaline)”
session.set(“liste”, list)

println(“Liste:” + session(“liste”).validate[Seq[String]]) // prints nothing => Liste:Failure(No attribute named ‘liste’ is defined)
session
}.exec(…)

Any idea why I cannot find the session attribute liste ?

Thank you in advance

https://gatling.io/docs/gatling/reference/current/session/session_api/#setting-attributes

Session instances are immutable!

Sorry but I don’t understand why this does not work:

I try to do this:

var tmp = “”
var list: Seq[String] = SeqString // var is for mutable variables

val autocompleteMobile: ChainBuilder = exec { session =>
session(“text”).as[String].foreach { c =>
tmp = tmp.concat(c.toString)
list = list :+ tmp
}
val tmp_list: Seq[String] = list // I create a tmp_list with keyword ‘val’ which should be immutable
println("out loop: " + list)
session.set(“liste”, tmp_list)

println(“Liste:” + session(“liste”).validate[Seq[String]])
session
}

This still does not work.
Liste:Failure(No attribute named ‘liste’ is defined)

Immutable means the value does not have to change after declaration right ? I just do session.set and session.get for printing. Can you please enlighten me ?

Hi!

Take care that session#set returns a new instance. (as session is immutable, a new instance is returned instead).

exec { session =>
  session("text").as[String].foreach { c =>
    tmp = tmp.concat(c.toString)
    list = list :+ tmp
  }
  val sessionWithList = session.set("liste", list) // <= new instance is created here!

  println("Liste:" + sessionWithList("liste").validate[Seq[String]])  // <= use your new session
  sessionWithList
}

Cheers!

That was it ! Thank you very much !

Hi Again,

Sorry for being unable to continue on my own, but I still cannot understand why it does not work. My need is to be able to iterate over a String, and send an HTTP request for each char in order to inject load to an autocomplete service:

var tmp = “”
var list: Seq[String] = SeqString

val autocompleteMobile: ChainBuilder = exec { session =>
session(“text”).as[String].foreach { c =>
tmp = tmp.concat(c.toString)
list = list :+ tmp
}
val newSession = session.set(“liste”, list)
println(“Liste:” + newSession(“liste”).as[Seq[String]]) // This works now => prints “Liste:List(l, la, lai, lait)”

newSession

}.exec( session => { //Here is the part where I cannot iterate over the List

println("List before foreach: " + session(“liste”).as[Seq[String]]) // Works fine too, prints “List before foreach: List(l, la, lai, lait)”
foreach(session(“liste”).as[Seq[String]], “text”) { // At this point, this does not work. => logs show “There were no requests sent during the simulation, reports won’t be generated”, which is normal. But nothing is printed before.
exec { session =>
println(“Element: ${text}”) // I’m expecting this code to print each element of my List, but nothing is done. It’s like foreach does not iterate over it.
//future http call will be here
session
}
}
session
}

From the documentation: sequenceName can be a sequence, an EL string pointing to a Seq[Any] Session attribute, or an Expression[Seq[Any]]

It seams that my session attribute is one of this.
Any help would be appreciated, thank you in advance.

Terry

Finally, I got it worked !

I post the solution here for those who will need it later on.

var tmp = “”
var list: Seq[String] = SeqString

val autocompleteMobile: ChainBuilder = exec { session =>
session(“text”).as[String].foreach { c =>
tmp = tmp.concat(c.toString)
list = list :+ tmp
}
val newSession = session.set(“liste”, list)
newSession
}.exec(
foreach("${liste}", “text”) {
exec(http(“Autocomplete MOBILE”)
.get("/my_uri/${text}")
.header(“id”, “${catalog}”))
}
)

For exemple, with text=bed, this will send 3 requests:

  1. /my_uri/b
  2. /my_uri/be
  3. /my_uri/bed

This is wrong.

You’ve defined tmp and list accumulators as global, hence shared amongst all virtual users.
This is going to break as soon as you’ll run more than 1 concurrent user.

Those accumulators should be unique per virtual user, hence stored inside their respective Session.

Hi,

I think this might be a solution.
This works and the variables are saved as session attributes.

val autocompleteMobile: ChainBuilder = exec { session =>
var tmpSession = session.set(“tmp”, “”).set(“list”, new ListBufferString)

session(“text”).as[String].foreach { c =>
tmpSession = tmpSession.set(“tmp”, tmpSession(“tmp”).as[String].concat(c.toString))
tmpSession = tmpSession.set(“list”, tmpSession(“list”).as[ListBuffer[String]] += tmpSession(“tmp”).as[String])
}

val newSession = tmpSession.set(“liste”, tmpSession(“list”).as[ListBuffer[String]].toList)
newSession
}.exec(
foreach("${liste}", “text”) {
exec(http(“Autocomplete MOBILE”)
.get("/my_uri/${text}")
.header(“id”, “${catalog}”))
}
)

NOTE:
I tried to replace these lines:
tmpSession = tmpSession.set(“tmp”, tmpSession(“tmp”).as[String].concat(c.toString))
tmpSession = tmpSession.set(“list”, tmpSession(“list”).as[ListBuffer[String]] += tmpSession(“tmp”).as[String])

with:
tmpSession = tmpSession.set(“tmp”, tmpSession(“tmp”).as[String].concat(c.toString)).set(“list”, tmpSession(“list”).as[ListBuffer[String]] += tmpSession(“tmp”).as[String])

But this does not work because tmpSession(“tmp”).as[String] has no value in the first loop.

Terry

Terry - see if this alternative works for you

val autocompleteMobile: ChainBuilder =
repeat(session => session(“text”).as[String].length, idx) {
exec(session =>
session
.set(“input”, session(“text”).as[String].take(idx + 1))
)
.exec(
http(“Autocomplete MOBILE”)
.get("/my_uri/${input}")
.header(“id”, “${catalog}”)
)
}