Files
micro-client-http/builder/request_builder_bench_test.go
pugnack 24801750a7
Some checks failed
coverage / build (push) Successful in 2m19s
test / test (push) Failing after 17m15s
integrate request builder into HTTP client for googleapis support (#157)
2025-09-23 13:30:15 +03:00

150 lines
4.4 KiB
Go

package builder
import (
"fmt"
"math/rand"
"strings"
"testing"
"time"
"google.golang.org/protobuf/proto"
pb "go.unistack.org/micro-client-http/v4/builder/proto"
)
// sink prevents the compiler from optimizing away parsePathTemplate results.
var sink *pathTemplate
func BenchmarkParsePathTemplate(b *testing.B) {
r := rand.New(rand.NewSource(1))
benchInput := func(size int) string {
sb := strings.Builder{}
sb.Grow(size * 10)
for i := 0; i < size; i++ {
name := fmt.Sprintf("var%d", r.Intn(1000))
if r.Intn(5) == 0 {
sb.WriteString(fmt.Sprintf("{%s=**}", name))
} else {
sb.WriteString(fmt.Sprintf("{%s}", name))
}
}
return sb.String()
}
sizes := []int{1_000, 10_000, 50_000, 100_000}
for _, size := range sizes {
input := benchInput(size)
b.Run(fmt.Sprintf("N=%d", size), func(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
var err error
sink, err = parsePathTemplate(input)
if err != nil && testing.Verbose() {
b.Fatal(err)
}
}
})
}
}
func BenchmarkRequestBuilder(b *testing.B) {
r := rand.New(rand.NewSource(time.Now().UnixNano()))
makeMsg := func(fieldCount int) proto.Message {
switch fieldCount {
case 5:
return &pb.Benchmark_Case5{
Field1: fmt.Sprintf("value%d", r.Intn(1000)),
Field2: fmt.Sprintf("value%d", r.Intn(1000)),
Field3: fmt.Sprintf("value%d", r.Intn(1000)),
Field4: fmt.Sprintf("value%d", r.Intn(1000)),
Field5: fmt.Sprintf("value%d", r.Intn(1000)),
}
case 10:
return &pb.Benchmark_Case10{
Field1: fmt.Sprintf("value%d", r.Intn(1000)),
Field2: fmt.Sprintf("value%d", r.Intn(1000)),
Field3: fmt.Sprintf("value%d", r.Intn(1000)),
Field4: fmt.Sprintf("value%d", r.Intn(1000)),
Field5: fmt.Sprintf("value%d", r.Intn(1000)),
Field6: fmt.Sprintf("value%d", r.Intn(1000)),
Field7: fmt.Sprintf("value%d", r.Intn(1000)),
Field8: fmt.Sprintf("value%d", r.Intn(1000)),
Field9: fmt.Sprintf("value%d", r.Intn(1000)),
Field10: fmt.Sprintf("value%d", r.Intn(1000)),
}
case 30:
return &pb.Benchmark_Case30{
Field1: fmt.Sprintf("value%d", r.Intn(1000)),
Field2: fmt.Sprintf("value%d", r.Intn(1000)),
Field3: fmt.Sprintf("value%d", r.Intn(1000)),
Field4: fmt.Sprintf("value%d", r.Intn(1000)),
Field5: fmt.Sprintf("value%d", r.Intn(1000)),
Field6: fmt.Sprintf("value%d", r.Intn(1000)),
Field7: fmt.Sprintf("value%d", r.Intn(1000)),
Field8: fmt.Sprintf("value%d", r.Intn(1000)),
Field9: fmt.Sprintf("value%d", r.Intn(1000)),
Field10: fmt.Sprintf("value%d", r.Intn(1000)),
Field11: fmt.Sprintf("value%d", r.Intn(1000)),
Field12: fmt.Sprintf("value%d", r.Intn(1000)),
Field13: fmt.Sprintf("value%d", r.Intn(1000)),
Field14: fmt.Sprintf("value%d", r.Intn(1000)),
Field15: fmt.Sprintf("value%d", r.Intn(1000)),
Field16: fmt.Sprintf("value%d", r.Intn(1000)),
Field17: fmt.Sprintf("value%d", r.Intn(1000)),
Field18: fmt.Sprintf("value%d", r.Intn(1000)),
Field19: fmt.Sprintf("value%d", r.Intn(1000)),
Field20: fmt.Sprintf("value%d", r.Intn(1000)),
Field21: fmt.Sprintf("value%d", r.Intn(1000)),
Field22: fmt.Sprintf("value%d", r.Intn(1000)),
Field23: fmt.Sprintf("value%d", r.Intn(1000)),
Field24: fmt.Sprintf("value%d", r.Intn(1000)),
Field25: fmt.Sprintf("value%d", r.Intn(1000)),
Field26: fmt.Sprintf("value%d", r.Intn(1000)),
Field27: fmt.Sprintf("value%d", r.Intn(1000)),
Field28: fmt.Sprintf("value%d", r.Intn(1000)),
Field29: fmt.Sprintf("value%d", r.Intn(1000)),
Field30: fmt.Sprintf("value%d", r.Intn(1000)),
}
default:
b.Fatal("undefined field count")
return nil
}
}
tests := []struct {
name string
pathTmpl string
bodyOption string
}{
{"all fields in path", "/resource/{field1}/{field2}", ""},
{"single field body", "/resource/{field1}", "field4"},
{"full body", "/resource", "*"},
}
for _, fields := range []int{5, 10, 30} {
for _, tt := range tests {
b.Run(fmt.Sprintf("%s_%d_fields", tt.name, fields), func(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
msg := makeMsg(fields)
rb, err := NewRequestBuilder(tt.pathTmpl, "POST", tt.bodyOption, msg)
if err != nil {
b.Fatalf("new request builder: %v", err)
}
_, _, err = rb.Build()
if err != nil {
b.Fatalf("build: %v", err)
}
}
})
}
}
}