- 所有 *_bench_test.go 文件从 for i := 0; i < b.N; i++ 改为 for b.Loop() - 部分测试文件从 for i := 0; i < N; ... 改为 for range N 或 for i := range N - 涵盖模块: cache, handler, http2, http3, loadbalance, logging, lua, middleware/accesslog, middleware/bodylimit, middleware/rewrite, middleware/security, netutil, resolver, server, ssl, stream Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
255 lines
6.3 KiB
Go
255 lines
6.3 KiB
Go
// Package rewrite URL 重写中间件基准测试
|
||
package rewrite
|
||
|
||
import (
|
||
"testing"
|
||
|
||
"github.com/valyala/fasthttp"
|
||
"rua.plus/lolly/internal/config"
|
||
)
|
||
|
||
// BenchmarkRewriteProcess 基准测试:正则匹配 + 替换
|
||
// 测试单个重写规则的性能
|
||
func BenchmarkRewriteProcess(b *testing.B) {
|
||
m, err := New([]config.RewriteRule{
|
||
{Pattern: "^/api/v1/(.*)$", Replacement: "/api/v2/$1", Flag: "last"},
|
||
})
|
||
if err != nil {
|
||
b.Fatalf("New() error: %v", err)
|
||
}
|
||
|
||
nextHandler := func(ctx *fasthttp.RequestCtx) {
|
||
ctx.WriteString("OK")
|
||
}
|
||
handler := m.Process(nextHandler)
|
||
|
||
b.ResetTimer()
|
||
b.ReportAllocs()
|
||
|
||
for b.Loop() {
|
||
ctx := &fasthttp.RequestCtx{}
|
||
ctx.Request.SetRequestURI("/api/v1/users")
|
||
handler(ctx)
|
||
}
|
||
}
|
||
|
||
// BenchmarkRewriteMultipleRules 基准测试:多规则匹配(最多 10 个)
|
||
// 测试规则列表的遍历和匹配性能
|
||
func BenchmarkRewriteMultipleRules(b *testing.B) {
|
||
// 创建 10 个规则,只有最后一个匹配
|
||
rules := []config.RewriteRule{
|
||
{Pattern: "^/a/(.*)$", Replacement: "/x/$1", Flag: "last"},
|
||
{Pattern: "^/b/(.*)$", Replacement: "/x/$1", Flag: "last"},
|
||
{Pattern: "^/c/(.*)$", Replacement: "/x/$1", Flag: "last"},
|
||
{Pattern: "^/d/(.*)$", Replacement: "/x/$1", Flag: "last"},
|
||
{Pattern: "^/e/(.*)$", Replacement: "/x/$1", Flag: "last"},
|
||
{Pattern: "^/f/(.*)$", Replacement: "/x/$1", Flag: "last"},
|
||
{Pattern: "^/g/(.*)$", Replacement: "/x/$1", Flag: "last"},
|
||
{Pattern: "^/h/(.*)$", Replacement: "/x/$1", Flag: "last"},
|
||
{Pattern: "^/i/(.*)$", Replacement: "/x/$1", Flag: "last"},
|
||
{Pattern: "^/j/(.*)$", Replacement: "/x/$1", Flag: "last"},
|
||
}
|
||
|
||
m, err := New(rules)
|
||
if err != nil {
|
||
b.Fatalf("New() error: %v", err)
|
||
}
|
||
|
||
nextHandler := func(ctx *fasthttp.RequestCtx) {
|
||
ctx.WriteString("OK")
|
||
}
|
||
handler := m.Process(nextHandler)
|
||
|
||
b.ResetTimer()
|
||
b.ReportAllocs()
|
||
|
||
for b.Loop() {
|
||
ctx := &fasthttp.RequestCtx{}
|
||
ctx.Request.SetRequestURI("/j/resource")
|
||
handler(ctx)
|
||
}
|
||
}
|
||
|
||
// BenchmarkRewriteWithVariableExpand 基准测试:带变量展开
|
||
// 测试变量展开对性能的影响
|
||
func BenchmarkRewriteWithVariableExpand(b *testing.B) {
|
||
// 在替换字符串中使用变量
|
||
m, err := New([]config.RewriteRule{
|
||
{Pattern: "^/api/(.*)$", Replacement: "/proxy/${host}/$1", Flag: "last"},
|
||
})
|
||
if err != nil {
|
||
b.Fatalf("New() error: %v", err)
|
||
}
|
||
|
||
nextHandler := func(ctx *fasthttp.RequestCtx) {
|
||
ctx.WriteString("OK")
|
||
}
|
||
handler := m.Process(nextHandler)
|
||
|
||
b.ResetTimer()
|
||
b.ReportAllocs()
|
||
|
||
for b.Loop() {
|
||
ctx := &fasthttp.RequestCtx{}
|
||
ctx.Request.SetRequestURI("/api/data")
|
||
// 设置 Host 头以供变量展开使用
|
||
ctx.Request.Header.Set("Host", "example.com")
|
||
handler(ctx)
|
||
}
|
||
}
|
||
|
||
// BenchmarkRewriteFlagLast 基准测试:FlagLast 循环检测
|
||
// 测试 FlagLast 重新扫描的性能
|
||
func BenchmarkRewriteFlagLast(b *testing.B) {
|
||
// 创建两条规则形成链式重写
|
||
// /v1/* -> /v2/* -> /v3/*
|
||
m, err := New([]config.RewriteRule{
|
||
{Pattern: "^/v1/(.*)$", Replacement: "/v2/$1", Flag: "last"},
|
||
{Pattern: "^/v2/(.*)$", Replacement: "/v3/$1", Flag: "last"},
|
||
})
|
||
if err != nil {
|
||
b.Fatalf("New() error: %v", err)
|
||
}
|
||
|
||
nextHandler := func(ctx *fasthttp.RequestCtx) {
|
||
ctx.WriteString("OK")
|
||
}
|
||
handler := m.Process(nextHandler)
|
||
|
||
b.ResetTimer()
|
||
b.ReportAllocs()
|
||
|
||
for b.Loop() {
|
||
ctx := &fasthttp.RequestCtx{}
|
||
ctx.Request.SetRequestURI("/v1/resource")
|
||
handler(ctx)
|
||
}
|
||
}
|
||
|
||
// BenchmarkRewriteNoMatch 基准测试:无匹配情况
|
||
// 测试当没有规则匹配时的性能
|
||
func BenchmarkRewriteNoMatch(b *testing.B) {
|
||
m, err := New([]config.RewriteRule{
|
||
{Pattern: "^/api/(.*)$", Replacement: "/proxy/$1", Flag: "last"},
|
||
})
|
||
if err != nil {
|
||
b.Fatalf("New() error: %v", err)
|
||
}
|
||
|
||
nextHandler := func(ctx *fasthttp.RequestCtx) {
|
||
ctx.WriteString("OK")
|
||
}
|
||
handler := m.Process(nextHandler)
|
||
|
||
b.ResetTimer()
|
||
b.ReportAllocs()
|
||
|
||
for b.Loop() {
|
||
ctx := &fasthttp.RequestCtx{}
|
||
ctx.Request.SetRequestURI("/static/file.txt")
|
||
handler(ctx)
|
||
}
|
||
}
|
||
|
||
// BenchmarkRewriteComplexPattern 基准测试:复杂正则表达式
|
||
// 测试复杂正则匹配的性能
|
||
func BenchmarkRewriteComplexPattern(b *testing.B) {
|
||
// 使用更复杂的正则表达式
|
||
m, err := New([]config.RewriteRule{
|
||
{Pattern: "^/api/v\\d+/(users|posts|comments)/(\\d+)/(profile|settings)$", Replacement: "/internal/$1/$2/$3", Flag: "last"},
|
||
})
|
||
if err != nil {
|
||
b.Fatalf("New() error: %v", err)
|
||
}
|
||
|
||
nextHandler := func(ctx *fasthttp.RequestCtx) {
|
||
ctx.WriteString("OK")
|
||
}
|
||
handler := m.Process(nextHandler)
|
||
|
||
b.ResetTimer()
|
||
b.ReportAllocs()
|
||
|
||
for b.Loop() {
|
||
ctx := &fasthttp.RequestCtx{}
|
||
ctx.Request.SetRequestURI("/api/v1/users/123/profile")
|
||
handler(ctx)
|
||
}
|
||
}
|
||
|
||
// BenchmarkRewriteRedirect 基准测试:重定向标志
|
||
// 测试重定向响应的性能
|
||
func BenchmarkRewriteRedirect(b *testing.B) {
|
||
m, err := New([]config.RewriteRule{
|
||
{Pattern: "^/old/(.*)$", Replacement: "/new/$1", Flag: "redirect"},
|
||
})
|
||
if err != nil {
|
||
b.Fatalf("New() error: %v", err)
|
||
}
|
||
|
||
nextHandler := func(ctx *fasthttp.RequestCtx) {
|
||
ctx.WriteString("OK")
|
||
}
|
||
handler := m.Process(nextHandler)
|
||
|
||
b.ResetTimer()
|
||
b.ReportAllocs()
|
||
|
||
for b.Loop() {
|
||
ctx := &fasthttp.RequestCtx{}
|
||
ctx.Request.SetRequestURI("/old/page")
|
||
handler(ctx)
|
||
}
|
||
}
|
||
|
||
// BenchmarkRewriteBreak 基准测试:Break 标志
|
||
// 测试 Break 标志提前终止的性能
|
||
func BenchmarkRewriteBreak(b *testing.B) {
|
||
m, err := New([]config.RewriteRule{
|
||
{Pattern: "^/api/(.*)$", Replacement: "/internal/$1", Flag: "break"},
|
||
{Pattern: "^/internal/(.*)$", Replacement: "/final/$1", Flag: "last"},
|
||
})
|
||
if err != nil {
|
||
b.Fatalf("New() error: %v", err)
|
||
}
|
||
|
||
nextHandler := func(ctx *fasthttp.RequestCtx) {
|
||
ctx.WriteString("OK")
|
||
}
|
||
handler := m.Process(nextHandler)
|
||
|
||
b.ResetTimer()
|
||
b.ReportAllocs()
|
||
|
||
for b.Loop() {
|
||
ctx := &fasthttp.RequestCtx{}
|
||
ctx.Request.SetRequestURI("/api/data")
|
||
handler(ctx)
|
||
}
|
||
}
|
||
|
||
// BenchmarkRewriteMultipleCaptures 基准测试:多捕获组
|
||
// 测试多个捕获组的替换性能
|
||
func BenchmarkRewriteMultipleCaptures(b *testing.B) {
|
||
m, err := New([]config.RewriteRule{
|
||
{Pattern: "^/(\\d{4})/(\\d{2})/(\\d{2})/(.*)$", Replacement: "/archive/$1-$2-$3/$4", Flag: "last"},
|
||
})
|
||
if err != nil {
|
||
b.Fatalf("New() error: %v", err)
|
||
}
|
||
|
||
nextHandler := func(ctx *fasthttp.RequestCtx) {
|
||
ctx.WriteString("OK")
|
||
}
|
||
handler := m.Process(nextHandler)
|
||
|
||
b.ResetTimer()
|
||
b.ReportAllocs()
|
||
|
||
for b.Loop() {
|
||
ctx := &fasthttp.RequestCtx{}
|
||
ctx.Request.SetRequestURI("/2024/03/15/article")
|
||
handler(ctx)
|
||
}
|
||
}
|