Files
seaweedfs/weed/s3api/s3vectors/metrics_test.go
T
Chris Lu 84cd3c621b s3vectors: integrate bucket metrics, audit events, and request limits (#12514)
* s3vectors: attribute request and traffic metrics to authorized buckets

* s3vectors: emit resource and identity audit events

* s3vectors: apply existing S3 request limits and preserve JSON errors

* s3vectors: select limit resources by the dispatched operation

* s3vectors: count decoded chunked request bodies against byte limits
2026-11-09 11:37:06 -08:00

77 lines
3.0 KiB
Go

package s3vectors
import (
"bytes"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"github.com/gorilla/mux"
"github.com/prometheus/client_golang/prometheus/testutil"
"github.com/seaweedfs/seaweedfs/weed/s3api/s3tables"
"github.com/seaweedfs/seaweedfs/weed/s3api/s3tables/s3tablestest"
"github.com/seaweedfs/seaweedfs/weed/stats"
)
func TestVectorMetricsAttributeAuthorizedBuckets(t *testing.T) {
fs := s3tablestest.Start(t)
s := NewServer(s3tables.NewManagerClient(fs.Client), headerAuth{}, newFakeVectors(0))
var limitCalls int
s.SetLimiter(func(next http.HandlerFunc, action string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { limitCalls++; next(w, r) }
})
router := mux.NewRouter()
s.RegisterRoutes(router)
request := func(identity, operation string, payload interface{}) *httptest.ResponseRecorder {
t.Helper()
body, err := json.Marshal(payload)
if err != nil {
t.Fatal(err)
}
r := httptest.NewRequest(http.MethodPost, "/"+operation, bytes.NewReader(body))
r.Header.Set("X-Test-Identity", identity)
w := httptest.NewRecorder()
router.ServeHTTP(w, r)
return w
}
const bucket = "metrics-vector-bucket"
if w := request("", "CreateVectorBucket", CreateVectorBucketRequest{VectorBucketName: bucket}); w.Code != http.StatusOK {
t.Fatalf("create: %d %s", w.Code, w.Body)
}
count := stats.S3RequestCounter.WithLabelValues("s3vectors.GetVectorBucket", "200", bucket)
before := testutil.ToFloat64(count)
if w := request("", "GetVectorBucket", GetVectorBucketRequest{VectorBucketArn: s.vectorBucketArn(bucket)}); w.Code != http.StatusOK {
t.Fatalf("get by ARN: %d %s", w.Code, w.Body)
}
if got := testutil.ToFloat64(count) - before; got != 1 {
t.Fatalf("bucket requests = %v, want 1", got)
}
denied := stats.S3RequestCounter.WithLabelValues("s3vectors.GetVectorBucket", "403", "")
before = testutil.ToFloat64(denied)
if w := request("stranger", "GetVectorBucket", GetVectorBucketRequest{VectorBucketName: bucket}); w.Code != http.StatusForbidden {
t.Fatalf("unauthorized get: %d %s", w.Code, w.Body)
}
if got := testutil.ToFloat64(denied) - before; got != 1 {
t.Fatalf("unattributed denied requests = %v, want 1", got)
}
if got := testutil.ToFloat64(stats.S3BucketTrafficReceivedBytesCounter.WithLabelValues(bucket)); got <= 0 {
t.Fatalf("received bytes = %v", got)
}
if got := testutil.ToFloat64(stats.S3BucketTrafficSentBytesCounter.WithLabelValues(bucket)); got <= 0 {
t.Fatalf("sent bytes = %v", got)
}
if got := testutil.ToFloat64(stats.S3InFlightRequestsGauge.WithLabelValues("s3vectors.GetVectorBucket")); got != 0 {
t.Fatalf("in-flight requests = %v after responses", got)
}
r := httptest.NewRequest(http.MethodGet, tagsPathPrefix+s.vectorBucketArn(bucket), nil)
w := httptest.NewRecorder()
router.ServeHTTP(w, r)
if w.Code != http.StatusOK || testutil.ToFloat64(stats.S3RequestCounter.WithLabelValues("s3vectors.ListTagsForResource", "200", bucket)) == 0 {
t.Fatalf("tag metrics: %d %s", w.Code, w.Body)
}
if limitCalls != 4 {
t.Fatalf("limiter calls = %d, want 4", limitCalls)
}
}