Coverage priorities 1-5: test pure functions, extract interfaces, mock-based handler tests

- Priority 1: Test NewSendEmailTask + NewSendPushTask (5 tests)
- Priority 2: Test customHTTPErrorHandler — all 15+ branches (21 tests)
- Priority 3: Extract Enqueuer interface + payload builders in worker pkg (5 tests)
- Priority 4: Extract ClassifyFile/ComputeRelPath in migrate-encrypt (6 tests)
- Priority 5: Define Handler interfaces, refactor to accept them, mock-based tests (14 tests)
- Fix .gitignore: /worker instead of worker to stop ignoring internal/worker/

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Trey T
2026-04-01 20:30:09 -05:00
parent 00fd674b56
commit bec880886b
83 changed files with 19569 additions and 730 deletions

View File

@@ -0,0 +1,186 @@
package middleware
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/treytartt/honeydue-api/internal/models"
)
func TestUserCache_SetAndGet(t *testing.T) {
cache := NewUserCache(1 * time.Minute)
user := &models.User{Username: "testuser", Email: "test@test.com"}
user.ID = 1
cache.Set(user)
cached := cache.Get(1)
require.NotNil(t, cached)
assert.Equal(t, "testuser", cached.Username)
assert.Equal(t, "test@test.com", cached.Email)
}
func TestUserCache_GetNonExistent_ReturnsNil(t *testing.T) {
cache := NewUserCache(1 * time.Minute)
cached := cache.Get(999)
assert.Nil(t, cached)
}
func TestUserCache_Expired_ReturnsNil(t *testing.T) {
// Very short TTL
cache := NewUserCache(1 * time.Millisecond)
user := &models.User{Username: "expiring_user"}
user.ID = 1
cache.Set(user)
// Wait for expiry
time.Sleep(5 * time.Millisecond)
cached := cache.Get(1)
assert.Nil(t, cached, "expired entry should return nil")
}
func TestUserCache_Invalidate(t *testing.T) {
cache := NewUserCache(1 * time.Minute)
user := &models.User{Username: "to_invalidate"}
user.ID = 1
cache.Set(user)
// Verify it's cached
require.NotNil(t, cache.Get(1))
// Invalidate
cache.Invalidate(1)
// Should be gone
assert.Nil(t, cache.Get(1))
}
func TestUserCache_ReturnsCopy_NotOriginal(t *testing.T) {
cache := NewUserCache(1 * time.Minute)
user := &models.User{Username: "original"}
user.ID = 1
cache.Set(user)
// Modify the returned copy
cached := cache.Get(1)
require.NotNil(t, cached)
cached.Username = "modified"
// Original cache entry should be unaffected
cached2 := cache.Get(1)
require.NotNil(t, cached2)
assert.Equal(t, "original", cached2.Username, "cache should return a copy, not the original")
}
func TestUserCache_SetCopiesInput(t *testing.T) {
cache := NewUserCache(1 * time.Minute)
user := &models.User{Username: "original"}
user.ID = 1
cache.Set(user)
// Modify the input after setting
user.Username = "modified_after_set"
// Cache should still have the original value
cached := cache.Get(1)
require.NotNil(t, cached)
assert.Equal(t, "original", cached.Username, "cache should store a copy of the input")
}
func TestUserCache_MultipleUsers(t *testing.T) {
cache := NewUserCache(1 * time.Minute)
user1 := &models.User{Username: "user1"}
user1.ID = 1
user2 := &models.User{Username: "user2"}
user2.ID = 2
cache.Set(user1)
cache.Set(user2)
cached1 := cache.Get(1)
cached2 := cache.Get(2)
require.NotNil(t, cached1)
require.NotNil(t, cached2)
assert.Equal(t, "user1", cached1.Username)
assert.Equal(t, "user2", cached2.Username)
}
func TestUserCache_OverwriteEntry(t *testing.T) {
cache := NewUserCache(1 * time.Minute)
user := &models.User{Username: "original"}
user.ID = 1
cache.Set(user)
// Overwrite with new data
updated := &models.User{Username: "updated"}
updated.ID = 1
cache.Set(updated)
cached := cache.Get(1)
require.NotNil(t, cached)
assert.Equal(t, "updated", cached.Username)
}
func TestTimezoneCache_GetAndCompare_NewEntry(t *testing.T) {
tc := NewTimezoneCache()
// First call should return false (not cached yet)
unchanged := tc.GetAndCompare(1, "America/New_York")
assert.False(t, unchanged, "first call should indicate a change")
}
func TestTimezoneCache_GetAndCompare_SameValue(t *testing.T) {
tc := NewTimezoneCache()
// First call sets the value
tc.GetAndCompare(1, "America/New_York")
// Second call with same value should return true (unchanged)
unchanged := tc.GetAndCompare(1, "America/New_York")
assert.True(t, unchanged, "same value should indicate no change")
}
func TestTimezoneCache_GetAndCompare_DifferentValue(t *testing.T) {
tc := NewTimezoneCache()
// Set initial value
tc.GetAndCompare(1, "America/New_York")
// Update to different value
unchanged := tc.GetAndCompare(1, "America/Chicago")
assert.False(t, unchanged, "different value should indicate a change")
// Now the new value is cached
unchanged = tc.GetAndCompare(1, "America/Chicago")
assert.True(t, unchanged, "same value should indicate no change")
}
func TestTimezoneCache_GetAndCompare_DifferentUsers(t *testing.T) {
tc := NewTimezoneCache()
tc.GetAndCompare(1, "America/New_York")
tc.GetAndCompare(2, "Europe/London")
assert.True(t, tc.GetAndCompare(1, "America/New_York"))
assert.True(t, tc.GetAndCompare(2, "Europe/London"))
assert.False(t, tc.GetAndCompare(1, "Europe/London"))
}