wip: update request latency test

This commit is contained in:
Joe Kralicky 2024-11-01 17:09:46 -04:00
parent 8049ca54d0
commit 85f06ab36b
No known key found for this signature in database
GPG key ID: 75C4875F34A9FB79
2 changed files with 82 additions and 64 deletions

View file

@ -1,12 +1,11 @@
package benchmarks_test
import (
"flag"
"fmt"
"io"
"math/rand/v2"
"net/http"
"path/filepath"
"strings"
"testing"
"github.com/pomerium/pomerium/internal/testenv"
@ -16,12 +15,16 @@ import (
"github.com/stretchr/testify/assert"
)
func BenchmarkRequestLatency(b *testing.B) {
for _, n := range []int{1, 10, 100} {
b.StopTimer()
env := testenv.New(b)
var numRoutes int
func init() {
flag.IntVar(&numRoutes, "routes", 100, "number of routes")
}
func TestRequestLatency(t *testing.T) {
env := testenv.New(t, testenv.Silent())
users := []*scenarios.User{}
for i := range n {
for i := range numRoutes {
users = append(users, &scenarios.User{
Email: fmt.Sprintf("user%d@example.com", i),
FirstName: fmt.Sprintf("Firstname%d", i),
@ -34,8 +37,8 @@ func BenchmarkRequestLatency(b *testing.B) {
up.Handle("/", func(w http.ResponseWriter, _ *http.Request) {
w.Write([]byte("OK"))
})
routes := make([]testenv.Route, n)
for i := range n {
routes := make([]testenv.Route, numRoutes)
for i := range numRoutes {
routes[i] = up.Route().
From(env.SubdomainURL(fmt.Sprintf("from-%d", i))).
PPL(fmt.Sprintf(`{"allow":{"and":["email":{"is":"user%d@example.com"}]}}`, i))
@ -45,26 +48,27 @@ func BenchmarkRequestLatency(b *testing.B) {
env.Start()
snippets.WaitStartupComplete(env)
b.StartTimer()
b.Run(fmt.Sprintf("routes=%d", n), func(b *testing.B) {
indexes := rand.Perm(n)
rec := env.NewLogRecorder(testenv.WithSkipCloseDelay())
for i := range b.N {
idx := indexes[i%n]
out := testing.Benchmark(func(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
// rec := env.NewLogRecorder(testenv.WithSkipCloseDelay())
for pb.Next() {
idx := rand.IntN(numRoutes)
resp, err := up.Get(routes[idx], upstreams.AuthenticateAs(fmt.Sprintf("user%d@example.com", idx)))
if !assert.NoError(b, err) {
rec.DumpToFile(filepath.Join("testdata", strings.ReplaceAll(b.Name(), "/", "_")))
// rec.DumpToFile(filepath.Join("testdata", strings.ReplaceAll(b.Name(), "/", "_")))
return
}
assert.Equal(b, resp.StatusCode, 200)
body, err := io.ReadAll(resp.Body)
resp.Body.Close()
assert.NoError(b, err)
assert.Equal(b, "OK", string(body))
}
})
})
t.Log(out)
t.Logf("req/s: %f", float64(out.N)/out.T.Seconds())
env.Stop()
}
}

View file

@ -204,6 +204,7 @@ type environment struct {
type EnvironmentOptions struct {
debug bool
pauseOnFailure bool
forceSilent bool
}
type EnvironmentOption func(*EnvironmentOptions)
@ -232,6 +233,15 @@ func PauseOnFailure(enable ...bool) EnvironmentOption {
}
}
func Silent(silent ...bool) EnvironmentOption {
if len(silent) == 0 {
silent = append(silent, true)
}
return func(o *EnvironmentOptions) {
o.forceSilent = silent[0]
}
}
var setGrpcLoggerOnce sync.Once
func New(t testing.TB, opts ...EnvironmentOption) Environment {
@ -257,7 +267,7 @@ func New(t testing.TB, opts ...EnvironmentOption) Environment {
require.NoError(t, err)
writer := log.NewMultiWriter()
silent := isSilent(t)
silent := options.forceSilent || isSilent(t)
if silent {
log.SetLevel(zerolog.FatalLevel)
zerolog.SetGlobalLevel(zerolog.DebugLevel)
@ -281,7 +291,8 @@ func New(t testing.TB, opts ...EnvironmentOption) Environment {
require: require.New(t),
tempDir: t.TempDir(),
ports: Ports{
Proxy: values.Deferred[int](),
ProxyHTTP: values.Deferred[int](),
ProxyGRPC: values.Deferred[int](),
GRPC: values.Deferred[int](),
HTTP: values.Deferred[int](),
Outbound: values.Deferred[int](),
@ -338,7 +349,8 @@ type WithCaller[T any] struct {
}
type Ports struct {
Proxy values.MutableValue[int]
ProxyHTTP values.MutableValue[int]
ProxyGRPC values.MutableValue[int]
GRPC values.MutableValue[int]
HTTP values.MutableValue[int]
Outbound values.MutableValue[int]
@ -364,7 +376,7 @@ func (e *environment) Require() *require.Assertions {
}
func (e *environment) SubdomainURL(subdomain string) values.Value[string] {
return values.Bind(e.ports.Proxy, func(port int) string {
return values.Bind(e.ports.ProxyHTTP, func(port int) string {
return fmt.Sprintf("https://%s.%s:%d", subdomain, e.domain, port)
})
}
@ -425,7 +437,7 @@ func (e *environment) Start() {
cfg := &config.Config{
Options: config.NewDefaultOptions(),
}
ports, err := netutil.AllocatePorts(7)
ports, err := netutil.AllocatePorts(8)
require.NoError(e.t, err)
atoi := func(str string) int {
p, err := strconv.Atoi(str)
@ -434,20 +446,22 @@ func (e *environment) Start() {
}
return p
}
e.ports.Proxy.Resolve(atoi(ports[0]))
e.ports.GRPC.Resolve(atoi(ports[1]))
e.ports.HTTP.Resolve(atoi(ports[2]))
e.ports.Outbound.Resolve(atoi(ports[3]))
e.ports.Metrics.Resolve(atoi(ports[4]))
e.ports.Debug.Resolve(atoi(ports[5]))
e.ports.ALPN.Resolve(atoi(ports[6]))
cfg.AllocatePorts(*(*[6]string)(ports[1:]))
e.ports.ProxyHTTP.Resolve(atoi(ports[0]))
e.ports.ProxyGRPC.Resolve(atoi(ports[1]))
e.ports.GRPC.Resolve(atoi(ports[2]))
e.ports.HTTP.Resolve(atoi(ports[3]))
e.ports.Outbound.Resolve(atoi(ports[4]))
e.ports.Metrics.Resolve(atoi(ports[5]))
e.ports.Debug.Resolve(atoi(ports[6]))
e.ports.ALPN.Resolve(atoi(ports[7]))
cfg.AllocatePorts(*(*[6]string)(ports[2:]))
cfg.Options.AutocertOptions = config.AutocertOptions{Enable: false}
cfg.Options.Services = "all"
cfg.Options.LogLevel = config.LogLevelDebug
cfg.Options.ProxyLogLevel = config.LogLevelInfo
cfg.Options.Addr = fmt.Sprintf("127.0.0.1:%d", e.ports.Proxy.Value())
cfg.Options.Addr = fmt.Sprintf("127.0.0.1:%d", e.ports.ProxyHTTP.Value())
cfg.Options.GRPCAddr = fmt.Sprintf("127.0.0.1:%d", e.ports.ProxyGRPC.Value())
cfg.Options.CAFile = filepath.Join(e.tempDir, "certs", "ca.pem")
cfg.Options.CertFile = filepath.Join(e.tempDir, "certs", "trusted.pem")
cfg.Options.KeyFile = filepath.Join(e.tempDir, "certs", "trusted-key.pem")
@ -707,8 +721,8 @@ func (e *environment) ReportOK(_ health.Check, _ ...health.Attr) {}
func (e *environment) advanceState(newState EnvironmentState) {
e.stateMu.Lock()
defer e.stateMu.Unlock()
if e.state != newState>>1 {
panic(fmt.Sprintf("internal test environment bug: invalid state: expected=%s, actual=%s", newState>>1, e.state))
if newState <= e.state {
panic(fmt.Sprintf("internal test environment bug: changed state to <= current: newState=%s, current=%s", newState, e.state))
}
e.debugf("state %s -> %s", e.state.String(), newState.String())
e.state = newState