package cache import ( "context" "errors" "strings" "testing" "time" ) func TestConsumeFixedWindowFailsClosedWithoutRedis(t *testing.T) { _, err := (*Redis)(nil).ConsumeFixedWindow(context.Background(), time.Minute, []FixedWindowRule{{Key: "rate:{external-login}:system", Limit: 300}}) if !errors.Is(err, ErrRedisUnavailable) { t.Fatalf("error = %v, want ErrRedisUnavailable", err) } } func TestFixedWindowLuaConsumesAllKeysWithoutRenewingExistingTTL(t *testing.T) { // These source-level invariants protect the security semantics even when unit // tests run without a Redis daemon: all keys increment before the one final // return, and PEXPIRE remains inside count==1 so rejected requests never slide TTL. if strings.Count(fixedWindowScript, `redis.call("INCR"`) != 1 { t.Fatalf("fixed-window script must increment through one loop: %s", fixedWindowScript) } if !strings.Contains(fixedWindowScript, `if count == 1 then`) || !strings.Contains(fixedWindowScript, `redis.call("PEXPIRE"`) { t.Fatal("fixed-window script must assign expiry only on first increment") } if strings.Count(fixedWindowScript, "return {") != 1 { t.Fatal("fixed-window script must not return early before consuming all keys") } if strings.Index(fixedWindowScript, `redis.call("INCR"`) > strings.Index(fixedWindowScript, `if count > limit then`) { t.Fatal("fixed-window script must increment before deciding") } }