mirror of
https://github.com/projectcapsule/capsule.git
synced 2026-08-19 20:46:42 +00:00
feat: upstream enterprise preview --------- Signed-off-by: Oliver Baehler <oliver@sudo-i.net> Co-authored-by: CorentinPtrl <pitrel.corentin@gmail.com>
186 lines
4.2 KiB
Go
186 lines
4.2 KiB
Go
// Copyright 2020-2026 Project Capsule Authors
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package cache
|
|
|
|
import (
|
|
"sync"
|
|
"sync/atomic"
|
|
|
|
. "github.com/onsi/ginkgo/v2"
|
|
. "github.com/onsi/gomega"
|
|
)
|
|
|
|
var _ = Describe("JSONPathCache", func() {
|
|
var c *JSONPathCache
|
|
|
|
BeforeEach(func() {
|
|
c = NewJSONPathCache()
|
|
})
|
|
|
|
It("returns false when path is missing", func() {
|
|
value, ok := c.Get(".spec.missing")
|
|
|
|
Expect(ok).To(BeFalse())
|
|
Expect(value).To(BeNil())
|
|
})
|
|
|
|
It("compiles and stores a JSONPath", func() {
|
|
compiled, err := c.GetOrCompile(".spec.containers[*].resources.requests.cpu")
|
|
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(compiled).NotTo(BeNil())
|
|
Expect(c.Stats()).To(Equal(1))
|
|
|
|
cached, ok := c.Get(".spec.containers[*].resources.requests.cpu")
|
|
Expect(ok).To(BeTrue())
|
|
Expect(cached).To(BeIdenticalTo(compiled))
|
|
})
|
|
|
|
It("returns the cached instance on repeated GetOrCompile calls", func() {
|
|
first, err := c.GetOrCompile(".spec.resources.requests.storage")
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
second, err := c.GetOrCompile(".spec.resources.requests.storage")
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
Expect(second).To(BeIdenticalTo(first))
|
|
Expect(c.Stats()).To(Equal(1))
|
|
})
|
|
|
|
It("does not store invalid JSONPath expressions", func() {
|
|
compiled, err := c.GetOrCompile(".spec.containers[?(")
|
|
|
|
Expect(err).To(HaveOccurred())
|
|
Expect(compiled).To(BeNil())
|
|
Expect(c.Stats()).To(Equal(0))
|
|
|
|
_, ok := c.Get(".spec.containers[?(")
|
|
Expect(ok).To(BeFalse())
|
|
})
|
|
|
|
It("deletes an existing path", func() {
|
|
_, err := c.GetOrCompile(".spec.replicas")
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
Expect(c.Delete(".spec.replicas")).To(BeTrue())
|
|
Expect(c.Delete(".spec.replicas")).To(BeFalse())
|
|
|
|
_, ok := c.Get(".spec.replicas")
|
|
Expect(ok).To(BeFalse())
|
|
Expect(c.Stats()).To(Equal(0))
|
|
})
|
|
|
|
It("deletes many paths and ignores missing or empty expressions", func() {
|
|
_, err := c.GetOrCompile(".spec.a")
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
_, err = c.GetOrCompile(".spec.b")
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
_, err = c.GetOrCompile(".spec.c")
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
deleted := c.DeleteMany(".spec.a", "", ".spec.missing", ".spec.c")
|
|
|
|
Expect(deleted).To(Equal(2))
|
|
Expect(c.Stats()).To(Equal(1))
|
|
|
|
_, ok := c.Get(".spec.a")
|
|
Expect(ok).To(BeFalse())
|
|
|
|
_, ok = c.Get(".spec.b")
|
|
Expect(ok).To(BeTrue())
|
|
|
|
_, ok = c.Get(".spec.c")
|
|
Expect(ok).To(BeFalse())
|
|
})
|
|
|
|
It("resets all compiled paths", func() {
|
|
_, err := c.GetOrCompile(".spec.a")
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
_, err = c.GetOrCompile(".spec.b")
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
Expect(c.Stats()).To(Equal(2))
|
|
|
|
c.Reset()
|
|
|
|
Expect(c.Stats()).To(Equal(0))
|
|
|
|
_, ok := c.Get(".spec.a")
|
|
Expect(ok).To(BeFalse())
|
|
})
|
|
|
|
It("prunes inactive paths", func() {
|
|
_, err := c.GetOrCompile(".spec.a")
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
_, err = c.GetOrCompile(".spec.b")
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
_, err = c.GetOrCompile(".spec.c")
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
pruned := c.PruneActive(map[string]struct{}{
|
|
".spec.a": {},
|
|
".spec.c": {},
|
|
})
|
|
|
|
Expect(pruned).To(Equal(1))
|
|
Expect(c.Stats()).To(Equal(2))
|
|
|
|
_, ok := c.Get(".spec.a")
|
|
Expect(ok).To(BeTrue())
|
|
|
|
_, ok = c.Get(".spec.b")
|
|
Expect(ok).To(BeFalse())
|
|
|
|
_, ok = c.Get(".spec.c")
|
|
Expect(ok).To(BeTrue())
|
|
})
|
|
|
|
It("prunes all paths when active set is empty", func() {
|
|
_, err := c.GetOrCompile(".spec.a")
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
_, err = c.GetOrCompile(".spec.b")
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
Expect(c.PruneActive(map[string]struct{}{})).To(Equal(2))
|
|
Expect(c.Stats()).To(Equal(0))
|
|
})
|
|
|
|
It("is safe under concurrent GetOrCompile calls for the same path", func() {
|
|
const workers = 32
|
|
|
|
var successes atomic.Int32
|
|
start := make(chan struct{})
|
|
|
|
var wg sync.WaitGroup
|
|
wg.Add(workers)
|
|
|
|
for i := 0; i < workers; i++ {
|
|
go func() {
|
|
defer GinkgoRecover()
|
|
defer wg.Done()
|
|
|
|
<-start
|
|
|
|
compiled, err := c.GetOrCompile(".spec.containers[*].resources.requests.cpu")
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(compiled).NotTo(BeNil())
|
|
|
|
successes.Add(1)
|
|
}()
|
|
}
|
|
|
|
close(start)
|
|
wg.Wait()
|
|
|
|
Expect(successes.Load()).To(Equal(int32(workers)))
|
|
Expect(c.Stats()).To(Equal(1))
|
|
})
|
|
})
|