Files
capsule/internal/cache/quantities_test.go
T
cc4fb45d70 feat: upstream enterprise preview (#1841)
feat: upstream enterprise preview

---------

Signed-off-by: Oliver Baehler <oliver@sudo-i.net>
Co-authored-by: CorentinPtrl <pitrel.corentin@gmail.com>
2026-05-28 00:58:58 +02:00

439 lines
13 KiB
Go

// Copyright 2020-2026 Project Capsule Authors
// SPDX-License-Identifier: Apache-2.0
package cache
import (
"sync"
"sync/atomic"
"time"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/apimachinery/pkg/types"
)
var _ = Describe("QuantityCache", func() {
var (
c *QuantityCache[string]
now time.Time
key string
limit resource.Quantity
used resource.Quantity
)
reservation := func(id string, qty string) Reservation {
return Reservation{
ID: id,
Usage: resource.MustParse(qty),
UID: types.UID("uid-" + id),
Group: "",
Version: "v1",
Kind: "Pod",
Namespace: "default",
Name: "pod-" + id,
}
}
BeforeEach(func() {
now = time.Date(2026, 4, 28, 12, 0, 0, 0, time.UTC)
c = NewQuantityCache[string]()
c.clock = func() time.Time { return now }
key = "quota-a"
limit = resource.MustParse("5")
used = resource.MustParse("0")
})
It("returns false for missing entries", func() {
entry, ok := c.Get(key)
Expect(ok).To(BeFalse())
Expect(entry.Reservations).To(BeNil())
Expect(entry.PendingDeletes).To(BeNil())
Expect(entry.Reserved.IsZero()).To(BeTrue())
})
It("creates a reservation when allowed", func() {
allowed, effectiveUsed, entry := c.UpsertReservation(key, reservation("a", "1"), used, limit)
Expect(allowed).To(BeTrue())
Expect(effectiveUsed.Cmp(resource.MustParse("1"))).To(Equal(0))
Expect(entry.Reserved.Cmp(resource.MustParse("1"))).To(Equal(0))
Expect(entry.Reservations).To(HaveLen(1))
Expect(entry.Reservations["a"].CreatedAt).To(Equal(now))
Expect(entry.Reservations["a"].UpdatedAt).To(Equal(now))
Expect(c.Len()).To(Equal(1))
})
It("rejects a reservation when it would exceed the limit", func() {
allowed, effectiveUsed, entry := c.UpsertReservation(
key,
reservation("a", "2"),
resource.MustParse("4"),
resource.MustParse("5"),
)
Expect(allowed).To(BeFalse())
Expect(effectiveUsed.Cmp(resource.MustParse("4"))).To(Equal(0))
Expect(entry.Reserved.IsZero()).To(BeTrue())
Expect(c.Len()).To(Equal(0))
})
It("keeps existing reservations unchanged when a new reservation is rejected", func() {
allowed, _, _ := c.UpsertReservation(key, reservation("a", "2"), used, limit)
Expect(allowed).To(BeTrue())
allowed, effectiveUsed, entry := c.UpsertReservation(
key,
reservation("b", "4"),
used,
limit,
)
Expect(allowed).To(BeFalse())
Expect(effectiveUsed.Cmp(resource.MustParse("2"))).To(Equal(0))
Expect(entry.Reserved.Cmp(resource.MustParse("2"))).To(Equal(0))
Expect(entry.Reservations).To(HaveLen(1))
Expect(entry.Reservations).To(HaveKey("a"))
stored, ok := c.Get(key)
Expect(ok).To(BeTrue())
Expect(stored.Reserved.Cmp(resource.MustParse("2"))).To(Equal(0))
Expect(stored.Reservations).To(HaveLen(1))
})
It("is idempotent for the same reservation identity and usage", func() {
allowed, _, first := c.UpsertReservation(key, reservation("a", "1"), used, limit)
Expect(allowed).To(BeTrue())
now = now.Add(time.Minute)
allowed, effectiveUsed, second := c.UpsertReservation(key, reservation("a", "1"), used, limit)
Expect(allowed).To(BeTrue())
Expect(effectiveUsed.Cmp(resource.MustParse("1"))).To(Equal(0))
Expect(second.Reserved.Cmp(resource.MustParse("1"))).To(Equal(0))
Expect(second.Reservations).To(HaveLen(1))
Expect(second.Reservations["a"].CreatedAt).To(Equal(first.Reservations["a"].CreatedAt))
Expect(second.Reservations["a"].UpdatedAt).To(Equal(first.Reservations["a"].UpdatedAt))
Expect(second.LastAccess).To(Equal(now))
})
It("updates an existing reservation when usage changes", func() {
allowed, _, first := c.UpsertReservation(key, reservation("a", "1"), used, limit)
Expect(allowed).To(BeTrue())
now = now.Add(time.Minute)
allowed, effectiveUsed, second := c.UpsertReservation(key, reservation("a", "3"), used, limit)
Expect(allowed).To(BeTrue())
Expect(effectiveUsed.Cmp(resource.MustParse("3"))).To(Equal(0))
Expect(second.Reserved.Cmp(resource.MustParse("3"))).To(Equal(0))
Expect(second.Reservations).To(HaveLen(1))
Expect(second.Reservations["a"].CreatedAt).To(Equal(first.Reservations["a"].CreatedAt))
Expect(second.Reservations["a"].UpdatedAt).To(Equal(now))
})
It("updates an existing reservation when object identity changes", func() {
res := reservation("a", "1")
allowed, _, first := c.UpsertReservation(key, res, used, limit)
Expect(allowed).To(BeTrue())
now = now.Add(time.Minute)
res.Name = "renamed-pod"
allowed, _, second := c.UpsertReservation(key, res, used, limit)
Expect(allowed).To(BeTrue())
Expect(second.Reservations["a"].Name).To(Equal("renamed-pod"))
Expect(second.Reservations["a"].CreatedAt).To(Equal(first.Reservations["a"].CreatedAt))
Expect(second.Reservations["a"].UpdatedAt).To(Equal(now))
})
It("returns defensive copies from Get", func() {
allowed, _, _ := c.UpsertReservation(key, reservation("a", "1"), used, limit)
Expect(allowed).To(BeTrue())
entry, ok := c.Get(key)
Expect(ok).To(BeTrue())
entry.Reserved = resource.MustParse("999")
entry.Reservations["a"] = reservation("mutated", "999")
entry.PendingDeletes = append(entry.PendingDeletes, PendingDeleteHint{UID: "fake"})
again, ok := c.Get(key)
Expect(ok).To(BeTrue())
Expect(again.Reserved.Cmp(resource.MustParse("1"))).To(Equal(0))
Expect(again.Reservations).To(HaveKey("a"))
Expect(again.Reservations).NotTo(HaveKey("mutated"))
Expect(again.PendingDeletes).To(BeEmpty())
})
It("returns defensive copies from Snapshot", func() {
allowed, _, _ := c.UpsertReservation(key, reservation("a", "1"), used, limit)
Expect(allowed).To(BeTrue())
snap := c.Snapshot()
snap[key] = QuantityEntry{
Reserved: resource.MustParse("999"),
}
entry, ok := c.Get(key)
Expect(ok).To(BeTrue())
Expect(entry.Reserved.Cmp(resource.MustParse("1"))).To(Equal(0))
})
It("deletes entries", func() {
allowed, _, _ := c.UpsertReservation(key, reservation("a", "1"), used, limit)
Expect(allowed).To(BeTrue())
Expect(c.Delete(key)).To(BeTrue())
Expect(c.Delete(key)).To(BeFalse())
Expect(c.Len()).To(Equal(0))
})
It("deletes reservations and removes empty entries", func() {
allowed, _, _ := c.UpsertReservation(key, reservation("a", "1"), used, limit)
Expect(allowed).To(BeTrue())
Expect(c.DeleteReservation(key, "a")).To(BeTrue())
Expect(c.Len()).To(Equal(0))
_, ok := c.Get(key)
Expect(ok).To(BeFalse())
})
It("deletes only the selected reservation and recomputes reserved", func() {
Expect(c.UpsertReservation(key, reservation("a", "1"), used, limit)).To(ReceiveAllowed())
Expect(c.UpsertReservation(key, reservation("b", "2"), used, limit)).To(ReceiveAllowed())
Expect(c.DeleteReservation(key, "a")).To(BeTrue())
entry, ok := c.Get(key)
Expect(ok).To(BeTrue())
Expect(entry.Reserved.Cmp(resource.MustParse("2"))).To(Equal(0))
Expect(entry.Reservations).To(HaveKey("b"))
Expect(entry.Reservations).NotTo(HaveKey("a"))
})
It("returns false when deleting a missing reservation", func() {
Expect(c.DeleteReservation(key, "missing")).To(BeFalse())
allowed, _, _ := c.UpsertReservation(key, reservation("a", "1"), used, limit)
Expect(allowed).To(BeTrue())
Expect(c.DeleteReservation(key, "missing")).To(BeFalse())
})
It("purges reservations for a key", func() {
Expect(c.UpsertReservation(key, reservation("a", "1"), used, limit)).To(ReceiveAllowed())
Expect(c.UpsertReservation(key, reservation("b", "2"), used, limit)).To(ReceiveAllowed())
Expect(c.UpsertReservation(key, reservation("c", "1"), used, limit)).To(ReceiveAllowed())
deleted := c.PurgeReservationsForKey(key, func(r Reservation) bool {
return r.ID == "a" || r.ID == "c"
})
Expect(deleted).To(Equal(2))
entry, ok := c.Get(key)
Expect(ok).To(BeTrue())
Expect(entry.Reserved.Cmp(resource.MustParse("2"))).To(Equal(0))
Expect(entry.Reservations).To(HaveLen(1))
Expect(entry.Reservations).To(HaveKey("b"))
})
It("purges all reservations and removes entry when no pending deletes remain", func() {
Expect(c.UpsertReservation(key, reservation("a", "1"), used, limit)).To(ReceiveAllowed())
deleted := c.PurgeReservationsForKey(key, func(r Reservation) bool {
return true
})
Expect(deleted).To(Equal(1))
Expect(c.Len()).To(Equal(0))
})
It("does not remove entry after purging all reservations if pending deletes remain", func() {
Expect(c.UpsertReservation(key, reservation("a", "1"), used, limit)).To(ReceiveAllowed())
c.AddPendingDelete(key, "uid-a")
deleted := c.PurgeReservationsForKey(key, func(r Reservation) bool {
return true
})
Expect(deleted).To(Equal(1))
entry, ok := c.Get(key)
Expect(ok).To(BeTrue())
Expect(entry.Reserved.IsZero()).To(BeTrue())
Expect(entry.PendingDeletes).To(HaveLen(1))
})
It("returns zero when purging a missing key or no reservation matches", func() {
Expect(c.PurgeReservationsForKey("missing", func(r Reservation) bool { return true })).To(Equal(0))
Expect(c.UpsertReservation(key, reservation("a", "1"), used, limit)).To(ReceiveAllowed())
Expect(c.PurgeReservationsForKey(key, func(r Reservation) bool { return false })).To(Equal(0))
})
It("adds pending deletes idempotently", func() {
c.AddPendingDelete(key, "uid-a")
c.AddPendingDelete(key, "uid-a")
Expect(c.HasPendingDeletes(key)).To(BeTrue())
Expect(c.PendingDeletes(key)).To(Equal([]types.UID{"uid-a"}))
entry, ok := c.Get(key)
Expect(ok).To(BeTrue())
Expect(entry.PendingDeletes[0].CreatedAt).To(Equal(now))
})
It("ignores empty pending delete UIDs", func() {
c.AddPendingDelete(key, "")
Expect(c.Len()).To(Equal(0))
Expect(c.PendingDeletes(key)).To(BeNil())
})
It("removes pending deletes and removes empty entry", func() {
c.AddPendingDelete(key, "uid-a")
Expect(c.RemovePendingDelete(key, "uid-a")).To(BeTrue())
Expect(c.RemovePendingDelete(key, "uid-a")).To(BeFalse())
Expect(c.Len()).To(Equal(0))
})
It("removes pending delete but keeps entry when reservations remain", func() {
Expect(c.UpsertReservation(key, reservation("a", "1"), used, limit)).To(ReceiveAllowed())
c.AddPendingDelete(key, "uid-a")
Expect(c.RemovePendingDelete(key, "uid-a")).To(BeTrue())
entry, ok := c.Get(key)
Expect(ok).To(BeTrue())
Expect(entry.Reserved.Cmp(resource.MustParse("1"))).To(Equal(0))
Expect(entry.PendingDeletes).To(BeEmpty())
})
It("returns nil pending deletes for missing keys", func() {
Expect(c.PendingDeletes("missing")).To(BeNil())
Expect(c.HasPendingDeletes("missing")).To(BeFalse())
})
It("clamps negative reserved totals to zero", func() {
Expect(c.UpsertReservation(key, reservation("a", "-5"), used, limit)).To(ReceiveAllowed())
entry, ok := c.Get(key)
Expect(ok).To(BeTrue())
Expect(entry.Reserved.IsZero()).To(BeTrue())
})
It("is safe under concurrent reservation upserts", func() {
const workers = 32
c.clock = time.Now
limit := resource.MustParse("100")
var allowedCount atomic.Int32
start := make(chan struct{})
var wg sync.WaitGroup
wg.Add(workers)
for i := 0; i < workers; i++ {
i := i
go func() {
defer GinkgoRecover()
defer wg.Done()
<-start
allowed, _, _ := c.UpsertReservation(
key,
reservation(string(rune('a'+i)), "1"),
resource.MustParse("0"),
limit,
)
if allowed {
allowedCount.Add(1)
}
}()
}
close(start)
wg.Wait()
Expect(allowedCount.Load()).To(Equal(int32(workers)))
entry, ok := c.Get(key)
Expect(ok).To(BeTrue())
Expect(entry.Reservations).To(HaveLen(workers))
Expect(entry.Reserved.Cmp(resource.MustParse("32"))).To(Equal(0))
})
It("enforces limit under concurrent reservation upserts", func() {
const workers = 16
c.clock = time.Now
limit := resource.MustParse("5")
var allowedCount atomic.Int32
start := make(chan struct{})
var wg sync.WaitGroup
wg.Add(workers)
for i := 0; i < workers; i++ {
i := i
go func() {
defer GinkgoRecover()
defer wg.Done()
<-start
allowed, _, _ := c.UpsertReservation(
key,
reservation(string(rune('a'+i)), "1"),
resource.MustParse("0"),
limit,
)
if allowed {
allowedCount.Add(1)
}
}()
}
close(start)
wg.Wait()
Expect(allowedCount.Load()).To(Equal(int32(5)))
entry, ok := c.Get(key)
Expect(ok).To(BeTrue())
Expect(entry.Reservations).To(HaveLen(5))
Expect(entry.Reserved.Cmp(resource.MustParse("5"))).To(Equal(0))
})
})
type quantityResult struct {
allowed bool
effectiveUsed resource.Quantity
entry QuantityEntry
}
func ReceiveAllowed() OmegaMatcher {
return WithTransform(func(in any) bool {
switch v := in.(type) {
case quantityResult:
return v.allowed
default:
return false
}
}, BeTrue())
}