Skip to content

Commit 4031eae

Browse files
committed
feat: Add error handling and test for database open failures in cache
1 parent 3111be8 commit 4031eae

File tree

3 files changed

+80
-4
lines changed

3 files changed

+80
-4
lines changed

base_cache.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,16 +67,13 @@ func (c *baseCache) cleanupItem(key string) {
6767

6868
// startCleanup starts the cleanup routine that removes old items
6969
func (c *baseCache) startCleanup() {
70-
if c.maxAge <= 0 {
71-
return
72-
}
73-
7470
// Run cleanup immediately once
7571
c.cleanup()
7672

7773
ticker := time.NewTicker(c.cleanupInterval)
7874
defer ticker.Stop()
7975

76+
// Start cleanup loop
8077
for {
8178
select {
8279
case <-ticker.C:

base_cache_test.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,4 +96,54 @@ func TestBaseCache(t *testing.T) {
9696
// Ensure that lastUsed is set to a recent time (within the last 2 seconds)
9797
assert.WithinDuration(t, time.Now(), entry.lastUsed, 2*time.Second, "expected entry.lastUsed to be recent")
9898
})
99+
100+
t.Run("cleanup doesn't run when maxAge is zero or negative", func(t *testing.T) {
101+
// Create base cache with zero maxAge
102+
opts := Options{
103+
CleanupInterval: 100 * time.Millisecond,
104+
MaxAge: 0,
105+
}
106+
107+
cache := newBaseCache(opts)
108+
defer cache.Stop()
109+
110+
// Add test item
111+
db, _ := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
112+
cache.cacheMutex.Lock()
113+
cache.dbCache["test"] = &dbCacheEntry{
114+
db: db,
115+
lastUsed: time.Now().Add(-10 * time.Second),
116+
}
117+
cache.cacheMutex.Unlock()
118+
119+
// Wait for potential cleanup
120+
time.Sleep(500 * time.Millisecond)
121+
122+
// Verify item still exists since cleanup should not run
123+
cache.cacheMutex.RLock()
124+
_, exists := cache.dbCache["test"]
125+
cache.cacheMutex.RUnlock()
126+
127+
assert.True(t, exists, "item should not be cleaned up when maxAge is 0")
128+
129+
// Test with negative maxAge
130+
opts.MaxAge = -1 * time.Second
131+
cache = newBaseCache(opts)
132+
defer cache.Stop()
133+
134+
cache.cacheMutex.Lock()
135+
cache.dbCache["test"] = &dbCacheEntry{
136+
db: db,
137+
lastUsed: time.Now().Add(-10 * time.Second),
138+
}
139+
cache.cacheMutex.Unlock()
140+
141+
time.Sleep(500 * time.Millisecond)
142+
143+
cache.cacheMutex.RLock()
144+
_, exists = cache.dbCache["test"]
145+
cache.cacheMutex.RUnlock()
146+
147+
assert.True(t, exists, "item should not be cleaned up when maxAge is negative")
148+
})
99149
}

cache_test.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,35 @@ func TestGet(t *testing.T) {
110110
})
111111
}
112112

113+
func TestOpenError(t *testing.T) {
114+
cache := gormoize.ByDSN(nil)
115+
116+
// Create a dialector function that will cause an error by using an invalid DSN
117+
failDialector := func(dsn string) gorm.Dialector {
118+
// Use a non-existent directory to force an error
119+
return sqlite.Open("/nonexistent/directory/db.sqlite")
120+
}
121+
122+
// Attempt to open the database
123+
db, err := cache.Open(failDialector, "test")
124+
125+
// Verify that the error is returned
126+
if err == nil {
127+
t.Error("expected error when opening invalid database")
128+
}
129+
130+
// Verify that nil is returned for the database
131+
if db != nil {
132+
t.Error("expected nil database when error occurs")
133+
}
134+
135+
// Verify that the failed connection is not cached
136+
cachedDB := cache.Get("test")
137+
if cachedDB != nil {
138+
t.Error("failed connection should not be cached")
139+
}
140+
}
141+
113142
func TestConcurrentOpen(t *testing.T) {
114143
// Clean up test database after tests
115144
const testDSN = "concurrent_test.db"

0 commit comments

Comments
 (0)