scala-使用匿名函数从加特林(Gatling)表达式解析的处理字符串

时间:2019-01-02 12:10:10

标签: scala gatling

我在http测试中使用了加特林EL表达式,看来包装任何形式的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“ email:password”进行编码,并将其用作授权标头,并以“ AppBasic”作为前缀。因此,不是Basic授权,它以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 个答案:

答案 0 :(得分:1)

这比Scala问题更像是加特林问题,但让我们尝试找出这里发生的情况。

Scala字符串插值

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

s"Hello, $name",其中name = "World"将产生"Hello World。但是,这不是您正在使用的内容。

现在最简单的方法是实际使用它。但是,它将需要在scala程序中使用username的值。

如果我没看错的话,您希望该值来自“加特林会话”,因此您正在使用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)解析字符串参数值,并将其转换为函数,该函数将在评估它们时基于存储在Session中的数据来计算结果。

(摘自文档,重点是我) 这要求将字符串传递给Gatling。但是,您在此处使用普通的Scala来转换String。 Gatling是嵌入式DSL,这意味着它嵌入在主机语言(Scala)中,这对您来说只是一个问题。

您正在这样做

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

让我们逐步进行以下操作: ${username}不是上面的 字符串插值,因为它开头缺少“字符串插值方法”(例如s中的s""),这是正确的,如果您想按字面传递它,以供Gatling解析。 但是,您不会将其传递给加特林,而是map。 这是普通的Scala,而Scala根本不知道其中包含值的Session之类的东西。

相反,String.map传递每个字符并在其上使用函数。 您认为username实际上就是一个字母

因此,它继续进行并且在每个字母上使用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中工作,您必须使用Session API访问它们。您可以查看是否可以使用美元符号访问值,如果API讨论了Expression[…],这意味着加特林需要额外的时间来解析它(这就是为什么它知道其中包含引用的原因) )

答案 1 :(得分:0)

找到了另一个问题的答案:

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())
)

谢谢。

在发现此问题之前,我已经采取了一种变通方法:团队负责人将20k行的csv替换为10k行的csv,因为加特林将事先将内容加载到测试中的内存中,并且较大的csv将消耗内存文档。

因此,只要20行,我就可以在csv文件中对编码的email:password进行硬编码,并以列名“ $ {col_name}”读取它们。

但是最好从会话中阅读。我不知道谢谢@tilois。