- Add nolint comments for type assertion errcheck in gjson/encode.go (switch case guarantees type safety) - Handle fasthttp.Serve errors in benchmark mock backends - Rename error variables to avoid shadowing in server.go - Use underscore for unused loop variables Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
179 lines
3.8 KiB
Go
179 lines
3.8 KiB
Go
// Package tools 提供基准测试和集成测试的辅助工具。
|
|
package tools
|
|
|
|
import (
|
|
"net"
|
|
"time"
|
|
|
|
"github.com/valyala/fasthttp"
|
|
)
|
|
|
|
// 预定义的测试数据大小常量
|
|
const (
|
|
Size100B = 100
|
|
Size1KB = 1024
|
|
Size10KB = 10 * 1024
|
|
Size100KB = 100 * 1024
|
|
Size1MB = 1024 * 1024
|
|
)
|
|
|
|
// MockBackendConfig Mock 后端配置
|
|
type MockBackendConfig struct {
|
|
// Mode 运行模式
|
|
Mode string
|
|
// StatusCode 响应状态码
|
|
StatusCode int
|
|
// ResponseBody 响应体
|
|
ResponseBody []byte
|
|
// ErrorRate 错误率 (0.0 - 1.0)
|
|
ErrorRate float64
|
|
// Delay 响应延迟
|
|
Delay time.Duration
|
|
}
|
|
|
|
// Mock 后端运行模式
|
|
const (
|
|
ModeNormalResponse = "normal"
|
|
ModeRandomResponse = "random"
|
|
ModeErrorResponse = "error"
|
|
ModeDelayedResponse = "delayed"
|
|
)
|
|
|
|
// GenerateTestData 生成指定大小的测试数据。
|
|
func GenerateTestData(size int) []byte {
|
|
data := make([]byte, size)
|
|
for i := range data {
|
|
data[i] = byte(i % 256)
|
|
}
|
|
return data
|
|
}
|
|
|
|
// SimpleMockBackend 创建一个简单的 Mock HTTP 后端。
|
|
// 返回监听地址和清理函数。
|
|
func SimpleMockBackend(statusCode int, responseBody []byte) (string, func()) {
|
|
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
handler := func(ctx *fasthttp.RequestCtx) {
|
|
ctx.SetStatusCode(statusCode)
|
|
ctx.SetBody(responseBody)
|
|
}
|
|
|
|
go func() {
|
|
if serveErr := fasthttp.Serve(ln, handler); serveErr != nil {
|
|
panic(serveErr)
|
|
}
|
|
}()
|
|
|
|
return ln.Addr().String(), func() {
|
|
_ = ln.Close()
|
|
}
|
|
}
|
|
|
|
// ErrorMockBackend 创建一个返回错误的 Mock HTTP 后端。
|
|
func ErrorMockBackend(errorRate float64, errorBody []byte) (string, func()) {
|
|
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
var requestCount int
|
|
handler := func(ctx *fasthttp.RequestCtx) {
|
|
requestCount++
|
|
if float64(requestCount%100)/100 < errorRate {
|
|
ctx.SetStatusCode(fasthttp.StatusInternalServerError)
|
|
ctx.SetBody(errorBody)
|
|
return
|
|
}
|
|
ctx.SetStatusCode(fasthttp.StatusOK)
|
|
ctx.SetBody([]byte("OK"))
|
|
}
|
|
|
|
go func() {
|
|
if serveErr := fasthttp.Serve(ln, handler); serveErr != nil {
|
|
panic(serveErr)
|
|
}
|
|
}()
|
|
|
|
return ln.Addr().String(), func() {
|
|
_ = ln.Close()
|
|
}
|
|
}
|
|
|
|
// DelayedMockBackend 创建一个带延迟的 Mock HTTP 后端。
|
|
func DelayedMockBackend(delay time.Duration, statusCode int, responseBody []byte) (string, func()) {
|
|
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
handler := func(ctx *fasthttp.RequestCtx) {
|
|
time.Sleep(delay)
|
|
ctx.SetStatusCode(statusCode)
|
|
ctx.SetBody(responseBody)
|
|
}
|
|
|
|
go func() {
|
|
if serveErr := fasthttp.Serve(ln, handler); serveErr != nil {
|
|
panic(serveErr)
|
|
}
|
|
}()
|
|
|
|
return ln.Addr().String(), func() {
|
|
_ = ln.Close()
|
|
}
|
|
}
|
|
|
|
// StartMockFasthttpBackend 根据配置启动 Mock HTTP 后端。
|
|
func StartMockFasthttpBackend(config MockBackendConfig) (string, func()) {
|
|
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
var requestCount int
|
|
handler := func(ctx *fasthttp.RequestCtx) {
|
|
requestCount++
|
|
|
|
switch config.Mode {
|
|
case ModeDelayedResponse:
|
|
time.Sleep(config.Delay)
|
|
ctx.SetStatusCode(config.StatusCode)
|
|
ctx.SetBody(config.ResponseBody)
|
|
|
|
case ModeErrorResponse:
|
|
if float64(requestCount%100)/100 < config.ErrorRate {
|
|
ctx.SetStatusCode(fasthttp.StatusInternalServerError)
|
|
ctx.SetBody([]byte(`{"error": "internal error"}`))
|
|
return
|
|
}
|
|
ctx.SetStatusCode(config.StatusCode)
|
|
ctx.SetBody(config.ResponseBody)
|
|
|
|
case ModeRandomResponse:
|
|
if requestCount%2 == 0 {
|
|
ctx.SetStatusCode(fasthttp.StatusOK)
|
|
} else {
|
|
ctx.SetStatusCode(fasthttp.StatusCreated)
|
|
}
|
|
ctx.SetBody(config.ResponseBody)
|
|
|
|
default:
|
|
ctx.SetStatusCode(config.StatusCode)
|
|
ctx.SetBody(config.ResponseBody)
|
|
}
|
|
}
|
|
|
|
go func() {
|
|
if serveErr := fasthttp.Serve(ln, handler); serveErr != nil {
|
|
panic(serveErr)
|
|
}
|
|
}()
|
|
|
|
return ln.Addr().String(), func() {
|
|
_ = ln.Close()
|
|
}
|
|
}
|