Some checks failed
Pipeline: Test, Lint, Build / Get version info (push) Has been cancelled
Pipeline: Test, Lint, Build / Lint Go code (push) Has been cancelled
Pipeline: Test, Lint, Build / Test Go code (push) Has been cancelled
Pipeline: Test, Lint, Build / Test JS code (push) Has been cancelled
Pipeline: Test, Lint, Build / Lint i18n files (push) Has been cancelled
Pipeline: Test, Lint, Build / Check Docker configuration (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (darwin/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (darwin/arm64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/386) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v5) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v6) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v7) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (windows/386) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (windows/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Push to GHCR (push) Has been cancelled
Pipeline: Test, Lint, Build / Push to Docker Hub (push) Has been cancelled
Pipeline: Test, Lint, Build / Cleanup digest artifacts (push) Has been cancelled
Pipeline: Test, Lint, Build / Build Windows installers (push) Has been cancelled
Pipeline: Test, Lint, Build / Package/Release (push) Has been cancelled
Pipeline: Test, Lint, Build / Upload Linux PKG (push) Has been cancelled
Close stale issues and PRs / stale (push) Has been cancelled
POEditor import / update-translations (push) Has been cancelled
162 lines
4.2 KiB
Go
162 lines
4.2 KiB
Go
package cache
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"time"
|
|
|
|
. "github.com/onsi/ginkgo/v2"
|
|
. "github.com/onsi/gomega"
|
|
)
|
|
|
|
var _ = Describe("SimpleCache", func() {
|
|
var (
|
|
cache SimpleCache[string, string]
|
|
)
|
|
|
|
BeforeEach(func() {
|
|
cache = NewSimpleCache[string, string]()
|
|
})
|
|
|
|
Describe("Add and Get", func() {
|
|
It("should add and retrieve a value", func() {
|
|
err := cache.Add("key", "value")
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
value, err := cache.Get("key")
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(value).To(Equal("value"))
|
|
})
|
|
})
|
|
|
|
Describe("AddWithTTL and Get", func() {
|
|
It("should add a value with TTL and retrieve it", func() {
|
|
err := cache.AddWithTTL("key", "value", 1*time.Minute)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
value, err := cache.Get("key")
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(value).To(Equal("value"))
|
|
})
|
|
|
|
It("should not retrieve a value after its TTL has expired", func() {
|
|
err := cache.AddWithTTL("key", "value", 10*time.Millisecond)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
time.Sleep(50 * time.Millisecond)
|
|
|
|
_, err = cache.Get("key")
|
|
Expect(err).To(HaveOccurred())
|
|
})
|
|
})
|
|
|
|
Describe("GetWithLoader", func() {
|
|
It("should retrieve a value using the loader function", func() {
|
|
loader := func(key string) (string, time.Duration, error) {
|
|
return fmt.Sprintf("%s=value", key), 1 * time.Minute, nil
|
|
}
|
|
|
|
value, err := cache.GetWithLoader("key", loader)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(value).To(Equal("key=value"))
|
|
})
|
|
|
|
It("should return the error returned by the loader function", func() {
|
|
loader := func(key string) (string, time.Duration, error) {
|
|
return "", 0, errors.New("some error")
|
|
}
|
|
|
|
_, err := cache.GetWithLoader("key", loader)
|
|
Expect(err).To(HaveOccurred())
|
|
})
|
|
})
|
|
|
|
Describe("Keys and Values", func() {
|
|
It("should return all keys and all values", func() {
|
|
err := cache.Add("key1", "value1")
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
err = cache.Add("key2", "value2")
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
keys := cache.Keys()
|
|
Expect(keys).To(ConsistOf("key1", "key2"))
|
|
|
|
values := cache.Values()
|
|
Expect(values).To(ConsistOf("value1", "value2"))
|
|
})
|
|
|
|
Context("when there are expired items in the cache", func() {
|
|
It("should not return expired items", func() {
|
|
Expect(cache.Add("key0", "value0")).To(Succeed())
|
|
for i := 1; i <= 3; i++ {
|
|
err := cache.AddWithTTL(fmt.Sprintf("key%d", i), fmt.Sprintf("value%d", i), 10*time.Millisecond)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
}
|
|
|
|
time.Sleep(50 * time.Millisecond)
|
|
|
|
Expect(cache.Keys()).To(ConsistOf("key0"))
|
|
Expect(cache.Values()).To(ConsistOf("value0"))
|
|
})
|
|
})
|
|
})
|
|
|
|
Describe("Options", func() {
|
|
Context("when size limit is set", func() {
|
|
BeforeEach(func() {
|
|
cache = NewSimpleCache[string, string](Options{
|
|
SizeLimit: 2,
|
|
})
|
|
})
|
|
|
|
It("should drop the oldest item when the size limit is reached", func() {
|
|
for i := 1; i <= 3; i++ {
|
|
err := cache.Add(fmt.Sprintf("key%d", i), fmt.Sprintf("value%d", i))
|
|
Expect(err).NotTo(HaveOccurred())
|
|
}
|
|
|
|
Expect(cache.Keys()).To(ConsistOf("key2", "key3"))
|
|
})
|
|
})
|
|
|
|
Context("when default TTL is set", func() {
|
|
BeforeEach(func() {
|
|
cache = NewSimpleCache[string, string](Options{
|
|
DefaultTTL: 10 * time.Millisecond,
|
|
})
|
|
})
|
|
|
|
It("should expire items after the default TTL", func() {
|
|
Expect(cache.AddWithTTL("key0", "value0", 1*time.Minute)).To(Succeed())
|
|
for i := 1; i <= 3; i++ {
|
|
err := cache.Add(fmt.Sprintf("key%d", i), fmt.Sprintf("value%d", i))
|
|
Expect(err).NotTo(HaveOccurred())
|
|
}
|
|
|
|
time.Sleep(50 * time.Millisecond)
|
|
|
|
for i := 1; i <= 3; i++ {
|
|
_, err := cache.Get(fmt.Sprintf("key%d", i))
|
|
Expect(err).To(HaveOccurred())
|
|
}
|
|
Expect(cache.Get("key0")).To(Equal("value0"))
|
|
})
|
|
})
|
|
|
|
Describe("OnExpiration", func() {
|
|
It("should call callback when item expires", func() {
|
|
cache = NewSimpleCache[string, string]()
|
|
expired := make(chan struct{})
|
|
cache.OnExpiration(func(k, v string) { close(expired) })
|
|
Expect(cache.AddWithTTL("key", "value", 10*time.Millisecond)).To(Succeed())
|
|
select {
|
|
case <-expired:
|
|
case <-time.After(100 * time.Millisecond):
|
|
Fail("expiration callback not called")
|
|
}
|
|
})
|
|
})
|
|
})
|
|
})
|