lolly/internal/testutil/mock_backend.go

180 lines
3.9 KiB
Go

// Package testutil provides mock backends and test helpers.
package testutil
import (
"net"
"time"
"github.com/valyala/fasthttp"
)
// 预定义的测试数据大小常量
const (
// Size100B 100 字节测试数据。
Size100B = 100
// Size1KB 1KB 测试数据。
Size1KB = 1024
// Size10KB 10KB 测试数据。
Size10KB = 10 * 1024
// Size100KB 100KB 测试数据。
Size100KB = 100 * 1024
// Size1MB 1MB 测试数据。
Size1MB = 1024 * 1024
)
// MockBackendConfig Mock 后端配置。
type MockBackendConfig struct {
Mode string
StatusCode int
ResponseBody []byte
ErrorRate float64
Delay time.Duration
}
// Mock 后端运行模式
const (
// ModeNormalResponse 正常响应模式。
ModeNormalResponse = "normal"
// ModeRandomResponse 随机响应模式。
ModeRandomResponse = "random"
// ModeErrorResponse 错误响应模式。
ModeErrorResponse = "error"
// ModeDelayedResponse 延迟响应模式。
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(cfg 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++
if cfg.Delay > 0 {
time.Sleep(cfg.Delay)
}
switch cfg.Mode {
case ModeErrorResponse:
if float64(requestCount%100)/100 < cfg.ErrorRate {
ctx.SetStatusCode(fasthttp.StatusInternalServerError)
ctx.SetBody(cfg.ResponseBody)
return
}
case ModeDelayedResponse:
time.Sleep(cfg.Delay)
case ModeRandomResponse:
if requestCount%2 == 0 {
ctx.SetStatusCode(fasthttp.StatusOK)
} else {
ctx.SetStatusCode(fasthttp.StatusInternalServerError)
}
ctx.SetBody(cfg.ResponseBody)
return
}
ctx.SetStatusCode(cfg.StatusCode)
ctx.SetBody(cfg.ResponseBody)
}
go func() {
if serveErr := fasthttp.Serve(ln, handler); serveErr != nil {
panic(serveErr)
}
}()
return ln.Addr().String(), func() {
_ = ln.Close()
}
}