diff --git a/filters/openpolicyagent/opaauthorizerequest/benchmark_test.go b/filters/openpolicyagent/opaauthorizerequest/benchmark_test.go index 67369cfd1a..926901a8cc 100644 --- a/filters/openpolicyagent/opaauthorizerequest/benchmark_test.go +++ b/filters/openpolicyagent/opaauthorizerequest/benchmark_test.go @@ -3,6 +3,7 @@ package opaauthorizerequest import ( _ "embed" "fmt" + "github.com/benburkert/pbench" "github.com/golang-jwt/jwt/v4" opasdktest "github.com/open-policy-agent/opa/sdk/test" "github.com/stretchr/testify/assert" @@ -252,21 +253,20 @@ func BenchmarkJwtValidation(b *testing.B) { signedToken, err := token.SignedString(key) require.NoError(b, err, "Failed to sign token") - ctx := &filtertest.Context{ - FStateBag: map[string]interface{}{}, - FResponse: &http.Response{}, - FRequest: &http.Request{ - Header: map[string][]string{ - "Authorization": {fmt.Sprintf("Bearer %s", signedToken)}, - }, - URL: reqUrl, - }, - FMetrics: &metricstest.MockMetrics{}, - } - b.ResetTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { + ctx := &filtertest.Context{ + FStateBag: map[string]interface{}{}, + FResponse: &http.Response{}, + FRequest: &http.Request{ + Header: map[string][]string{ + "Authorization": {fmt.Sprintf("Bearer %s", signedToken)}, + }, + URL: reqUrl, + }, + FMetrics: &metricstest.MockMetrics{}, + } f.Request(ctx) assert.False(b, ctx.FServed) } @@ -329,6 +329,74 @@ func BenchmarkMinimalPolicyBundle(b *testing.B) { }) } +// BenchmarkWithPercentiles is an example benchmark that demonstrates how to measure +// and report latency percentiles in OPA filter benchmark tests. +// +// It uses a minimal policy with decision logging enabled and reports +// p50, p95, p99, and p999 latency percentiles to provide insights into +// the distribution of request latencies, especially the impact of +// decision logging. +// +// To run this benchmark, use the following command: +// go test -bench=^BenchmarkWithPercentiles$ -benchmem ./filters/openpolicyagent/opaauthorizerequest +func BenchmarkWithPercentiles(b *testing.B) { + opaControlPlane := opasdktest.MustNewServer( + opasdktest.MockBundle(testBundleEndpoint, map[string]string{ + "main.rego": ` + package envoy.authz + + default allow = false + + allow { + input.parsed_path = [ "allow" ] + } + `, + }), + ) + defer opaControlPlane.Stop() + + decisionLogsConsumer := newDecisionConsumer() + defer decisionLogsConsumer.Close() + + filterOpts := FilterOptions{ + OpaControlPlaneUrl: opaControlPlane.URL(), + DecisionConsumerUrl: decisionLogsConsumer.URL, + DecisionPath: testDecisionPath, + BundleName: testBundleName, + DecisionLogging: true, + ContextExtensions: "", + } + f, err := createOpaFilter(filterOpts) + require.NoError(b, err) + + reqUrl, err := url.Parse("http://opa-authorized.test/allow") + require.NoError(b, err) + + ctx := &filtertest.Context{ + FStateBag: map[string]interface{}{}, + FResponse: &http.Response{}, + FRequest: &http.Request{ + URL: reqUrl, + }, + FMetrics: &metricstest.MockMetrics{}, + } + + pb := pbench.New(b) + pb.ReportPercentile(0.5) + pb.ReportPercentile(0.95) + pb.ReportPercentile(0.99) + pb.ReportPercentile(0.999) + + pb.Run("minimal-with-decision-logs", func(b *pbench.B) { + b.RunParallel(func(pb *pbench.PB) { + for pb.Next() { + f.Request(ctx) + assert.False(b, ctx.FServed) + } + }) + }) +} + func newDecisionConsumer() *httptest.Server { return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) diff --git a/go.mod b/go.mod index fa8e47e82e..45a7727543 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( github.com/abbot/go-http-auth v0.4.0 github.com/andybalholm/brotli v1.1.1 github.com/aryszka/jobqueue v0.0.3 + github.com/benburkert/pbench v0.0.0-20160623210926-4ec5821845ef github.com/cenkalti/backoff v2.2.1+incompatible github.com/cespare/xxhash/v2 v2.3.0 github.com/cjoudrey/gluahttp v0.0.0-20201111170219-25003d9adfa9 @@ -94,6 +95,7 @@ require ( github.com/envoyproxy/protoc-gen-validate v1.1.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/gavv/monotime v0.0.0-20190418164738-30dba4353424 // indirect github.com/go-ini/ini v1.67.0 // indirect github.com/go-jose/go-jose/v4 v4.0.5 // indirect github.com/go-logr/logr v1.4.2 // indirect diff --git a/go.sum b/go.sum index 7453012a10..faa3e7c7a1 100644 --- a/go.sum +++ b/go.sum @@ -44,6 +44,8 @@ github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJ github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/aryszka/jobqueue v0.0.3 h1:O5YbgzQCjRomudwnDTY5BrHUNJhvPHQHq7GfGpE+ybs= github.com/aryszka/jobqueue v0.0.3/go.mod h1:SdxqI6HZ4E1Lss94tey5OfjcAu3bdCDWS1AQzzIN4m4= +github.com/benburkert/pbench v0.0.0-20160623210926-4ec5821845ef h1:+7ZJvJGiV4hUBdjhEDhfGdjBCOmhVi0YQ5n+6g/ei+k= +github.com/benburkert/pbench v0.0.0-20160623210926-4ec5821845ef/go.mod h1:hrhDSsc41bBqGejYXbvMh6qexfcC2vXjodP5gufwWyI= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -153,6 +155,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/gavv/monotime v0.0.0-20190418164738-30dba4353424 h1:Vh7rylVZRZCj6W41lRlP17xPk4Nq260H4Xo/DDYmEZk= +github.com/gavv/monotime v0.0.0-20190418164738-30dba4353424/go.mod h1:vmp8DIyckQMXOPl0AQVHt+7n5h7Gb7hS6CUydiV8QeA= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=