lolly/internal/middleware/rewrite/rewrite_bench_test.go
xfy 8ed800271d test: 迁移基准测试循环到 Go 1.24 b.Loop() API
- 所有 *_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>
2026-04-16 13:50:15 +08:00

255 lines
6.3 KiB
Go
Raw Permalink 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 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)
}
}