Configuring loops with an external parameter

894 views
Skip to first unread message

Thomas Segismont

unread,
Jun 1, 2015, 5:14:59 AM6/1/15
to gat...@googlegroups.com
Hi everyone,

I'm trying to build a configurable scenario. I want the tester to be able to configure the number of loops but at execution time I get this ouput:

[INFO] --- gatling-maven-plugin:2.1.6:execute (default-cli) @ hawkular-metrics-load-tests ---
10:43:15.156 [main][ERROR][ZincCompiler.scala:108] i.g.c.ZincCompiler$ - /home/tsegismont/Projets/hawkular-metrics/load-tests/src/test/scala/org/hawkular/metrics/loadtest/MetricsSimulation.scala:25: type mismatch;
 found  
: Integer
 required
: io.gatling.core.session.Expression[Int]
   
(which expands to)  io.gatling.core.session.Session => io.gatling.core.validation.Validation[Int]
10:43:15.161 [main][ERROR][ZincCompiler.scala:108] i.g.c.ZincCompiler$ -     val simulation = repeat(loops, "n") {
10:43:15.163 [main][ERROR][ZincCompiler.scala:108] i.g.c.ZincCompiler$ -                             ^
10:43:15.530 [main][ERROR][ZincCompiler.scala:108] i.g.c.ZincCompiler$ - one error found

I'm sure it's something stupid but I have zero Scala knowledge... :-(

Here's my simulation file:

package org.hawkular.metrics.loadtest

import scala.concurrent.duration._

import io.gatling.core.Predef._
import io.gatling.http.Predef._
import io.gatling.jdbc.Predef._

class MetricsSimulation extends Simulation {

    val baseURI
= System.getProperty("baseURI", "http://localhost:8080")

    val clients
= Integer.getInteger("clients", 1)
    val ramp  
= java.lang.Long.getLong("ramp", 0L)

    val loops
= Integer.getInteger("loops", 1000)
    val interval
= Integer.getInteger("interval", 1)

    val httpProtocol
= http
       
.baseURL(baseURI)
       
.header("Hawkular-Tenant", "default")
       
.contentTypeHeader("application/json;charset=utf-8")

    val simulation
= repeat(loops, "n") {
       
exec(http("Report ${n}")
           
.post("/hawkular/metrics/gauges/data")
           
.body(ELFileBody("body.json")).asJSON
       
).pause(interval)
   
}

    val scn
= scenario("MetricsSimulation").exec(simulation)

    setUp
(scn.inject(rampUsers(clients) over (ramp seconds))).protocols(httpProtocol)
}


Thanks in advance for your help and the awesome tool!
 

Best regards,
Thomas




Pierre DAL-PRA

unread,
Jun 1, 2015, 5:23:12 AM6/1/15
to gat...@googlegroups.com
Can you please try to change 
 val loops = Integer.getInteger("loops", 1000)

to:

 val loops = Integer.getInteger("loops", 1000).toInt

?

Cheers,

Pierre

Stéphane LANDELLE

unread,
Jun 1, 2015, 5:25:22 AM6/1/15
to gat...@googlegroups.com
Salut Thomas,

TL;DR:
Scala types are different from the Java ones.
 val loops = Integer.getInteger("loops", 1000).toInt // Scala way

or
val loops = Integer.getInteger("loops", 1000).intValue // Java way


Long explanation:
An implicit conversion between Integer and Int can automatically happen but only if there's only one implicit conversion involved.
And there's already one because repeat actually takes a function (so there's an implicit conversion from raw value to function).

Have fun!


Stéphane Landelle
Lead developer


--
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/d/optout.

Thomas Segismont

unread,
Jun 1, 2015, 5:28:31 AM6/1/15
to gat...@googlegroups.com
It works. Awesome, thanks!

Thomas Segismont

unread,
Jun 1, 2015, 5:49:58 AM6/1/15
to gat...@googlegroups.com

Le lundi 1 juin 2015 11:25:22 UTC+2, Stéphane Landelle a écrit :

Long explanation:
An implicit conversion between Integer and Int can automatically happen but only if there's only one implicit conversion involved.
And there's already one because repeat actually takes a function (so there's an implicit conversion from raw value to function).


