mirror of
https://github.com/lukaszraczylo/traefikoidc.git
synced 2026-11-03 07:44:13 +00:00
Grace extensions overwrote ExpiresAt, so a polled stale entry never hit MaxGracePeriod. The bound now uses the first expiry. SetMaxSize with a non-positive size spun the eviction loop forever. It now clamps to 1. One value larger than MaxMemoryBytes flushed every other entry and left the cache over its cap. The cache now drops that value. int64(float64) wrapped a far-future nbf or iat into the past, so the token passed. Non-finite and out-of-range claims now fail.
89 lines
2.5 KiB
Go
89 lines
2.5 KiB
Go
package traefikoidc
|
|
|
|
import (
|
|
"math"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func newBoundsCache(t *testing.T, cfg UniversalCacheConfig) *UniversalCache {
|
|
t.Helper()
|
|
cfg.CleanupInterval = time.Hour
|
|
if cfg.DefaultTTL == 0 {
|
|
cfg.DefaultTTL = time.Hour
|
|
}
|
|
c := NewUniversalCache(cfg)
|
|
t.Cleanup(func() { _ = c.Close() })
|
|
return c
|
|
}
|
|
|
|
// Grace extensions must stay within MaxGracePeriod of the ORIGINAL expiry.
|
|
func TestGraceNeverServesPastOriginalExpiryBound(t *testing.T) {
|
|
c := newBoundsCache(t, UniversalCacheConfig{
|
|
Type: CacheTypeMetadata, MaxSize: 10,
|
|
MetadataConfig: &MetadataCacheConfig{
|
|
GracePeriod: 20 * time.Millisecond, ExtendedGracePeriod: 20 * time.Millisecond,
|
|
MaxGracePeriod: 100 * time.Millisecond, SecurityCriticalMaxGracePeriod: 100 * time.Millisecond,
|
|
},
|
|
})
|
|
if err := c.Set("k", "v", 10*time.Millisecond); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
c.ActivateGracePeriod("k")
|
|
deadline := time.Now().Add(600 * time.Millisecond)
|
|
for time.Now().Before(deadline) {
|
|
time.Sleep(10 * time.Millisecond)
|
|
if _, ok := c.Get("k"); !ok {
|
|
return
|
|
}
|
|
}
|
|
t.Fatal("stale entry still served 600ms after a 100ms max grace")
|
|
}
|
|
|
|
func TestSetMaxSizeNegativeTerminates(t *testing.T) {
|
|
c := newBoundsCache(t, UniversalCacheConfig{Type: CacheTypeGeneral, MaxSize: 10})
|
|
for _, k := range []string{"a", "b", "c"} {
|
|
_ = c.Set(k, "v", time.Hour)
|
|
}
|
|
done := make(chan struct{})
|
|
go func() { c.SetMaxSize(-1); close(done) }()
|
|
select {
|
|
case <-done:
|
|
case <-time.After(2 * time.Second):
|
|
t.Fatal("SetMaxSize(-1) did not return")
|
|
}
|
|
}
|
|
|
|
// One oversized value must not flush the other live entries.
|
|
func TestOversizedValueDoesNotFlushCache(t *testing.T) {
|
|
c := newBoundsCache(t, UniversalCacheConfig{
|
|
Type: CacheTypeGeneral, MaxSize: 10, MaxMemoryBytes: 1000, EnableMemoryLimit: true,
|
|
})
|
|
_ = c.Set("live", "x", time.Hour)
|
|
_ = c.Set("big", make([]byte, 5000), time.Hour)
|
|
if _, ok := c.Get("live"); !ok {
|
|
t.Fatal("oversized insert evicted a live entry")
|
|
}
|
|
c.mu.RLock()
|
|
mem := c.currentMemory
|
|
c.mu.RUnlock()
|
|
if mem > 1000 {
|
|
t.Fatalf("currentMemory=%d exceeds cap 1000", mem)
|
|
}
|
|
}
|
|
|
|
// Out-of-range or non-finite nbf/iat must be rejected, not wrapped into the past.
|
|
func TestTimeClaimsRejectOutOfRange(t *testing.T) {
|
|
for _, v := range []float64{1e19, 1e300, math.Inf(1), math.Inf(-1), math.NaN()} {
|
|
if verifyNotBefore(v) == nil {
|
|
t.Errorf("nbf=%v accepted", v)
|
|
}
|
|
if verifyIssuedAt(v) == nil {
|
|
t.Errorf("iat=%v accepted", v)
|
|
}
|
|
if verifyExpiration(v) == nil {
|
|
t.Errorf("exp=%v accepted", v)
|
|
}
|
|
}
|
|
}
|