Skip to content

Commit 5ac4da4

Browse files
Add cache tests
1 parent 6bcbc2e commit 5ac4da4

5 files changed

Lines changed: 792 additions & 0 deletions

File tree

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ require (
2525
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0 // indirect
2626
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0 // indirect
2727
github.com/MicahParks/keyfunc v1.9.0 // indirect
28+
github.com/alicebob/miniredis/v2 v2.35.0 // indirect
2829
github.com/cespare/xxhash/v2 v2.3.0 // indirect
2930
github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 // indirect
3031
github.com/davecgh/go-spew v1.1.1 // indirect
@@ -45,6 +46,7 @@ require (
4546
github.com/pmezard/go-difflib v1.0.0 // indirect
4647
github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect
4748
github.com/stretchr/objx v0.5.2 // indirect
49+
github.com/yuin/gopher-lua v1.1.1 // indirect
4850
github.com/zeebo/errs v1.4.0 // indirect
4951
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
5052
go.opentelemetry.io/contrib/detectors/gcp v1.36.0 // indirect

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapp
3434
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0/go.mod h1:otE2jQekW/PqXk1Awf5lmfokJx4uwuqcj1ab5SpGeW0=
3535
github.com/MicahParks/keyfunc v1.9.0 h1:lhKd5xrFHLNOWrDc4Tyb/Q1AJ4LCzQ48GVJyVIID3+o=
3636
github.com/MicahParks/keyfunc v1.9.0/go.mod h1:IdnCilugA0O/99dW+/MkvlyrsX8+L8+x95xuVNtM5jw=
37+
github.com/alicebob/miniredis/v2 v2.35.0 h1:QwLphYqCEAo1eu1TqPRN2jgVMPBweeQcR21jeqDCONI=
38+
github.com/alicebob/miniredis/v2 v2.35.0/go.mod h1:TcL7YfarKPGDAthEtl5NBeHZfeUQj6OXMm/+iu5cLMM=
3739
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
3840
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
3941
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
@@ -101,6 +103,8 @@ github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/
101103
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
102104
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
103105
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
106+
github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M=
107+
github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
104108
github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM=
105109
github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4=
106110
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=

internal/cache/factory_test.go

Lines changed: 288 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,288 @@
1+
package cache
2+
3+
import (
4+
"testing"
5+
"time"
6+
7+
"authguard/internal/auth"
8+
"github.com/alicebob/miniredis/v2"
9+
"github.com/stretchr/testify/assert"
10+
"github.com/stretchr/testify/mock"
11+
)
12+
13+
// MockLogger implements the Logger interface for testing
14+
type MockLogger struct {
15+
mock.Mock
16+
}
17+
18+
func (m *MockLogger) Info(msg string, keysAndValues ...any) {
19+
args := []any{msg}
20+
args = append(args, keysAndValues...)
21+
m.Called(args...)
22+
}
23+
24+
func (m *MockLogger) Debug(msg string, keysAndValues ...any) {
25+
args := []any{msg}
26+
args = append(args, keysAndValues...)
27+
m.Called(args...)
28+
}
29+
30+
func (m *MockLogger) Error(msg string, keysAndValues ...any) {
31+
args := []any{msg}
32+
args = append(args, keysAndValues...)
33+
m.Called(args...)
34+
}
35+
36+
func (m *MockLogger) Warn(msg string, keysAndValues ...any) {
37+
args := []any{msg}
38+
args = append(args, keysAndValues...)
39+
m.Called(args...)
40+
}
41+
42+
func (m *MockLogger) With(keysAndValues ...any) auth.Logger {
43+
args := m.Called(keysAndValues)
44+
return args.Get(0).(auth.Logger)
45+
}
46+
47+
func TestNewCache(t *testing.T) {
48+
t.Run("Memory cache type", func(t *testing.T) {
49+
mockLogger := &MockLogger{}
50+
mockLogger.On("Info", "initializing memory cache", "max_keys", 1000, "cleanup_interval", 10*time.Minute)
51+
mockLogger.On("Info", "memory cache initialized successfully")
52+
53+
config := auth.CacheConfig{
54+
Type: auth.CacheTypeMemory,
55+
MaxKeys: 1000,
56+
CleanupInterval: 10 * time.Minute,
57+
}
58+
59+
cache, err := NewCache(config, mockLogger)
60+
61+
assert.NoError(t, err)
62+
assert.NotNil(t, cache)
63+
64+
// Verify it's a memory cache
65+
memCache, ok := cache.(*MemoryCache)
66+
assert.True(t, ok)
67+
assert.Equal(t, 1000, memCache.maxKeys)
68+
69+
_ = cache.Close()
70+
mockLogger.AssertExpectations(t)
71+
})
72+
73+
t.Run("Redis cache type with empty URL", func(t *testing.T) {
74+
mockLogger := &MockLogger{}
75+
mockLogger.On("Info", "Redis URL not configured, falling back to memory cache")
76+
mockLogger.On("Info", "initializing memory cache", "max_keys", 500, "cleanup_interval", 5*time.Minute)
77+
mockLogger.On("Info", "memory cache initialized successfully")
78+
79+
config := auth.CacheConfig{
80+
Type: auth.CacheTypeRedis,
81+
RedisURL: "", // Empty URL should fallback to memory
82+
MaxKeys: 500,
83+
CleanupInterval: 5 * time.Minute,
84+
}
85+
86+
cache, err := NewCache(config, mockLogger)
87+
88+
assert.NoError(t, err)
89+
assert.NotNil(t, cache)
90+
91+
// Should fallback to memory cache
92+
_, ok := cache.(*MemoryCache)
93+
assert.True(t, ok)
94+
95+
_ = cache.Close()
96+
mockLogger.AssertExpectations(t)
97+
})
98+
99+
t.Run("Redis cache type with invalid URL", func(t *testing.T) {
100+
mockLogger := &MockLogger{}
101+
mockLogger.On("Info", "attempting to connect to Redis", "url", "invalid-redis-url", "db", 0)
102+
mockLogger.On("Warn", "failed to connect to Redis, falling back to memory cache", "error", mock.AnythingOfType("*fmt.wrapError"))
103+
mockLogger.On("Info", "initializing memory cache", "max_keys", 1000, "cleanup_interval", 10*time.Minute)
104+
mockLogger.On("Info", "memory cache initialized successfully")
105+
106+
config := auth.CacheConfig{
107+
Type: auth.CacheTypeRedis,
108+
RedisURL: "invalid-redis-url",
109+
RedisPassword: "password",
110+
RedisDB: 0,
111+
MaxKeys: 1000,
112+
CleanupInterval: 10 * time.Minute,
113+
}
114+
115+
cache, err := NewCache(config, mockLogger)
116+
117+
assert.NoError(t, err)
118+
assert.NotNil(t, cache)
119+
120+
// Should fallback to memory cache due to connection failure
121+
_, ok := cache.(*MemoryCache)
122+
assert.True(t, ok)
123+
124+
_ = cache.Close()
125+
mockLogger.AssertExpectations(t)
126+
})
127+
128+
t.Run("Unknown cache type", func(t *testing.T) {
129+
mockLogger := &MockLogger{}
130+
mockLogger.On("Warn", "unknown cache type, defaulting to memory", "type", auth.CacheType(999))
131+
mockLogger.On("Info", "initializing memory cache", "max_keys", 1000, "cleanup_interval", 10*time.Minute)
132+
mockLogger.On("Info", "memory cache initialized successfully")
133+
134+
config := auth.CacheConfig{
135+
Type: auth.CacheType(999), // Invalid cache type
136+
MaxKeys: 1000,
137+
CleanupInterval: 10 * time.Minute,
138+
}
139+
140+
cache, err := NewCache(config, mockLogger)
141+
142+
assert.NoError(t, err)
143+
assert.NotNil(t, cache)
144+
145+
// Should default to memory cache
146+
_, ok := cache.(*MemoryCache)
147+
assert.True(t, ok)
148+
149+
_ = cache.Close()
150+
mockLogger.AssertExpectations(t)
151+
})
152+
}
153+
154+
func TestCreateRedisCache(t *testing.T) {
155+
t.Run("Empty Redis URL", func(t *testing.T) {
156+
mockLogger := &MockLogger{}
157+
mockLogger.On("Info", "Redis URL not configured, falling back to memory cache")
158+
mockLogger.On("Info", "initializing memory cache", "max_keys", 1000, "cleanup_interval", 10*time.Minute)
159+
mockLogger.On("Info", "memory cache initialized successfully")
160+
161+
config := auth.CacheConfig{
162+
RedisURL: "",
163+
MaxKeys: 1000,
164+
CleanupInterval: 10 * time.Minute,
165+
}
166+
167+
cache, err := createRedisCache(config, mockLogger)
168+
169+
assert.NoError(t, err)
170+
assert.NotNil(t, cache)
171+
172+
// Should be memory cache
173+
_, ok := cache.(*MemoryCache)
174+
assert.True(t, ok)
175+
176+
_ = cache.Close()
177+
mockLogger.AssertExpectations(t)
178+
})
179+
180+
t.Run("Invalid Redis URL", func(t *testing.T) {
181+
mockLogger := &MockLogger{}
182+
mockLogger.On("Info", "attempting to connect to Redis", "url", "invalid-url", "db", 0)
183+
mockLogger.On("Warn", "failed to connect to Redis, falling back to memory cache", "error", mock.AnythingOfType("*fmt.wrapError"))
184+
mockLogger.On("Info", "initializing memory cache", "max_keys", 1000, "cleanup_interval", 10*time.Minute)
185+
mockLogger.On("Info", "memory cache initialized successfully")
186+
187+
config := auth.CacheConfig{
188+
RedisURL: "invalid-url",
189+
RedisPassword: "test",
190+
RedisDB: 0,
191+
MaxKeys: 1000,
192+
CleanupInterval: 10 * time.Minute,
193+
}
194+
195+
cache, err := createRedisCache(config, mockLogger)
196+
197+
assert.NoError(t, err)
198+
assert.NotNil(t, cache)
199+
200+
// Should fallback to memory cache
201+
_, ok := cache.(*MemoryCache)
202+
assert.True(t, ok)
203+
204+
_ = cache.Close()
205+
mockLogger.AssertExpectations(t)
206+
})
207+
208+
t.Run("Successful Redis connection", func(t *testing.T) {
209+
// Use miniredis for real Redis connection test
210+
s := miniredis.RunT(t)
211+
defer s.Close()
212+
213+
mockLogger := &MockLogger{}
214+
mockLogger.On("Info", "attempting to connect to Redis", "url", "redis://"+s.Addr(), "db", 0)
215+
mockLogger.On("Info", "Redis cache initialized successfully")
216+
217+
config := auth.CacheConfig{
218+
RedisURL: "redis://" + s.Addr(),
219+
RedisPassword: "",
220+
RedisDB: 0,
221+
MaxKeys: 1000,
222+
CleanupInterval: 10 * time.Minute,
223+
}
224+
225+
cache, err := createRedisCache(config, mockLogger)
226+
227+
assert.NoError(t, err)
228+
assert.NotNil(t, cache)
229+
230+
// Should be Redis cache, not memory fallback
231+
_, ok := cache.(*RedisCache)
232+
assert.True(t, ok)
233+
234+
_ = cache.Close()
235+
mockLogger.AssertExpectations(t)
236+
})
237+
}
238+
239+
func TestCreateMemoryCache(t *testing.T) {
240+
t.Run("Valid configuration", func(t *testing.T) {
241+
mockLogger := &MockLogger{}
242+
mockLogger.On("Info", "initializing memory cache", "max_keys", 500, "cleanup_interval", 5*time.Minute)
243+
mockLogger.On("Info", "memory cache initialized successfully")
244+
245+
config := auth.CacheConfig{
246+
MaxKeys: 500,
247+
CleanupInterval: 5 * time.Minute,
248+
}
249+
250+
cache, err := createMemoryCache(config, mockLogger)
251+
252+
assert.NoError(t, err)
253+
assert.NotNil(t, cache)
254+
255+
memCache, ok := cache.(*MemoryCache)
256+
assert.True(t, ok)
257+
assert.Equal(t, 500, memCache.maxKeys)
258+
259+
_ = cache.Close()
260+
mockLogger.AssertExpectations(t)
261+
})
262+
263+
t.Run("Invalid memory cache config", func(t *testing.T) {
264+
mockLogger := &MockLogger{}
265+
mockLogger.On("Info", "initializing memory cache", "max_keys", -100, "cleanup_interval", time.Duration(-1))
266+
mockLogger.On("Info", "memory cache initialized successfully")
267+
268+
config := auth.CacheConfig{
269+
MaxKeys: -100, // Invalid
270+
CleanupInterval: time.Duration(-1), // Invalid
271+
}
272+
273+
cache, err := createMemoryCache(config, mockLogger)
274+
275+
// Should still work due to defaults in NewMemoryCache
276+
assert.NoError(t, err)
277+
assert.NotNil(t, cache)
278+
279+
memCache, ok := cache.(*MemoryCache)
280+
assert.True(t, ok)
281+
// Should use defaults
282+
assert.Equal(t, 1000, memCache.maxKeys)
283+
assert.Equal(t, 10*time.Minute, memCache.janitor.interval)
284+
285+
_ = cache.Close()
286+
mockLogger.AssertExpectations(t)
287+
})
288+
}

0 commit comments

Comments
 (0)