Good to know, thanks. I guess that's why other parameters don't need conversion.
 
Have fun!


I'm already having some :) Now I need to figure out how to build a JSON string with a configurable number of metrics data points. Once this is done I'll be in the Nirvana :p

Stéphane LANDELLE

unread,
Jun 1, 2015, 6:07:39 AM6/1/15
to gat...@googlegroups.com
Now I need to figure out how to build a JSON string with a configurable number of metrics data points. Once this is done I'll be in the Nirvana :p

Many different possibilities, depending on your use case and your Scala skills :)

If your template is "almost" static, ie number of metrics doesn't depend on user but only on System props, you can easily write a Gatling EL String template (see StringBody).

Thomas Segismont

unread,
Jun 1, 2015, 7:11:52 AM6/1/15
to gat...@googlegroups.com
I wrote this:

package org.hawkular.metrics.loadtest

import scala.concurrent.duration._

import io.gatling.core.Predef._
import io.gatling.http.Predef._
import io.gatling.jdbc.Predef._

class MetricsSimulation extends Simulation {

    val baseURI
= System.getProperty("baseURI", "http://localhost:8080")

    val clients
= Integer.getInteger("clients", 1)
    val ramp  
= java.lang.Long.getLong("ramp", 0L)


    val loops
= Integer.getInteger("loops", 10).toInt
    val interval
= Integer.getInteger("interval", 1)

    val metrics
= Integer.getInteger("metrics", 10)
    val points
= Integer.getInteger("points", 1)


    val httpProtocol
= http
       
.baseURL(baseURI)
       
.header("Hawkular-Tenant", "default")
       
.contentTypeHeader("application/json;charset=utf-8")


    val random
= new util.Random
    val genReport
= (m: Int, p: Int) => {
        val builder
= new StringBuilder
        builder
+= '['
       
for (i <- 1 to m) {
            builder
++= """{"id":"metrics.load.test."""
            builder.append(i)
            builder ++= """
.value","data":["""
           
for (j <- 1 to p) {
                builder
++= """{"timestamp":"""
                builder
.append(System.currentTimeMillis)
                builder
++= ""","value":"""
                builder
.append(random.nextDouble)
                builder
+= '}'
               
if (j < p) builder += ','
           
}
            builder
++= "]}"
           
if (i < m) builder += ','
       
}
        builder
+= ']'
        builder
.toString
   
}
    val feeder
= Iterator.continually(Map("jsonReport" -> genReport(metrics, points)))


    val simulation
= repeat(loops, "n") {

        feed
(feeder)
       
.exec(http("Report ${n}")
           
.post("/hawkular/metrics/gauges/data")
           
.body(StringBody("""${jsonReport}"""))

       
).pause(interval)
   
}

    val scn
= scenario("MetricsSimulation").exec(simulation)

    setUp
(scn.inject(rampUsers(clients) over (ramp seconds))).protocols(httpProtocol)
}

I'm sure it's not idiomatic Scala but it seems to work as expected.

Stéphane LANDELLE

unread,
Jun 1, 2015, 7:35:12 AM6/1/15
to gat...@googlegroups.com
I'm sure it's not idiomatic Scala but it seems to work as expected.

Well, it's not because Gatling is written in Scala that we enforce any coding style on you.
The most important is you feel confident in the way you write and can maintain.


Then, if I may: there's no need to store the generated body in the Sessions with a Feeder.
You can just simply call genReport from  StringBody:

    val simulation = repeat(loops, "n") {

        
exec(http("Report ${n}")
            
.post("/hawkular/metrics/gauges/data")

            
.body(StringBody(session => genReport(metrics, points)))
        ).pause(interval)
    
}


Also, note that, instead of writing:
if (< m) builder += ','

you can simply move the StringBuilder's index after the loop:
builder.setLength(builder.length - 1)


Cheers,

Stéphane

