lolly/internal/benchmark/tools/benchmark_context.go
xfy f145a8770e refactor: modernize code with Go 1.22+ features
Apply modern Go patterns across the codebase:
- Replace `interface{}` with `any` (Go 1.18+)
- Use `for range n` instead of `for i := 0; i < n; i++` (Go 1.22+)
- Replace `sort.Slice` with `slices.Sort` from slices package
- Simplify sync.WaitGroup patterns with errgroup where appropriate
- Add Makefile targets for modernize analyzer

Total: 84 files updated, net reduction of 79 lines

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 10:37:45 +08:00

360 lines
8.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Package tools 提供基准测试工具函数。
//
// 该文件提供标准化的基准测试上下文构造器,用于:
// - 快速创建模拟的 fasthttp.RequestCtx
// - 标准化测试数据大小
// - 简化组件级基准测试编写
//
// 作者xfy
package tools
import (
"bytes"
"math/rand"
"net"
"strconv"
"time"
"github.com/valyala/fasthttp"
)
// BenchmarkContext 提供标准化的基准测试上下文。
//
// 包含构造模拟请求所需的所有配置。
type BenchmarkContext struct {
// randSrc 随机数生成器
randSrc *rand.Rand
// RequestSize 请求数据大小
RequestSize TestDataSize
// ResponseSize 响应数据大小
ResponseSize TestDataSize
// Concurrency 并发级别(用于并行测试)
Concurrency int
}
// NewBenchmarkContext 创建基准测试上下文。
//
// 参数:
// - reqSize: 请求数据大小
// - respSize: 响应数据大小
// - concurrency: 并发级别
//
// 返回值:
// - *BenchmarkContext: 配置好的基准测试上下文
func NewBenchmarkContext(reqSize, respSize TestDataSize, concurrency int) *BenchmarkContext {
return &BenchmarkContext{
RequestSize: reqSize,
ResponseSize: respSize,
Concurrency: concurrency,
randSrc: rand.New(rand.NewSource(time.Now().UnixNano())),
}
}
// MockRequestCtx 构造模拟的 fasthttp.RequestCtx。
//
// 创建一个可用于基准测试的请求上下文,包含:
// - 请求方法和路径
// - 请求头
// - 请求体
// - 远程地址
//
// 参数:
// - method: HTTP 方法 (GET, POST, etc.)
// - path: 请求路径
//
// 返回值:
// - *fasthttp.RequestCtx: 模拟的请求上下文
func (bc *BenchmarkContext) MockRequestCtx(method, path string) *fasthttp.RequestCtx {
ctx := &fasthttp.RequestCtx{}
// 设置请求行
ctx.Request.Header.SetMethod(method)
ctx.Request.SetRequestURI(path)
// 设置远程地址
ctx.Init(&fasthttp.Request{}, &net.TCPAddr{
IP: net.ParseIP("192.168.1.100"),
Port: 12345,
}, nil)
// 设置请求体
if bc.RequestSize > 0 {
body := GenerateTestData(bc.RequestSize)
ctx.Request.SetBody(body)
}
return ctx
}
// MockRequestCtxWithHeaders 构造带自定义请求头的模拟上下文。
//
// 参数:
// - method: HTTP 方法
// - path: 请求路径
// - headers: 请求头键值对
//
// 返回值:
// - *fasthttp.RequestCtx: 模拟的请求上下文
func (bc *BenchmarkContext) MockRequestCtxWithHeaders(method, path string, headers map[string]string) *fasthttp.RequestCtx {
ctx := bc.MockRequestCtx(method, path)
// 设置请求头
for key, value := range headers {
ctx.Request.Header.Set(key, value)
}
return ctx
}
// MockRequestCtxWithBody 构造带自定义请求体的模拟上下文。
//
// 参数:
// - method: HTTP 方法
// - path: 请求路径
// - body: 请求体内容
//
// 返回值:
// - *fasthttp.RequestCtx: 模拟的请求上下文
func (bc *BenchmarkContext) MockRequestCtxWithBody(method, path string, body []byte) *fasthttp.RequestCtx {
ctx := bc.MockRequestCtx(method, path)
ctx.Request.SetBody(body)
return ctx
}
// MockRequestCtxWithIP 构造带指定 IP 的模拟上下文。
//
// 参数:
// - method: HTTP 方法
// - path: 请求路径
// - ip: 客户端 IP 地址
//
// 返回值:
// - *fasthttp.RequestCtx: 模拟的请求上下文
func (bc *BenchmarkContext) MockRequestCtxWithIP(method, path, ip string) *fasthttp.RequestCtx {
ctx := &fasthttp.RequestCtx{}
ctx.Request.Header.SetMethod(method)
ctx.Request.SetRequestURI(path)
ctx.Init(&fasthttp.Request{}, &net.TCPAddr{
IP: net.ParseIP(ip),
Port: 12345,
}, nil)
return ctx
}
// MockResponse 构造模拟响应数据。
//
// 根据 ResponseSize 生成响应体。
//
// 返回值:
// - []byte: 模拟的响应数据
func (bc *BenchmarkContext) MockResponse() []byte {
return GenerateTestData(bc.ResponseSize)
}
// MockResponseWithContentType 构造带 Content-Type 的模拟响应。
//
// 参数:
// - statusCode: HTTP 状态码
// - contentType: 内容类型
//
// 返回值:
// - []byte: 模拟的响应数据
func (bc *BenchmarkContext) MockResponseWithContentType(_, _ string) []byte {
// 返回响应体,调用者负责设置状态码和 Content-Type
return GenerateTestData(bc.ResponseSize)
}
// RandomIP 生成随机 IP 地址。
//
// 用于测试多客户端场景。
//
// 返回值:
// - string: 随机 IP 地址
func (bc *BenchmarkContext) RandomIP() string {
return "192.168." + strconv.Itoa(bc.randSrc.Intn(256)) + "." + strconv.Itoa(bc.randSrc.Intn(256))
}
// RandomPath 生成随机请求路径。
//
// 参数:
// - prefix: 路径前缀
//
// 返回值:
// - string: 随机路径
func (bc *BenchmarkContext) RandomPath(prefix string) string {
return prefix + "/" + strconv.Itoa(bc.randSrc.Intn(10000))
}
// MockJSONRequest 构造 JSON 格式的模拟请求。
//
// 参数:
// - path: 请求路径
// - data: JSON 数据
//
// 返回值:
// - *fasthttp.RequestCtx: 模拟的请求上下文
func (bc *BenchmarkContext) MockJSONRequest(path string, data []byte) *fasthttp.RequestCtx {
ctx := bc.MockRequestCtx("POST", path)
ctx.Request.Header.SetContentType("application/json")
ctx.Request.SetBody(data)
return ctx
}
// MockFormRequest 构造表单格式的模拟请求。
//
// 参数:
// - path: 请求路径
// - form: 表单数据键值对
//
// 返回值:
// - *fasthttp.RequestCtx: 模拟的请求上下文
func (bc *BenchmarkContext) MockFormRequest(path string, form map[string]string) *fasthttp.RequestCtx {
ctx := bc.MockRequestCtx("POST", path)
ctx.Request.Header.SetContentType("application/x-www-form-urlencoded")
// 构造表单数据
var buf bytes.Buffer
first := true
for key, value := range form {
if !first {
buf.WriteByte('&')
}
buf.WriteString(key)
buf.WriteByte('=')
buf.WriteString(value)
first = false
}
ctx.Request.SetBody(buf.Bytes())
return ctx
}
// SetResponse 设置模拟上下文的响应。
//
// 用于测试响应处理逻辑。
//
// 参数:
// - ctx: 请求上下文
// - statusCode: HTTP 状态码
// - body: 响应体
func (bc *BenchmarkContext) SetResponse(ctx *fasthttp.RequestCtx, statusCode int, body []byte) {
ctx.Response.SetStatusCode(statusCode)
ctx.Response.SetBody(body)
}
// SetJSONResponse 设置 JSON 格式的模拟响应。
//
// 参数:
// - ctx: 请求上下文
// - statusCode: HTTP 状态码
// - json: JSON 数据
func (bc *BenchmarkContext) SetJSONResponse(ctx *fasthttp.RequestCtx, statusCode int, json []byte) {
ctx.Response.SetStatusCode(statusCode)
ctx.Response.Header.SetContentType("application/json")
ctx.Response.SetBody(json)
}
// DefaultBenchmarkContext 返回默认的基准测试上下文。
//
// 配置:
// - RequestSize: 1KB
// - ResponseSize: 1KB
// - Concurrency: 1
//
// 返回值:
// - *BenchmarkContext: 默认配置的上下文
func DefaultBenchmarkContext() *BenchmarkContext {
return NewBenchmarkContext(Size1KB, Size1KB, 1)
}
// SmallRequestContext 返回小请求的基准测试上下文。
//
// 配置:
// - RequestSize: 100B
// - ResponseSize: 100B
//
// 返回值:
// - *BenchmarkContext: 小请求配置的上下文
func SmallRequestContext() *BenchmarkContext {
return NewBenchmarkContext(100, 100, 1)
}
// LargeRequestContext 返回大请求的基准测试上下文。
//
// 配置:
// - RequestSize: 100KB
// - ResponseSize: 100KB
//
// 返回值:
// - *BenchmarkContext: 大请求配置的上下文
func LargeRequestContext() *BenchmarkContext {
return NewBenchmarkContext(Size100KB, Size100KB, 1)
}
// HighConcurrencyContext 返回高并发基准测试上下文。
//
// 配置:
// - Concurrency: 100
//
// 返回值:
// - *BenchmarkContext: 高并发配置的上下文
func HighConcurrencyContext() *BenchmarkContext {
return NewBenchmarkContext(Size1KB, Size1KB, 100)
}
// BenchmarkContextPool 提供基准测试上下文的池。
//
// 用于减少内存分配开销。
type BenchmarkContextPool struct {
pool chan *BenchmarkContext
}
// NewBenchmarkContextPool 创建基准测试上下文池。
//
// 参数:
// - size: 池大小
//
// 返回值:
// - *BenchmarkContextPool: 上下文池
func NewBenchmarkContextPool(size int) *BenchmarkContextPool {
p := &BenchmarkContextPool{
pool: make(chan *BenchmarkContext, size),
}
// 预填充池
for range size {
p.pool <- DefaultBenchmarkContext()
}
return p
}
// Get 从池中获取基准测试上下文。
//
// 返回值:
// - *BenchmarkContext: 基准测试上下文
func (p *BenchmarkContextPool) Get() *BenchmarkContext {
select {
case ctx := <-p.pool:
return ctx
default:
return DefaultBenchmarkContext()
}
}
// Put 将基准测试上下文放回池中。
//
// 参数:
// - ctx: 基准测试上下文
func (p *BenchmarkContextPool) Put(ctx *BenchmarkContext) {
select {
case p.pool <- ctx:
default:
// 池已满,丢弃
}
}