109 lines
3.2 KiB
Go
109 lines
3.2 KiB
Go
package affinity
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestTableKeepsBindingsIsolatedAndExpiresThem(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
now := time.Date(2026, time.August, 2, 9, 0, 0, 0, time.UTC)
|
|
table, err := NewTable(Options{
|
|
MaxEntries: 2,
|
|
Now: func() time.Time { return now },
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("NewTable() error = %v", err)
|
|
}
|
|
first, err := NewKey("client-a", "route-a", "session-a")
|
|
if err != nil {
|
|
t.Fatalf("NewKey(first) error = %v", err)
|
|
}
|
|
second, err := NewKey("client-b", "route-a", "session-a")
|
|
if err != nil {
|
|
t.Fatalf("NewKey(second) error = %v", err)
|
|
}
|
|
if first == second {
|
|
t.Fatal("same session under distinct clients must have different affinity keys")
|
|
}
|
|
|
|
table.Bind(first, "proxy-a", now.Add(time.Minute))
|
|
table.Bind(second, "proxy-b", now.Add(time.Minute))
|
|
if binding, ok := table.Lookup(first); !ok || binding.ProxyID != "proxy-a" {
|
|
t.Fatalf("Lookup(first) = (%+v, %v), want proxy-a", binding, ok)
|
|
}
|
|
|
|
now = now.Add(time.Minute)
|
|
if _, ok := table.Lookup(first); ok {
|
|
t.Fatal("Lookup(first) retained an expired binding")
|
|
}
|
|
}
|
|
|
|
func TestTableEvictsLeastRecentlyUsedBindingAtCapacity(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
now := time.Date(2026, time.August, 2, 9, 0, 0, 0, time.UTC)
|
|
table, err := NewTable(Options{
|
|
MaxEntries: 2,
|
|
Now: func() time.Time { return now },
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("NewTable() error = %v", err)
|
|
}
|
|
first := mustKey(t, "client-a", "route-a", "session-a")
|
|
second := mustKey(t, "client-a", "route-a", "session-b")
|
|
third := mustKey(t, "client-a", "route-a", "session-c")
|
|
expiresAt := now.Add(time.Minute)
|
|
|
|
table.Bind(first, "proxy-a", expiresAt)
|
|
table.Bind(second, "proxy-b", expiresAt)
|
|
if _, ok := table.Lookup(first); !ok {
|
|
t.Fatal("Lookup(first) must retain the binding")
|
|
}
|
|
table.Bind(third, "proxy-c", expiresAt)
|
|
|
|
if _, ok := table.Lookup(second); ok {
|
|
t.Fatal("Lookup(second) retained least recently used binding after capacity eviction")
|
|
}
|
|
if binding, ok := table.Lookup(first); !ok || binding.ProxyID != "proxy-a" {
|
|
t.Fatalf("Lookup(first) = (%+v, %v), want proxy-a", binding, ok)
|
|
}
|
|
if binding, ok := table.Lookup(third); !ok || binding.ProxyID != "proxy-c" {
|
|
t.Fatalf("Lookup(third) = (%+v, %v), want proxy-c", binding, ok)
|
|
}
|
|
}
|
|
|
|
func TestNewKeyRejectsInvalidInputs(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
for _, test := range []struct {
|
|
name string
|
|
clientID string
|
|
routing string
|
|
sessionID string
|
|
}{
|
|
{name: "empty client", routing: "route-a", sessionID: "session-a"},
|
|
{name: "empty routing", clientID: "client-a", sessionID: "session-a"},
|
|
{name: "empty session", clientID: "client-a", routing: "route-a"},
|
|
{name: "oversized session", clientID: "client-a", routing: "route-a", sessionID: string(make([]byte, 129))},
|
|
{name: "space session", clientID: "client-a", routing: "route-a", sessionID: "session a"},
|
|
} {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
if _, err := NewKey(test.clientID, test.routing, test.sessionID); err == nil {
|
|
t.Fatal("NewKey() error = nil, want invalid input")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func mustKey(t *testing.T, clientID, routing, sessionID string) Key {
|
|
t.Helper()
|
|
key, err := NewKey(clientID, routing, sessionID)
|
|
if err != nil {
|
|
t.Fatalf("NewKey() error = %v", err)
|
|
}
|
|
return key
|
|
}
|