代码之家  ›  专栏  ›  技术社区  ›  WesternGun

scala-使用匿名函数从gatlingel表达式解析的进程字符串

  •  1
  • WesternGun  · 技术社区  · 6 年前

    我在一个http测试中使用gatlingel表达式,似乎包装任何类型的EL表达式都会使解析无效,即。,

    这是有效的:

    def run(env: Parameters): ChainBuilder =
      feed(env.feeder)
      .exec(
        http(Seq(env.env, "verify").mkString(":"))
          .get(env.base + "/verify")
          .queryParam("email", "${username}")
          .check(
            status.is(200),
            jsonPath("$..exist").is("true"),
          )
      )
      exitHereIfFailed
    

    def run(env: Parameters): ChainBuilder =
      feed(env.feeder).exec(
        http(Seq(env.base, "authorize").mkString(":"))
          .post(env.base + "/authorize")
          .asJSON // "Accept" and "ContentType" set to JSON
          .header(HttpHeaderNames.AcceptCharset, "UTF-8")
          .header(HttpHeaderNames.Authorization,
            "AppBasic " + Base64.getEncoder().encodeToString(("${username}" + ":" + "password").getBytes())))
          .body(StringBody(env.authorizeBody))
          .check(
            status.is(200),
            header(HttpHeaderNames.ContentType).is(HttpHeaderValues.ApplicationJson),
            header(HttpHeaderNames.AcceptCharset).is("UTF-8"),
            jsonPath("$..id_token") exists
        )
      )
    

    我想用Base64编码“电子邮件:密码,并将其用作授权头,前缀为“AppBasic”。事实并非如此 Basic 授权,其中 基本

    现在我做一些类似的事情:

    ...
    .header(HttpHeaderNames.Authorization,
          "AppBasic " + "${username}".map(username => Base64.getEncoder().encodeToString((username + ":" + "password").getBytes())))
    ...
    

    但是,日志显示了一个奇怪的现象 Vector String .

    HTTP request:
    POST <some url>
    headers=
    Accept: application/json
    Content-Type: application/json
    Accept-Charset: UTF-8
    Authorization: AppBasic Vector(JDoxMTEx, ezoxMTEx, dToxMTEx, czoxMTEx, ZToxMTEx, cjoxMTEx, bjoxMTEx, YToxMTEx, bToxMTEx, ZToxMTEx, fToxMTEx)
    User-Agent: curl/7.54.0
    Content-Length: 143
    

    因此,它是一个就地字符串转换,而不是一个集合映射。我能做什么?

    2 回复  |  直到 6 年前
        1
  •  2
  •   tilois    6 年前

    这更像是一个Gatling问题,而不是Scala问题,但是让我们来看看到底发生了什么。

    Scala字符串插值

    要将值包含到字符串中,可以使用字符串插值 ${…} 语法。例子:

    s"Hello, $name" 哪里 name = "World" 会导致 "Hello World . 然而,那就是 你在用什么。

    现在最简单的方法就是用这个代替。但是它需要 username 在scala程序中可用。

    如果我没看错,那么您希望值来自Gatling会话,因此使用 Gatling Expression Language

    如果不是这样,最简单的方法就是使用Scala字符串插值:

    def asBase64(input: String): String = java.util.Base64.getEncoder().encodeToString(input.getBytes())
    val username = "johnDoe"
    val password = "1111" // Some more or less random password
    val headerValue = asBase64(s"${username}:$password")
    val header = s"Basic $headerValue" // … should be "Basic am9obkRvZToxMTEx" here
    

    这是怎么回事?

    Gatling解析字符串参数值 并将它们转换为函数,在对它们进行求值时,根据存储在会话中的数据计算结果。

    这需要将字符串传递给Gatling。不过,这里使用的是纯Scala来转换字符串。 Gatling是一个嵌入式DSL,这意味着它被嵌入到宿主语言(Scala)中,而这正是你所需要的。

    你在做这个

    "${username}".map(username =>
        Base64.getEncoder().encodeToString((username + ":" + "password").getBytes()
    

    让我们一步一步来: ${username} 字符串插值与上面一样,因为它在开头缺少“字符串插值方法”(例如 s 在里面 s"" )这是正确的,如果你想传递它,让它被Gatling解析。 但是你没有把它传给加特林,而是你 map 在上面。 这是普通的Scala,Scala不知道 Session 值在其中。

    取而代之的是 String.map 传递每个字符并在其上使用函数。 你认为 实际上是一个单身 .

    username + ":" + "password" 在每个字母上。 顺便说一句:你原来的代码没有 "password" 如果这是一个真正的隐藏密码,它就不再隐藏了(Base64是可逆的)。

    所以这就是

    Vector(JDoxMTEx, ezoxMTEx, dToxMTEx, czoxMTEx, ZToxMTEx, cjoxMTEx, bjoxMTEx, YToxMTEx, bToxMTEx, ZToxMTEx, fToxMTEx)
    

    来自。它有11个条目,每个字母对应一个条目: $, {, u, s, e, r, n, a, m, e, } 再加上一点。

    使用会话中的密码可以做什么

    最简单的方法是使用什么 Gatling already offers AppBasic 并将使用 Basic

    你可以用 Session API 访问值(使用 session("name") 访问会话中的值)。

    .header(HttpHeaderNames.Authorization, s"AppBasic ${asBase64(s"${session("username").as[String]}:$password")}")
    

    假设函数 asBase64 像上面定义的那样(否则会有点长),并且有一个变量 password 在范围内。 如果不只是用你想要的价值来代替它(和美元一起)。

    希望这能帮你解决问题。 我想说的是,你没有完全意识到什么是Gatling特有的,什么是Scala(这是完全可以的,但有时它会咬你,就像这里)。我写了一点篇幅,希望这能把它分开一点。

    您的基本问题是,您习惯于使用美元表示法访问会话中的值。只要你把值传给加特林就行了。在这种情况下,加特林是为你做的。然而,它在普通Scala中不起作用,因此您必须使用会话API来访问它们。如果API讨论 Expression[…] 这意味着Gatling需要额外的时间来解析它(这就是为什么它知道其中有一个引用)

        2
  •  0
  •   WesternGun    6 年前

    从另一个问题中找到答案:

    Using a feeder to pass in header values (Gatling)

    解决方案是在这里编写一个函数,在我的例子中:

    .header(HttpHeaderNames.Authorization, session =>
        for {
            username <- session("username").validate[String]
        } yield "AppBasic " + Base64.getEncoder.encodeToString((username + ":" + "1111").getBytes())
    )
    

    谢谢你。

    在发现这一点之前,我做了一个解决办法:团队领导用一个20行的csv替换10k行测试csv,因为Gatling会在测试中预先将内容加载到内存中,而根据文档,如果有一个大的csv将消耗内存。

    所以我可以用20行代码来硬编码电子邮件:密码输入csv文件,并用列名“${col\$name}”读取它们。

    但最好从课时开始阅读。我不知道。谢谢提洛瓦。