在 Gatling 中创建加权馈线

Create a weighted feeder in Gatling

我有几个 .csv 文件要用于 Gatling 中的相同数据。这些文件中的每一个都有一定数量的 ID,我希望能够公平地访问这些文件。我不想将它们全部放在同一个文件中,因为 .csv 文件是从 SQL 查询生成的,虽然我可能在一个文件中有很多 ID,但在另一个文件中只有几个。对我来说重要的是我从我的每个文件中得到一个随机样本和一种指定分布的方法。

我找到了 an example 如何执行此操作,但在我的案例中应用它时遇到了问题。这是我到目前为止的代码。我尝试 1) 在会话中打印出来自馈线的值和 2) 尝试在获取请求中使用来自馈线的值。两次尝试都失败了,我在下面详述了各种错误:

import scala.concurrent.duration._

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

class FeederTest extends Simulation {

  //headers...

  val userCreds = csv("user_creds.csv")

  val sample1 = csv("sample1.csv")

  val sample2 = csv("sample2.csv")

  def randFeed(): String = {
    val foo = Random.nextInt(2)
    var retval = ""
    if (foo == 0) retval = "file1"
    if (foo == 1) retval = "file2"
    return retval
  }

  val scn = scenario("feeder test")
    .repeat(1) {
      feed(userCreds)
        .doSwitch(randFeed)(
          "file1" -> feed(sample1),
          "file2" -> feed(sample2)
        )  
        .exec(http("request - login")
          .post("<URL>")
          .headers(headers_login)
          .formParam("email", "${username}")
          .formParam("password", "<not telling>"))
        .exec(session => {
           println(session)
           println(session("first").as[String])
           session})
        .exec(http("goto_url")
          .get("<my url>/${first}"))

        }
  setUp(scn.inject(atOnceUsers(1))).protocols(httpProtocol)
}

这是我在会话中尝试打印进纸器值时遇到的错误(如上面使用 session(<value>).as[String] 的代码):

[ERROR] [03/13/2015 10:22:38.221] [GatlingSystem-akka.actor.default-dispatcher-8] [akka://GatlingSystem/user/sessionHook-2] key not found: first                                                                              
java.util.NoSuchElementException: key not found: first                                                         
        at scala.collection.MapLike$class.default(MapLike.scala:228)                                                    at scala.collection.AbstractMap.default(Map.scala:59)                                                  
        at scala.collection.MapLike$class.apply(MapLike.scala:141)                                             
        at scala.collection.AbstractMap.apply(Map.scala:59)                                                    
        at io.gatling.core.session.SessionAttribute.as(Session.scala:40)                                       
        at FeederTest$$anonfun.apply(feeder_test.scala:81)                                                   
        at FeederTest$$anonfun.apply(feeder_test.scala:79)                                                   
        at io.gatling.core.action.SessionHook.executeOrFail(SessionHook.scala:35)                              
        at io.gatling.core.action.Failable$class.execute(Actions.scala:71)                                     
        at io.gatling.core.action.SessionHook.execute(SessionHook.scala:28)                                    
        at io.gatling.core.action.Action$$anonfun$receive.applyOrElse(Actions.scala:29)                      
        at scala.PartialFunction$OrElse.applyOrElse(PartialFunction.scala:171)                                 
        at akka.actor.Actor$class.aroundReceive(Actor.scala:465)                                               
        at io.gatling.core.akka.BaseActor.aroundReceive(BaseActor.scala:22)                                    
        at akka.actor.ActorCell.receiveMessage(ActorCell.scala:516)                                            
        at akka.actor.ActorCell.invoke(ActorCell.scala:487)                                                    
        at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:254)    
        at akka.dispatch.Mailbox.run(Mailbox.scala:221)                                                        
        at akka.dispatch.Mailbox.exec(Mailbox.scala:231)                                                       
        at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)                                
        at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)                    
        at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)                            
        at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)

我也试过在会话中只使用 EL 表达式 ${first}。所有这一切只是打印出字符串 ${first}。同样,在最后 .get 行中,我收到一条错误消息“未定义名为 'first' 的属性。

我目前使用的 CSV 文件只有两列,第一列和最后一列,如下所示:

sample1.csv:
first, last
george, bush
bill, clinton
barak, obama

sample2.csv:
first, last
super, man
aqua, man
bat, man

我正在使用 Gatling 2.1.4。

我从来没有用过喂食器,但是从文档中,我看到了两个可能的问题:

  1. randFeed returns "foo" 或 "bar" 但您正在使用 "file1" 和 "file2" 进行映射,因此正在加载任何内容? (documentation 表示 "If no switch is selected, the switch is bypassed.")
  2. 我看到的 examples for feeders 没有显示使用 session(varname) 访问馈送数据,而是 "${varname}".

doSwitch 采用 Expression[Any],这是 Session => Validation[Any] 的类型别名。 Gatling 有一个隐式转换,可以让你传递一个静态值,参见 documentation.

这正是您所做的。即使 randFeed 是一个 def,它仍然不是 return 一个函数,而是一个字符串。

由于您希望每次虚拟用户通过此步骤时都调用 randFeed,因此即使您不使用 Session 输入参数,也必须将 randFeed 包装在一个函数中。

doSwitch(_ => randFeed)

那么,你的 randFeed 既丑陋(无意冒犯)又低效(随机同步):

import scala.concurrent.forkjoin.ThreadLocalRandom
def randFeed(): String =
  ThreadLocalRandom.current().nextInt(2) match {
    case 0 => "file1"
    case 1 => "file2"
  }