Skip to content

Commit

Permalink
predicates/traffic: deflake TestTrafficSegmentSplit (#3330)
Browse files Browse the repository at this point in the history
Use fixed random sequence to deflake TestTrafficSegmentSplit.

Fixes #2665

Signed-off-by: Alexander Yastrebov <[email protected]>
  • Loading branch information
AlexanderYastrebov authored Dec 10, 2024
1 parent d8d1bbf commit 010c033
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 7 deletions.
11 changes: 11 additions & 0 deletions predicates/traffic/export_test.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
package traffic

import "github.com/zalando/skipper/routing"

var ExportRandomValue = randomValue

func WithRandFloat64(ps routing.PredicateSpec, randFloat64 func() float64) routing.PredicateSpec {
if s, ok := ps.(*segmentSpec); ok {
s.randFloat64 = randFloat64
} else {
panic("invalid predicate spec, expected *segmentSpec")
}
return ps
}
22 changes: 22 additions & 0 deletions predicates/traffic/rand_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package traffic_test

import (
"math/rand/v2"
"sync"
)

// newTestRandFloat64 returns a function that generates fixed sequence of random float64 values for testing.
func newTestRandFloat64() func() float64 {
return rand.New(&lockedSource{s: rand.NewPCG(0x5EED_1, 0x5EED_2)}).Float64
}

type lockedSource struct {
mu sync.Mutex
s rand.Source
}

func (s *lockedSource) Uint64() uint64 {
s.mu.Lock()
defer s.mu.Unlock()
return s.s.Uint64()
}
17 changes: 11 additions & 6 deletions predicates/traffic/segment.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,13 @@ import (
)

type (
segmentSpec struct{}
segmentPredicate struct{ min, max float64 }
segmentSpec struct {
randFloat64 func() float64
}
segmentPredicate struct {
randFloat64 func() float64
min, max float64
}
)

type contextKey struct{}
Expand All @@ -19,7 +24,7 @@ var randomValue contextKey

// NewSegment creates a new traffic segment predicate specification
func NewSegment() routing.WeightedPredicateSpec {
return &segmentSpec{}
return &segmentSpec{rand.Float64}
}

func (*segmentSpec) Name() string {
Expand All @@ -42,12 +47,12 @@ func (*segmentSpec) Name() string {
// r50: Path("/test") && TrafficSegment(0.0, 0.5) -> <shunt>;
// r30: Path("/test") && TrafficSegment(0.5, 0.8) -> <shunt>;
// r20: Path("/test") && TrafficSegment(0.8, 1.0) -> <shunt>;
func (*segmentSpec) Create(args []any) (routing.Predicate, error) {
func (s *segmentSpec) Create(args []any) (routing.Predicate, error) {
if len(args) != 2 {
return nil, predicates.ErrInvalidPredicateParameters
}

p, ok := &segmentPredicate{}, false
p, ok := &segmentPredicate{randFloat64: s.randFloat64}, false

if p.min, ok = args[0].(float64); !ok || p.min < 0 || p.min > 1 {
return nil, predicates.ErrInvalidPredicateParameters
Expand All @@ -72,7 +77,7 @@ func (*segmentSpec) Weight() int {
}

func (p *segmentPredicate) Match(req *http.Request) bool {
r := routing.FromContext(req.Context(), randomValue, rand.Float64)
r := routing.FromContext(req.Context(), randomValue, p.randFloat64)
// min == max defines a never-matching interval and always yields false
return p.min <= r && r < p.max
}
4 changes: 3 additions & 1 deletion predicates/traffic/segment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,9 @@ func TestTrafficSegmentSplit(t *testing.T) {
RoutingOptions: routing.Options{
FilterRegistry: builtin.MakeRegistry(),
Predicates: []routing.PredicateSpec{
traffic.NewSegment(),
// Use fixed random sequence to deflake the test,
// see https://github.com/zalando/skipper/issues/2665
traffic.WithRandFloat64(traffic.NewSegment(), newTestRandFloat64()),
},
},
Routes: eskip.MustParse(`
Expand Down

0 comments on commit 010c033

Please sign in to comment.