我有一个web应用,我可以传入一些参数,来控制响应时间及响应code,当然还有其它的一些控制
代码片段例如:
funcmethod(c*gin.Context) { data, _ :=ioutil.ReadAll(c.Request.Body) t, b :=c.GetQuery("time") ifb { duration, e :=time.ParseDuration(t) ife!=nil { fmt.Println(e) } time.Sleep(duration) } status_code, b :=c.GetQuery("status_code") code :=200ifb { code, _=strconv.Atoi(status_code) } //如果传入参数r,就随机返回code,随机等待时间_, b=c.GetQuery("r") ifb { codes := []int{200, 201, 300, 401, 400, 401, 403, 405, 406, 500, 502, 503, 504} rand.Seed(time.Now().UnixNano()) n :=rand.Intn(len(codes)) ifn%2==0 { code=200 } else { code=codes[n] } time.Sleep(time.Duration(n) *time.Second) } //获取参数内容,设置响应头hd :=make(map[string]string) header, b :=c.GetQuery("headers") json.Unmarshal([]byte(header), &hd) fork, v :=rangehd { c.Header(k, v) } //重定向,应该只有GET方法才起作用redirects, b :=c.GetQuery("redirects") ifb { c.Redirect(301, redirects) } //获取参数内容,设置响应内容body, b :=c.GetQuery("body") ifb { c.String(code, body) return } c.JSON(code, gin.H{ "path": c.Request.URL.Path, "method": c.Request.Method, "params": c.Params, "headers": c.Request.Header, "query": c.Request.URL.RawQuery, "cookies": c.Request.Cookies(), "body": string(data), }) }
首先说明一下,我为什么要有这么一个应用。
公司有一个ddtrace
链路数据收集的服务,我这个应用通过请求调用,会产生链路数据
链路数据收集服务收集数据后,会上报到中心并写入到es中,其中有业务针对服务做一些统计。
例如:平均每秒请求数,请求错误数,请求错误率,请求平均响应时间,最大响应时间,p75,p99等
那么我可以模拟一些请求:
模拟多个时间段的请求,这样我可以测试好几个时间(平均响应,最大,最小,p75等)
模拟多个响应code的请求,这样可以计算错误数,错误率。
模拟多个方法的请求(get,post,put,delete)等
模拟请求的路由(/a,/b,/test/*anypath)等
可以写一个脚本,随机生成一些响应时间,随机生成一些响应code
请求的时候依次带上响应时间,响应code。
那么这些时间,及响应code 本地是记录的,通过numpy
库来计算最大值,最小值,百分位等
通过判断code是不是400及以上,判断请求是否是错误,记录错误数
通过错误数/总数 那么可以计算错误率
通过单位时间内的请求数,可以算出平均每秒请求数,例如查询数据范围为15分钟,也就是900秒,如果我请求了10次,那么就是10/900=0.01 。当然请求数可以多一点
这一切都是可以通过脚本来自动测试完成的。所以我需要有这样的应用来辅助我完成测试
我遇到什么问题呢。
我写完这个应用后,通过curl来测试,发现预期不正确
status_code=301
生效了,但是time=2s
没生效
curl-v http://172.16.5.9:18090/a?status_code=301&time=2s
time=2s
生效了,但是status_code=301
没生效
curl-v http://172.16.5.9:18090/a?time=2s&status_code=301
我开始怀疑代码有问题,后来查了下,代码没问题啊。
后来再通过curl -v
查看了下详细请求
仔细看第6行,请求为GET /a?time=2s
我还有一个参数竟然丢了,我以为curl有问题,竟然去man curl
看文档了
# curl -v http://172.16.5.9:18090/a?time=2s&status_code=301[1] 32296[root@izbp152ke14timzud0du15z anypath]# * About to connect() to 172.16.5.9 port 18090 (#0)* Trying 172.16.5.9... * Connected to 172.16.5.9 (172.16.5.9) port 18090 (#0)> GET /a?time=2s HTTP/1.1 > User-Agent: curl/7.29.0 > Host: 172.16.5.9:18090 > Accept: */* > < HTTP/1.1 200 OK < Content-Type: application/json; charset=utf-8 < Date: Thu, 06 Jan 202206:43:41 GMT < Content-Length: 139< * Connection #0 to host 172.16.5.9 left intact{"body":"","cookies":[],"headers":{"Accept":["*/*"],"User-Agent":["curl/7.29.0"]},"method":"GET","params":[],"path":"/a","query":"time=2s"}
文档没耐心看完,突然想到加个双引号试试,参数都生效了
# curl -v "http://172.16.5.9:18090/a?time=2s&status_code=301"* About to connect() to 172.16.5.9 port 18090 (#0)* Trying 172.16.5.9... * Connected to 172.16.5.9 (172.16.5.9) port 18090 (#0)> GET /a?time=2s&status_code=301 HTTP/1.1 > User-Agent: curl/7.29.0 > Host: 172.16.5.9:18090 > Accept: */* > < HTTP/1.1 301 Moved Permanently < Content-Type: application/json; charset=utf-8 < Date: Thu, 06 Jan 202206:43:09 GMT < Content-Length: 160< * Connection #0 to host 172.16.5.9 left intact{"body":"","cookies":[],"headers":{"Accept":["*/*"],"User-Agent":["curl/7.29.0"]},"method":"GET","params":[],"path":"/a","query":"time=2s\u0026status_code=301"}
这个时候恍然大悟,发现是&
符号的问题,在Linux中 &
是命令连接符号,执行多个命令使用的,并不是你想的那样,作为URL的一个参数而已,所以需要加个双引号
你可以看到这是两个命令
[root@izbp152ke14timzud0du15z anypath]# ls&pwd[1] 20105/root/anypath [root@izbp152ke14timzud0du15z anypath]# anyPath cfg.yaml demo[1]+ Done ls--color=auto