xfy 8643a0aff9 refactor: improve error handling and fix linter warnings
- 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>
2026-05-09 17:32:06 +08:00

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