Skip to content

Commit bef25ff

Browse files
committed
add grpc entropy
1 parent cc54768 commit bef25ff

File tree

4 files changed

+112
-46
lines changed

4 files changed

+112
-46
lines changed

conformance/tests/weight-distribution.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,11 @@ type GRPCRequestSender struct {
7575
}
7676

7777
func (s *GRPCRequestSender) SendRequest() (string, error) {
78-
resp, err := s.client.SendRPC(s.t, s.gwAddr, s.expected, s.timeout)
78+
uniqueExpected := s.expected
79+
if err := grpc.AddEntropy(&uniqueExpected); err != nil {
80+
return "", fmt.Errorf("error adding entropy: %w", err)
81+
}
82+
resp, err := s.client.SendRPC(s.t, s.gwAddr, uniqueExpected, s.timeout)
7983
if err != nil {
8084
return "", fmt.Errorf("failed to send gRPC request: %w", err)
8185
}

conformance/utils/entropy/entropy.go

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
Copyright 2025 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package entropy
18+
19+
import (
20+
"crypto/rand"
21+
"fmt"
22+
"math/big"
23+
"time"
24+
)
25+
26+
// randomNumber generates a random number between 0 and limit-1
27+
func randomNumber(limit int64) (*int64, error) {
28+
number, err := rand.Int(rand.Reader, big.NewInt(limit))
29+
if err != nil {
30+
return nil, err
31+
}
32+
n := number.Int64()
33+
return &n, nil
34+
}
35+
36+
// AddDelay adds a random delay up to the specified limit in milliseconds
37+
func AddDelay(limit int64) error {
38+
randomSleepDuration, err := randomNumber(limit)
39+
if err != nil {
40+
return err
41+
}
42+
time.Sleep(time.Duration(*randomSleepDuration) * time.Millisecond)
43+
return nil
44+
}
45+
46+
// GenerateRandomValue generates a random value as a string for use in headers/metadata
47+
func GenerateRandomValue(limit int64) (string, error) {
48+
randomVal, err := randomNumber(limit)
49+
if err != nil {
50+
return "", err
51+
}
52+
return fmt.Sprintf("%d", *randomVal), nil
53+
}
54+
55+
// AddRandomEntropy randomly chooses to add delay, random value, or both
56+
// The addRandomValue function should be provided by the caller to handle
57+
// protocol-specific ways of adding the random value (HTTP headers, gRPC metadata, etc.)
58+
func AddRandomEntropy(addRandomValue func(string) error) error {
59+
random, err := randomNumber(3)
60+
if err != nil {
61+
return err
62+
}
63+
64+
switch *random {
65+
case 0:
66+
return AddDelay(1000)
67+
case 1:
68+
randomValue, err := GenerateRandomValue(10000)
69+
if err != nil {
70+
return err
71+
}
72+
return addRandomValue(randomValue)
73+
case 2:
74+
if err := AddDelay(1000); err != nil {
75+
return err
76+
}
77+
randomValue, err := GenerateRandomValue(10000)
78+
if err != nil {
79+
return err
80+
}
81+
return addRandomValue(randomValue)
82+
default:
83+
return fmt.Errorf("invalid random value: %d", *random)
84+
}
85+
}

conformance/utils/grpc/grpc.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import (
3333

3434
pb "sigs.k8s.io/gateway-api/conformance/echo-basic/grpcechoserver"
3535
"sigs.k8s.io/gateway-api/conformance/utils/config"
36+
"sigs.k8s.io/gateway-api/conformance/utils/entropy"
3637
"sigs.k8s.io/gateway-api/conformance/utils/http"
3738
"sigs.k8s.io/gateway-api/conformance/utils/tlog"
3839
)
@@ -289,3 +290,20 @@ func MakeRequestAndExpectEventuallyConsistentResponse(t *testing.T, c Client, ti
289290
http.AwaitConvergence(t, timeoutConfig.RequiredConsecutiveSuccesses, timeoutConfig.MaxTimeToConsistency, sendRPC)
290291
tlog.Logf(t, "Request passed")
291292
}
293+
294+
// AddEntropy adds randomness to ExpectedResponse to avoid caching issues and ensure each request is unique.
295+
// It randomly chooses to add a delay, random metadata, or both.
296+
func AddEntropy(exp *ExpectedResponse) error {
297+
addRandomMetadata := func(randomValue string) error {
298+
if exp.RequestMetadata == nil {
299+
exp.RequestMetadata = &RequestMetadata{}
300+
}
301+
if exp.RequestMetadata.Metadata == nil {
302+
exp.RequestMetadata.Metadata = make(map[string]string)
303+
}
304+
exp.RequestMetadata.Metadata["x-jitter"] = randomValue
305+
return nil
306+
}
307+
308+
return entropy.AddRandomEntropy(addRandomMetadata)
309+
}

conformance/utils/http/http.go

Lines changed: 4 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,15 @@ limitations under the License.
1717
package http
1818

1919
import (
20-
"crypto/rand"
2120
"fmt"
22-
"math/big"
2321
"net"
2422
"net/url"
2523
"strings"
2624
"testing"
2725
"time"
2826

2927
"sigs.k8s.io/gateway-api/conformance/utils/config"
28+
"sigs.k8s.io/gateway-api/conformance/utils/entropy"
3029
"sigs.k8s.io/gateway-api/conformance/utils/roundtripper"
3130
"sigs.k8s.io/gateway-api/conformance/utils/tlog"
3231
)
@@ -483,51 +482,11 @@ func setRedirectRequestDefaults(req *roundtripper.Request, cRes *roundtripper.Ca
483482

484483
// addEntropy adds jitter to the request by adding either a delay up to 1 second, or a random header value, or both.
485484
func AddEntropy(exp *ExpectedResponse) error {
486-
randomNumber := func(limit int64) (*int64, error) {
487-
number, err := rand.Int(rand.Reader, big.NewInt(limit))
488-
if err != nil {
489-
return nil, err
490-
}
491-
n := number.Int64()
492-
return &n, nil
493-
}
494-
495-
// adds a delay
496-
delay := func(limit int64) error {
497-
randomSleepDuration, err := randomNumber(limit)
498-
if err != nil {
499-
return err
500-
}
501-
time.Sleep(time.Duration(*randomSleepDuration) * time.Millisecond)
502-
return nil
503-
}
504-
// adds random header value
505-
randomHeader := func(limit int64) error {
506-
randomHeaderValue, err := randomNumber(limit)
507-
if err != nil {
508-
return err
509-
}
485+
addRandomHeader := func(randomValue string) error {
510486
exp.Request.Headers = make(map[string]string)
511-
exp.Request.Headers["X-Jitter"] = fmt.Sprintf("%d", *randomHeaderValue)
487+
exp.Request.Headers["X-Jitter"] = randomValue
512488
return nil
513489
}
514490

515-
random, err := randomNumber(3)
516-
if err != nil {
517-
return err
518-
}
519-
520-
switch *random {
521-
case 0:
522-
return delay(1000)
523-
case 1:
524-
return randomHeader(10000)
525-
case 2:
526-
if err := delay(1000); err != nil {
527-
return err
528-
}
529-
return randomHeader(10000)
530-
default:
531-
return fmt.Errorf("invalid random value: %d", *random)
532-
}
491+
return entropy.AddRandomEntropy(addRandomHeader)
533492
}

0 commit comments

Comments
 (0)