diff --git a/routing/endpointregistry.go b/routing/endpointregistry.go index c8f929d07a..f7840e034d 100644 --- a/routing/endpointregistry.go +++ b/routing/endpointregistry.go @@ -33,6 +33,7 @@ func (e *entry) InflightRequests() int64 { type EndpointRegistry struct { lastSeen map[string]time.Time + now func() time.Time mu sync.Mutex @@ -45,7 +46,7 @@ type RegistryOptions struct { } func (r *EndpointRegistry) Do(routes []*Route) []*Route { - now := time.Now() + now := r.now() for _, route := range routes { if route.BackendType == eskip.LBBackend { @@ -76,6 +77,7 @@ func NewEndpointRegistry(o RegistryOptions) *EndpointRegistry { return &EndpointRegistry{ data: map[string]*entry{}, lastSeen: map[string]time.Time{}, + now: time.Now, } } diff --git a/routing/endpointregistry_test.go b/routing/endpointregistry_test.go index 39c4d6e1c7..22039b9686 100644 --- a/routing/endpointregistry_test.go +++ b/routing/endpointregistry_test.go @@ -1,4 +1,4 @@ -package routing +package routing_test import ( "fmt" @@ -9,10 +9,11 @@ import ( "github.com/stretchr/testify/assert" "github.com/zalando/skipper/eskip" + "github.com/zalando/skipper/routing" ) func TestEmptyRegistry(t *testing.T) { - r := NewEndpointRegistry(RegistryOptions{}) + r := routing.NewEndpointRegistry(routing.RegistryOptions{}) m := r.GetMetrics("some key") assert.Equal(t, time.Time{}, m.DetectedTime()) @@ -20,7 +21,7 @@ func TestEmptyRegistry(t *testing.T) { } func TestSetAndGet(t *testing.T) { - r := NewEndpointRegistry(RegistryOptions{}) + r := routing.NewEndpointRegistry(routing.RegistryOptions{}) mBefore := r.GetMetrics("some key") r.IncInflightRequest("some key") @@ -39,7 +40,7 @@ func TestSetAndGet(t *testing.T) { } func TestSetAndGetAnotherKey(t *testing.T) { - r := NewEndpointRegistry(RegistryOptions{}) + r := routing.NewEndpointRegistry(routing.RegistryOptions{}) r.IncInflightRequest("some key") mToChange := r.GetMetrics("some key") @@ -50,20 +51,46 @@ func TestSetAndGetAnotherKey(t *testing.T) { } func TestDoRemovesOldEntries(t *testing.T) { - route := &Route{LBEndpoints: []LBEndpoint{ - {Host: "existing endpoint"}, - }} - route.BackendType = eskip.LBBackend + r := routing.NewEndpointRegistry(routing.RegistryOptions{}) - r := NewEndpointRegistry(RegistryOptions{}) + routing.SetNow(r, func() time.Time { + return time.Date(2023, 9, 14, 0, 0, 0, 0, time.UTC) + }) + route := &routing.Route{ + LBEndpoints: []routing.LBEndpoint{ + {Host: "endpoint1.test:80"}, + {Host: "endpoint2.test:80"}, + }, + Route: eskip.Route{ + BackendType: eskip.LBBackend, + }, + } + r.Do([]*routing.Route{route}) + + mExist := r.GetMetrics("endpoint1.test:80") + mExistYet := r.GetMetrics("endpoint2.test:80") + assert.NotEqual(t, time.Time{}, mExist.DetectedTime()) + assert.NotEqual(t, time.Time{}, mExistYet.DetectedTime()) - r.IncInflightRequest("existing endpoint") - r.IncInflightRequest("removed endpoint") - r.lastSeen["removed endpoint"] = time.Now().Add(-lastSeenTimeout) - r.Do([]*Route{route}) + r.IncInflightRequest("endpoint1.test:80") + r.IncInflightRequest("endpoint2.test:80") + + routing.SetNow(r, func() time.Time { + return time.Date(2023, 9, 14, 0, 0, 0, 0, time.UTC).Add(routing.ExportLastSeenTimeout + time.Second) + }) + route = &routing.Route{ + LBEndpoints: []routing.LBEndpoint{ + {Host: "endpoint1.test:80"}, + }, + Route: eskip.Route{ + BackendType: eskip.LBBackend, + }, + } + route.BackendType = eskip.LBBackend + r.Do([]*routing.Route{route}) - mExist := r.GetMetrics("existing endpoint") - mRemoved := r.GetMetrics("removed endpoint") + mExist = r.GetMetrics("endpoint1.test:80") + mRemoved := r.GetMetrics("endpoint2.test:80") assert.NotEqual(t, time.Time{}, mExist.DetectedTime()) assert.Equal(t, int64(1), mExist.InflightRequests()) @@ -103,7 +130,7 @@ func benchmarkIncInflightRequests(b *testing.B, name string, goroutines int) { const mapSize int = 10000 b.Run(name, func(b *testing.B) { - r := NewEndpointRegistry(RegistryOptions{}) + r := routing.NewEndpointRegistry(routing.RegistryOptions{}) for i := 1; i < mapSize; i++ { r.IncInflightRequest(fmt.Sprintf("foo-%d", i)) } @@ -139,7 +166,7 @@ func benchmarkGetInflightRequests(b *testing.B, name string, goroutines int) { const mapSize int = 10000 b.Run(name, func(b *testing.B) { - r := NewEndpointRegistry(RegistryOptions{}) + r := routing.NewEndpointRegistry(routing.RegistryOptions{}) for i := 1; i < mapSize; i++ { r.IncInflightRequest(fmt.Sprintf("foo-%d", i)) } diff --git a/routing/export_test.go b/routing/export_test.go index 174db04730..1049a10594 100644 --- a/routing/export_test.go +++ b/routing/export_test.go @@ -1,8 +1,15 @@ package routing +import "time" + var ( ExportProcessRouteDef = processRouteDef ExportNewMatcher = newMatcher ExportMatch = (*matcher).match ExportProcessPredicates = processPredicates + ExportLastSeenTimeout = lastSeenTimeout ) + +func SetNow(r *EndpointRegistry, now func() time.Time) { + r.now = now +}