From 65f128de57810a8b98fb9461962918ccfbc65a38 Mon Sep 17 00:00:00 2001 From: carsontham Date: Fri, 13 Jun 2025 01:27:24 +0800 Subject: [PATCH 1/6] added entropy to mesh weight test Signed-off-by: carsontham --- conformance/tests/mesh/httproute-weight.go | 23 ++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/conformance/tests/mesh/httproute-weight.go b/conformance/tests/mesh/httproute-weight.go index 09ef3465b5..60b7c5cddd 100644 --- a/conformance/tests/mesh/httproute-weight.go +++ b/conformance/tests/mesh/httproute-weight.go @@ -21,10 +21,12 @@ import ( "errors" "fmt" "math" + "math/rand" "slices" "strings" "sync" "testing" + "time" "golang.org/x/sync/errgroup" @@ -52,7 +54,7 @@ var MeshHTTPRouteWeight = suite.ConformanceTest{ t.Run("Requests should have a distribution that matches the weight", func(t *testing.T) { host := "echo" expected := http.ExpectedResponse{ - Request: http.Request{Path: "/", Host: host}, + Request: http.Request{Path: "/", Host: host, Headers: make(map[string]string)}, Response: http.Response{StatusCode: 200}, Namespace: "gateway-conformance-mesh", } @@ -89,7 +91,9 @@ func testDistribution(t *testing.T, client echo.MeshPod, expected http.ExpectedR g.SetLimit(concurrentRequests) for i := 0.0; i < totalRequests; i++ { g.Go(func() error { - _, cRes, err := client.CaptureRequestResponseAndCompare(t, expected) + uniqueExpected := expected + addEntropy(&uniqueExpected) + _, cRes, err := client.CaptureRequestResponseAndCompare(t, uniqueExpected) if err != nil { return fmt.Errorf("failed: %w", err) } @@ -141,3 +145,18 @@ func testDistribution(t *testing.T, client echo.MeshPod, expected http.ExpectedR }) return errors.Join(errs...) } + +// addEntropy adds jitter to the request by adding either a delay up to 1 second, or a random header value, or both. +func addEntropy(exp *http.ExpectedResponse) { + delay := func() { time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond) } + randomHeader := func() { exp.Request.Headers["X-Jitter"] = fmt.Sprintf("%d", rand.Intn(9999)) } + switch rand.Intn(3) { + case 0: + delay() + case 1: + randomHeader() + case 2: + delay() + randomHeader() + } +} From f056dd5dea02fedc9b1d583dbb24a9a6de6607d1 Mon Sep 17 00:00:00 2001 From: carsontham Date: Fri, 13 Jun 2025 15:32:24 +0800 Subject: [PATCH 2/6] added nolint:gosec to skip linter issues for conformance test --- conformance/tests/mesh/httproute-weight.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/conformance/tests/mesh/httproute-weight.go b/conformance/tests/mesh/httproute-weight.go index 60b7c5cddd..a63f2e5ca9 100644 --- a/conformance/tests/mesh/httproute-weight.go +++ b/conformance/tests/mesh/httproute-weight.go @@ -148,9 +148,9 @@ func testDistribution(t *testing.T, client echo.MeshPod, expected http.ExpectedR // addEntropy adds jitter to the request by adding either a delay up to 1 second, or a random header value, or both. func addEntropy(exp *http.ExpectedResponse) { - delay := func() { time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond) } - randomHeader := func() { exp.Request.Headers["X-Jitter"] = fmt.Sprintf("%d", rand.Intn(9999)) } - switch rand.Intn(3) { + delay := func() { time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond) } //nolint:gosec // This is test code to get random value. + randomHeader := func() { exp.Request.Headers["X-Jitter"] = fmt.Sprintf("%d", rand.Intn(9999)) } //nolint:gosec // This is test code to get random value. + switch rand.Intn(3) { //nolint:gosec // This is test code to get random value case 0: delay() case 1: From 812f3dbce8e71d8ebcb0e3e464ac0b61d865dd28 Mon Sep 17 00:00:00 2001 From: carsontham Date: Sat, 14 Jun 2025 11:31:48 +0800 Subject: [PATCH 3/6] move creation of header map to entropy func to avoid concurrent map writes --- conformance/tests/mesh/httproute-weight.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/conformance/tests/mesh/httproute-weight.go b/conformance/tests/mesh/httproute-weight.go index a63f2e5ca9..125625c2de 100644 --- a/conformance/tests/mesh/httproute-weight.go +++ b/conformance/tests/mesh/httproute-weight.go @@ -54,7 +54,7 @@ var MeshHTTPRouteWeight = suite.ConformanceTest{ t.Run("Requests should have a distribution that matches the weight", func(t *testing.T) { host := "echo" expected := http.ExpectedResponse{ - Request: http.Request{Path: "/", Host: host, Headers: make(map[string]string)}, + Request: http.Request{Path: "/", Host: host}, Response: http.Response{StatusCode: 200}, Namespace: "gateway-conformance-mesh", } @@ -148,9 +148,12 @@ func testDistribution(t *testing.T, client echo.MeshPod, expected http.ExpectedR // addEntropy adds jitter to the request by adding either a delay up to 1 second, or a random header value, or both. func addEntropy(exp *http.ExpectedResponse) { - delay := func() { time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond) } //nolint:gosec // This is test code to get random value. - randomHeader := func() { exp.Request.Headers["X-Jitter"] = fmt.Sprintf("%d", rand.Intn(9999)) } //nolint:gosec // This is test code to get random value. - switch rand.Intn(3) { //nolint:gosec // This is test code to get random value + delay := func() { time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond) } //nolint:gosec // This is test code to get random value. + randomHeader := func() { + exp.Request.Headers = make(map[string]string) + exp.Request.Headers["X-Jitter"] = fmt.Sprintf("%d", rand.Intn(9999)) //nolint:gosec // This is test code to get random value. + } + switch rand.Intn(3) { //nolint:gosec // This is test code to get random value case 0: delay() case 1: From 30979604ec4332988f154e6d4993e9b88a4428d7 Mon Sep 17 00:00:00 2001 From: carsontham Date: Sun, 15 Jun 2025 16:20:35 +0800 Subject: [PATCH 4/6] use crypto/rand instead of math/rand --- conformance/tests/mesh/httproute-weight.go | 57 +++++++++++++++++----- 1 file changed, 45 insertions(+), 12 deletions(-) diff --git a/conformance/tests/mesh/httproute-weight.go b/conformance/tests/mesh/httproute-weight.go index 125625c2de..6be723cf92 100644 --- a/conformance/tests/mesh/httproute-weight.go +++ b/conformance/tests/mesh/httproute-weight.go @@ -18,10 +18,11 @@ package meshtests import ( "cmp" + "crypto/rand" "errors" "fmt" "math" - "math/rand" + "math/big" "slices" "strings" "sync" @@ -92,7 +93,9 @@ func testDistribution(t *testing.T, client echo.MeshPod, expected http.ExpectedR for i := 0.0; i < totalRequests; i++ { g.Go(func() error { uniqueExpected := expected - addEntropy(&uniqueExpected) + if err := addEntropy(&uniqueExpected); err != nil { + return fmt.Errorf("error adding entropy: %w", err) + } _, cRes, err := client.CaptureRequestResponseAndCompare(t, uniqueExpected) if err != nil { return fmt.Errorf("failed: %w", err) @@ -147,19 +150,49 @@ func testDistribution(t *testing.T, client echo.MeshPod, expected http.ExpectedR } // addEntropy adds jitter to the request by adding either a delay up to 1 second, or a random header value, or both. -func addEntropy(exp *http.ExpectedResponse) { - delay := func() { time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond) } //nolint:gosec // This is test code to get random value. - randomHeader := func() { +func addEntropy(exp *http.ExpectedResponse) error { + randomNumber := func(limit int64) (*int64, error) { + number, err := rand.Int(rand.Reader, big.NewInt(limit)) + if err != nil { + return nil, err + } + n := number.Int64() + return &n, nil + } + + // adds a delay + delay := func(limit int64) error { + randomSleepDuration, err := randomNumber(limit) + if err != nil { + return err + } + time.Sleep(time.Duration(*randomSleepDuration) * time.Millisecond) + return nil + } + // adds random header value + randomHeader := func(limit int64) error { + randomHeaderValue, err := randomNumber(limit) + if err != nil { + return err + } exp.Request.Headers = make(map[string]string) - exp.Request.Headers["X-Jitter"] = fmt.Sprintf("%d", rand.Intn(9999)) //nolint:gosec // This is test code to get random value. + exp.Request.Headers["X-Jitter"] = fmt.Sprintf("%d", *randomHeaderValue) + return nil } - switch rand.Intn(3) { //nolint:gosec // This is test code to get random value - case 0: - delay() + + random, err := randomNumber(3) + if err != nil { + return err + } + + switch *random { + case int64(0): + delay(1000) case 1: - randomHeader() + randomHeader(10000) case 2: - delay() - randomHeader() + delay(1000) + randomHeader(10000) } + return nil } From a0428a11658e7d5a52f4711eb9ba775268c0a312 Mon Sep 17 00:00:00 2001 From: carsontham Date: Sun, 15 Jun 2025 16:45:02 +0800 Subject: [PATCH 5/6] handle error checking and add default in switch --- conformance/tests/mesh/httproute-weight.go | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/conformance/tests/mesh/httproute-weight.go b/conformance/tests/mesh/httproute-weight.go index 6be723cf92..241c8ebd88 100644 --- a/conformance/tests/mesh/httproute-weight.go +++ b/conformance/tests/mesh/httproute-weight.go @@ -186,13 +186,16 @@ func addEntropy(exp *http.ExpectedResponse) error { } switch *random { - case int64(0): - delay(1000) + case 0: + return delay(1000) case 1: - randomHeader(10000) + return randomHeader(10000) case 2: - delay(1000) - randomHeader(10000) + if err := delay(1000); err != nil { + return err + } + return randomHeader(10000) + default: + return nil } - return nil } From d524e191f4ed89a9d775d7d35b2793cdd5566178 Mon Sep 17 00:00:00 2001 From: carsontham Date: Sun, 15 Jun 2025 16:55:22 +0800 Subject: [PATCH 6/6] return error in default for switch case --- conformance/tests/mesh/httproute-weight.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conformance/tests/mesh/httproute-weight.go b/conformance/tests/mesh/httproute-weight.go index 241c8ebd88..cc296d92d5 100644 --- a/conformance/tests/mesh/httproute-weight.go +++ b/conformance/tests/mesh/httproute-weight.go @@ -196,6 +196,6 @@ func addEntropy(exp *http.ExpectedResponse) error { } return randomHeader(10000) default: - return nil + return fmt.Errorf("invalid random value: %d", *random) } }