Thomas SEGISMONT

unread,
Jun 1, 2015, 9:03:01 AM6/1/15
to gat...@googlegroups.com
Thanks for the tips!


2015-06-01 13:35 GMT+02:00 Stéphane LANDELLE <slan...@gatling.io>:
Then, if I may: there's no need to store the generated body in the Sessions with a Feeder.
You can just simply call genReport from  StringBody:

    val simulation = repeat(loops, "n") {
        
exec(http("Report ${n}")
            
.post("/hawkular/metrics/gauges/data")
            
.body(StringBody(session => genReport(metrics, points)))
        ).pause(interval)
    
}



Awesome. The scenario does not look convoluted this way.
 
Also, note that, instead of writing:
if (< m) builder += ','

you can simply move the StringBuilder's index after the loop:
builder.setLength(builder.length - 1)



I don't understand this :(

Could you explain why this call to #setLength will add the comma? Sorry if the question might sound stupid.

Thomas Segismont

unread,
Jun 1, 2015, 4:23:43 PM6/1/15
to gat...@googlegroups.com
Yeah, you keep:
builder += ','
without the "if"

But after the loop:
builder.setLength(builder.length - 1)

Auto facepalm :)

pandya ronak

unread,
Jun 25, 2016, 5:46:00 AM6/25/16
to Gatling User Group
Hi All,
I am stuck here.
I want that user can input 'userCount, repeatCount, testServerUrl and definitionId' from command line while executing from Gatling. From command line I execute
`
    > export JAVA_OPTS="-DuserCount=1 -DflowRepeatCount=1 -DdefinitionId=10220101 -DtestServerUrl='https://someurl.com'"
    > sudo bash gatling.sh`

but there is runtime error,
Errors ------------------------------
--------------------------------------
` url null/api/workflows can't be parsed into a URI: scheme `

URL which I provide is shown null
Actually it is not taking the parameters which we provide thru cmd.. If I write JAVA_OPTS="-Duseraskjafsjafajnfwet=5" gatling.bat -s TestCLI instead of JAVA_OPTS="-DuserCount=5" gatling.bat -s TestCLI it will accept it and runs default value(however it taked default value only not parameters we passed) val userCount: Int = Integer.getInteger("userCount", 1).toInt It takes '1' not 5(which we pass thru cmd)

Here is the code snippet,


import io.gatling.core.Predef._
import io.gatling.http.Predef._
import scala.concurrent.duration._        

class TestCLI extends Simulation {          
    val userCount = Integer.getInteger("userCount", 1).toInt   
    val holdEachUserToWait = 2 
    val flowRepeatCount = Integer.getInteger("flowRepeatCount", 2).toInt   
    val definitionId  = java.lang.Long.getLong("definitionId", 0L)     
    val testServerUrl = System.getProperty("testServerUrl")

    val httpProtocol = http
            .baseURL(testServerUrl)
            .inferHtmlResources()
            .acceptHeader("""*/*""")
            .acceptEncodingHeader("""gzip, deflate""")
            .acceptLanguageHeader("""en-US,en;q=0.8""")
            .authorizationHeader(envAuthenticationHeaderFromPostman)
            .connection("""keep-alive""")
            .contentTypeHeader("""application/vnd.v7811+json""")

            .userAgentHeader("""Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.65 Safari/537.36""")

    val headers_0 = Map(
            """Cache-Control""" -> """no-cache""",
            """Origin""" -> """chrome-extension://faswwegilgnpjigdojojuagwoowdkwmasem""")



                    val scn = scenario("testabcd")
                        .repeat (flowRepeatCount) {
                            exec(http("asdfg")
                            .post("""/api/workflows""")

                            .headers(headers_0)
                            .body(StringBody("""{"definitionId":$definitionId}"""))) // I also want to get this value dynamic from CLI and put here
                            .pause(holdEachUserToWait)
                        }                  

                    setUp(scn.inject(atOnceUsers(userCount))).protocols(httpProtocol)

                }

Thanks.
Reply all
Reply to author
Forward
0 new messages