关于开源软件:Go-实现-json-格式定义-http-协议压测脚本

84次阅读

共计 3152 个字符,预计需要花费 8 分钟才能阅读完成。

原文由 bugVanisher 发表于 TesterHome 社区,点击原文链接可与作者间接交换。

前段时间,我主导推动组里实现了一套基于 Locust+boomer 的通用的压测平台,次要目标是满足咱们组内的各种压测场景,比方 grpc、websocket、webrtc、http 等协定的压测场景。正好咱们公司的技术栈以 go 为主,咱们能够轻松地应用 go 编写脚本,通过公司的部署平台编译打包后横向扩缩施压集群,能够说解决了各种压测需要。然而咱们发现,只管本人编写脚本十分自在,然而对不理解平台、不理解 Go 的同学来说,应用老本是比拟大的,尤其是首次接触,因而我开始思考如何简化脚本的编写和部署。

从 http 开始

来源于 httprunner 和公司其余 Group 的工具的灵感,我想到用 json 的形式去定义 http 压测场景,而后用 go 去解析执行,能够预感的是这种形式的压测性能不如间接写代码,然而如果能够通过可承受的性能损耗来换取更简略的接入形式,更对立的应用形式,也是极好的,毕竟咱们不缺机器。针对 http 协定,以下大略梳理了一下须要实现的能力。

简略阐明下:

  • 多接口

    很好了解,压测的时候须要满足多个接口按肯定的比例同时压测。在某些非凡场景下,可能还存在接口依赖的问题,这也要思考到。

  • 登录态

    压测的接口可能有登录校验,那么压测的时候须要带上登录态,如果能买通账号平台主动批量生成登录态就不便很多了。

  • 参数化

    定义的脚本须要提供参数化能力,总不能所有参数写死,比方动静生成工夫戳,ID,变长字符串等等,如果简略的参数生成无奈满足,用户本人上传也是挺好的。

  • 校验

    响应内容校验是接口测试很重要的局部,在压测场景也是一样的。

定义 Json 构造

接下来,定义 Json 构造,尽量去满足下面所形容的需要。http 协定,无非就是三个局部,body、header、url,因而每一个接口须要蕴含这个三个字段,当然,名字是必不可少的,还有一个十分重要的字段,就是校验字段 validator,上面就来看看这个 Json 应该是什么样子。

{
    "debug": true,
    "domain": "https://postman-echo.com",
    "header": {},  
    "declare": ["{{ $sessionId := getSid}}"
    ],
    "init_variables": {
        "roomId": 1001,
        "sessionId": "{{$sessionId}}",
        "ids": "{{$sessionId}}"
    },
    "running_variables": {"tid": "{{ getRandomId 5000}}"
    },
    "func_set": [
        {
            "key": "getTest",
            "method": "GET",
            "url": "/get?name=gannicus&roomId={{.roomId}}&age=10&tid={{.tid}}",
            "body": "{\"timeout\":10000}",
            "validator": "{{and  (eq .http_status_code 200) (eq .args.age (10 | toString)) }}"
        },
        {
            "key": "postTest",
            "method": "POST",
            "header": {"Cookie": "{{ .tid}}",
                "Content-Type": "application/json"
            },
            "url": "/post?name=gannicus",
            "body": "{\"timeout\":{{ .tid}}, \"retry\":true}",
            "validator": "{{and  (eq .http_status_code 200) (eq .data.timeout (.tid | toFloat64) ) (eq .data.retry false) }}"
        }
    ]
}

func_set 应该挺好了解的,这里解释一下 declare、init_variables、running_variables:

  • declare
    这个字段是为了申明变量的,比方在 init 或 running 变量中都能够援用这个变量,申明形式如:

    ["{{ $sessionId := getSid}}",
        "{{$id := 100100}}"
    ]
  • init_variables

    初始化变量,只初始化一次,能够是常量,也能够从模板函数中获取,如:

    {
            "roomId": 1001,
            "sessionId": "{{$sessionId}}",
            "ids": "{{now}}"
    }
  • running_variables

    运行时变量,每一个申请发动前都会去结构参数,因而不倡议常量定义在这里。

    {"tid": "{{ getRandomId 5000}}"
    }

解析流程

想要利用 boomer,那就须要想方法生成 boomer.Task,它的构造如下:

type Task struct {
    // The weight is used to distribute goroutines over multiple tasks.
    Weight int
    // Fn is called by the goroutines allocated to this task, in a loop.
    Fn   func()
    Name string
}

外围就是失去这个执行函数 Fn,思路就是别离依据 init 和 running 变量定义,为 func_set 中申明的每个申请别离定义一个匿名函数,函数中去动静生成变量,而后发动实在申请,最初依据每个申请申明的 validator 进行断言。整个执行流程如下:

实现原理

go 的原生库中就有模板相干的库 text/template, 我间接应用模板库实现了这套解析逻辑,包含参数的生成,模板办法、断言,整个 json 脚本的语法都是基于 go 的模板库的。感兴趣的敌人能够查看:

  • 官网模板库
  • Go 语言规范库 text/template 包深入浅出

如何断言

因为断言这部分十分重要,所以独自讲。下面曾经说过断言是通过模板来实现的,所以要应用断言就要把握根本的模板语法。

模板库内置了比拟和逻辑办法所以能够间接应用,比方比拟 http 状态码:

"validator": "{{eq .http_status_code 200}}"

再比方多个比拟:

"validator": "{{and  (eq .http_status_code 200) (eq .data.timeout (.tid | toFloat64) ) (eq .data.retry false) }}"

可能你也曾经留神到了有一个 toFloat64, 它是一个模板自定义函数,这里是为了做类型转换。

此外,你也能够看到基于 go 模板库,拜访变量变得非常简单,比方下面的.data.timeout, 它对应响应中的内容相似如下:

{
    "data":{"timeout": 1000}
}

这样咱们就能够比拟响应 json 中的任何字段了。

写在最初

简略做了一下压力测试,比照不应用模板解析和应用模板解析的状况,模板解析在 CPU 密集型的场景下性能大略是间接写脚本编译的三分之一,如果不是 CPU 密集型应该能够去到二分之一,因而我临时不优化了。令人惊喜的是这个模板解析也能够扩大成为接口测试的编写形式,相似 httprunner。

目前只是做了一个 Demo,还没正真集成到咱们的压测平台,还是挺令人期待呀。

源码地址:https://github.com/bugVanisher/go-httpwrapper

原文由 bugVanisher 发表于 TesterHome 社区,点击原文链接可与作者间接交换。


今日份的常识已摄入~
想理解更多前沿测试开发技术:欢送关注「第十届 MTSC 大会·上海」>>>
1 个主会场 +12 大专场,大咖星散精英齐聚
12 个专场包含:
知乎、OpenHarmony、开源、游戏、酷家乐、音视频、客户端、服务端、数字经济、效力晋升、品质保障、智能化测试

正文完
 0