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:
465
internal/repositories/user_repo_coverage_test.go
Normal file
465
internal/repositories/user_repo_coverage_test.go
Normal file
@@ -0,0 +1,465 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/treytartt/honeydue-api/internal/models"
|
||||
"github.com/treytartt/honeydue-api/internal/testutil"
|
||||
)
|
||||
|
||||
func TestUserRepository_FindByUsername_CaseInsensitive(t *testing.T) {
|
||||
db := testutil.SetupTestDB(t)
|
||||
repo := NewUserRepository(db)
|
||||
|
||||
testutil.CreateTestUser(t, db, "TestUser", "test@example.com", "Password123")
|
||||
|
||||
// Should find with different cases
|
||||
found, err := repo.FindByUsername("testuser")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "TestUser", found.Username)
|
||||
|
||||
found, err = repo.FindByUsername("TESTUSER")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "TestUser", found.Username)
|
||||
}
|
||||
|
||||
func TestUserRepository_FindByUsername_NotFound(t *testing.T) {
|
||||
db := testutil.SetupTestDB(t)
|
||||
repo := NewUserRepository(db)
|
||||
|
||||
_, err := repo.FindByUsername("nonexistent")
|
||||
assert.Error(t, err)
|
||||
assert.ErrorIs(t, err, ErrUserNotFound)
|
||||
}
|
||||
|
||||
func TestUserRepository_FindByEmail_CaseInsensitive(t *testing.T) {
|
||||
db := testutil.SetupTestDB(t)
|
||||
repo := NewUserRepository(db)
|
||||
|
||||
testutil.CreateTestUser(t, db, "testuser", "Test@Example.com", "Password123")
|
||||
|
||||
found, err := repo.FindByEmail("test@example.com")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "Test@Example.com", found.Email)
|
||||
}
|
||||
|
||||
func TestUserRepository_FindByEmail_NotFound(t *testing.T) {
|
||||
db := testutil.SetupTestDB(t)
|
||||
repo := NewUserRepository(db)
|
||||
|
||||
_, err := repo.FindByEmail("nonexistent@example.com")
|
||||
assert.Error(t, err)
|
||||
assert.ErrorIs(t, err, ErrUserNotFound)
|
||||
}
|
||||
|
||||
func TestUserRepository_ExistsByUsername_CaseInsensitive(t *testing.T) {
|
||||
db := testutil.SetupTestDB(t)
|
||||
repo := NewUserRepository(db)
|
||||
|
||||
testutil.CreateTestUser(t, db, "TestUser", "test@example.com", "Password123")
|
||||
|
||||
exists, err := repo.ExistsByUsername("TESTUSER")
|
||||
require.NoError(t, err)
|
||||
assert.True(t, exists)
|
||||
}
|
||||
|
||||
func TestUserRepository_ExistsByEmail_CaseInsensitive(t *testing.T) {
|
||||
db := testutil.SetupTestDB(t)
|
||||
repo := NewUserRepository(db)
|
||||
|
||||
testutil.CreateTestUser(t, db, "testuser", "Test@Example.com", "Password123")
|
||||
|
||||
exists, err := repo.ExistsByEmail("test@example.com")
|
||||
require.NoError(t, err)
|
||||
assert.True(t, exists)
|
||||
}
|
||||
|
||||
func TestUserRepository_GetOrCreateToken(t *testing.T) {
|
||||
db := testutil.SetupTestDB(t)
|
||||
repo := NewUserRepository(db)
|
||||
|
||||
user := testutil.CreateTestUser(t, db, "testuser", "test@example.com", "Password123")
|
||||
|
||||
// Create token
|
||||
token1, err := repo.GetOrCreateToken(user.ID)
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, token1.Key)
|
||||
|
||||
// Should return same token
|
||||
token2, err := repo.GetOrCreateToken(user.ID)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, token1.Key, token2.Key)
|
||||
}
|
||||
|
||||
func TestUserRepository_FindTokenByKey(t *testing.T) {
|
||||
db := testutil.SetupTestDB(t)
|
||||
repo := NewUserRepository(db)
|
||||
|
||||
user := testutil.CreateTestUser(t, db, "testuser", "test@example.com", "Password123")
|
||||
|
||||
token, err := repo.GetOrCreateToken(user.ID)
|
||||
require.NoError(t, err)
|
||||
|
||||
found, err := repo.FindTokenByKey(token.Key)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, token.Key, found.Key)
|
||||
assert.Equal(t, user.ID, found.UserID)
|
||||
}
|
||||
|
||||
func TestUserRepository_FindTokenByKey_NotFound(t *testing.T) {
|
||||
db := testutil.SetupTestDB(t)
|
||||
repo := NewUserRepository(db)
|
||||
|
||||
_, err := repo.FindTokenByKey("nonexistent-token-key")
|
||||
assert.Error(t, err)
|
||||
assert.ErrorIs(t, err, ErrTokenNotFound)
|
||||
}
|
||||
|
||||
func TestUserRepository_DeleteToken(t *testing.T) {
|
||||
db := testutil.SetupTestDB(t)
|
||||
repo := NewUserRepository(db)
|
||||
|
||||
user := testutil.CreateTestUser(t, db, "testuser", "test@example.com", "Password123")
|
||||
|
||||
token, err := repo.GetOrCreateToken(user.ID)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = repo.DeleteToken(token.Key)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = repo.FindTokenByKey(token.Key)
|
||||
assert.ErrorIs(t, err, ErrTokenNotFound)
|
||||
}
|
||||
|
||||
func TestUserRepository_DeleteToken_NotFound(t *testing.T) {
|
||||
db := testutil.SetupTestDB(t)
|
||||
repo := NewUserRepository(db)
|
||||
|
||||
err := repo.DeleteToken("nonexistent-key")
|
||||
assert.ErrorIs(t, err, ErrTokenNotFound)
|
||||
}
|
||||
|
||||
func TestUserRepository_DeleteTokenByUserID(t *testing.T) {
|
||||
db := testutil.SetupTestDB(t)
|
||||
repo := NewUserRepository(db)
|
||||
|
||||
user := testutil.CreateTestUser(t, db, "testuser", "test@example.com", "Password123")
|
||||
|
||||
_, err := repo.GetOrCreateToken(user.ID)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = repo.DeleteTokenByUserID(user.ID)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Token should be gone
|
||||
var count int64
|
||||
db.Model(&models.AuthToken{}).Where("user_id = ?", user.ID).Count(&count)
|
||||
assert.Equal(t, int64(0), count)
|
||||
}
|
||||
|
||||
func TestUserRepository_CreateToken(t *testing.T) {
|
||||
db := testutil.SetupTestDB(t)
|
||||
repo := NewUserRepository(db)
|
||||
|
||||
user := testutil.CreateTestUser(t, db, "testuser", "test@example.com", "Password123")
|
||||
|
||||
token, err := repo.CreateToken(user.ID)
|
||||
require.NoError(t, err)
|
||||
assert.NotEmpty(t, token.Key)
|
||||
assert.Equal(t, user.ID, token.UserID)
|
||||
}
|
||||
|
||||
func TestUserRepository_UpdateLastLogin(t *testing.T) {
|
||||
db := testutil.SetupTestDB(t)
|
||||
repo := NewUserRepository(db)
|
||||
|
||||
user := testutil.CreateTestUser(t, db, "testuser", "test@example.com", "Password123")
|
||||
|
||||
err := repo.UpdateLastLogin(user.ID)
|
||||
require.NoError(t, err)
|
||||
|
||||
found, err := repo.FindByID(user.ID)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, found.LastLogin)
|
||||
}
|
||||
|
||||
func TestUserRepository_UpdateProfile(t *testing.T) {
|
||||
db := testutil.SetupTestDB(t)
|
||||
repo := NewUserRepository(db)
|
||||
|
||||
user := testutil.CreateTestUser(t, db, "testuser", "test@example.com", "Password123")
|
||||
|
||||
profile, err := repo.GetOrCreateProfile(user.ID)
|
||||
require.NoError(t, err)
|
||||
|
||||
profile.Bio = "Test bio"
|
||||
profile.PhoneNumber = "+1-555-0100"
|
||||
err = repo.UpdateProfile(profile)
|
||||
require.NoError(t, err)
|
||||
|
||||
updated, err := repo.GetOrCreateProfile(user.ID)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "Test bio", updated.Bio)
|
||||
assert.Equal(t, "+1-555-0100", updated.PhoneNumber)
|
||||
}
|
||||
|
||||
func TestUserRepository_SetProfileVerified(t *testing.T) {
|
||||
db := testutil.SetupTestDB(t)
|
||||
repo := NewUserRepository(db)
|
||||
|
||||
user := testutil.CreateTestUser(t, db, "testuser", "test@example.com", "Password123")
|
||||
|
||||
// Create profile
|
||||
_, err := repo.GetOrCreateProfile(user.ID)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = repo.SetProfileVerified(user.ID, true)
|
||||
require.NoError(t, err)
|
||||
|
||||
profile, err := repo.GetOrCreateProfile(user.ID)
|
||||
require.NoError(t, err)
|
||||
assert.True(t, profile.Verified)
|
||||
}
|
||||
|
||||
func TestUserRepository_FindByIDWithProfile(t *testing.T) {
|
||||
db := testutil.SetupTestDB(t)
|
||||
repo := NewUserRepository(db)
|
||||
|
||||
user := testutil.CreateTestUser(t, db, "testuser", "test@example.com", "Password123")
|
||||
|
||||
// Create profile first
|
||||
profile := &models.UserProfile{
|
||||
UserID: user.ID,
|
||||
Bio: "My bio",
|
||||
}
|
||||
err := db.Create(profile).Error
|
||||
require.NoError(t, err)
|
||||
|
||||
found, err := repo.FindByIDWithProfile(user.ID)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, user.ID, found.ID)
|
||||
require.NotNil(t, found.Profile)
|
||||
assert.Equal(t, "My bio", found.Profile.Bio)
|
||||
}
|
||||
|
||||
func TestUserRepository_FindByIDWithProfile_NotFound(t *testing.T) {
|
||||
db := testutil.SetupTestDB(t)
|
||||
repo := NewUserRepository(db)
|
||||
|
||||
_, err := repo.FindByIDWithProfile(9999)
|
||||
assert.Error(t, err)
|
||||
assert.ErrorIs(t, err, ErrUserNotFound)
|
||||
}
|
||||
|
||||
func TestUserRepository_ConfirmationCode_Lifecycle(t *testing.T) {
|
||||
db := testutil.SetupTestDB(t)
|
||||
repo := NewUserRepository(db)
|
||||
|
||||
user := testutil.CreateTestUser(t, db, "testuser", "test@example.com", "Password123")
|
||||
|
||||
// Create confirmation code
|
||||
expiresAt := time.Now().UTC().Add(1 * time.Hour)
|
||||
code, err := repo.CreateConfirmationCode(user.ID, "123456", expiresAt)
|
||||
require.NoError(t, err)
|
||||
assert.NotZero(t, code.ID)
|
||||
|
||||
// Find it
|
||||
found, err := repo.FindConfirmationCode(user.ID, "123456")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, code.ID, found.ID)
|
||||
|
||||
// Mark as used
|
||||
err = repo.MarkConfirmationCodeUsed(code.ID)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Should not find used code
|
||||
_, err = repo.FindConfirmationCode(user.ID, "123456")
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestUserRepository_ConfirmationCode_InvalidatesExisting(t *testing.T) {
|
||||
db := testutil.SetupTestDB(t)
|
||||
repo := NewUserRepository(db)
|
||||
|
||||
user := testutil.CreateTestUser(t, db, "testuser", "test@example.com", "Password123")
|
||||
|
||||
expiresAt := time.Now().UTC().Add(1 * time.Hour)
|
||||
|
||||
// Create first code
|
||||
code1, err := repo.CreateConfirmationCode(user.ID, "111111", expiresAt)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create second code (should invalidate first)
|
||||
_, err = repo.CreateConfirmationCode(user.ID, "222222", expiresAt)
|
||||
require.NoError(t, err)
|
||||
|
||||
// First code should be used/invalidated
|
||||
var c models.ConfirmationCode
|
||||
db.First(&c, code1.ID)
|
||||
assert.True(t, c.IsUsed)
|
||||
}
|
||||
|
||||
func TestUserRepository_Transaction(t *testing.T) {
|
||||
db := testutil.SetupTestDB(t)
|
||||
repo := NewUserRepository(db)
|
||||
|
||||
user := testutil.CreateTestUser(t, db, "testuser", "test@example.com", "Password123")
|
||||
|
||||
err := repo.Transaction(func(txRepo *UserRepository) error {
|
||||
found, err := txRepo.FindByID(user.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
found.FirstName = "Updated"
|
||||
return txRepo.Update(found)
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
found, err := repo.FindByID(user.ID)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "Updated", found.FirstName)
|
||||
}
|
||||
|
||||
func TestUserRepository_DB(t *testing.T) {
|
||||
db := testutil.SetupTestDB(t)
|
||||
repo := NewUserRepository(db)
|
||||
|
||||
assert.NotNil(t, repo.DB())
|
||||
}
|
||||
|
||||
func TestUserRepository_FindByAppleID(t *testing.T) {
|
||||
db := testutil.SetupTestDB(t)
|
||||
repo := NewUserRepository(db)
|
||||
|
||||
user := testutil.CreateTestUser(t, db, "appleuser", "apple@test.com", "Password123")
|
||||
appleAuth := &models.AppleSocialAuth{
|
||||
UserID: user.ID,
|
||||
AppleID: "apple_sub_123",
|
||||
Email: "apple@test.com",
|
||||
}
|
||||
require.NoError(t, db.Create(appleAuth).Error)
|
||||
|
||||
found, err := repo.FindByAppleID("apple_sub_123")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, user.ID, found.UserID)
|
||||
}
|
||||
|
||||
func TestUserRepository_FindByAppleID_NotFound(t *testing.T) {
|
||||
db := testutil.SetupTestDB(t)
|
||||
repo := NewUserRepository(db)
|
||||
|
||||
_, err := repo.FindByAppleID("nonexistent_apple_id")
|
||||
assert.ErrorIs(t, err, ErrAppleAuthNotFound)
|
||||
}
|
||||
|
||||
func TestUserRepository_FindByGoogleID(t *testing.T) {
|
||||
db := testutil.SetupTestDB(t)
|
||||
repo := NewUserRepository(db)
|
||||
|
||||
user := testutil.CreateTestUser(t, db, "googleuser", "google@test.com", "Password123")
|
||||
googleAuth := &models.GoogleSocialAuth{
|
||||
UserID: user.ID,
|
||||
GoogleID: "google_sub_123",
|
||||
Email: "google@test.com",
|
||||
}
|
||||
require.NoError(t, db.Create(googleAuth).Error)
|
||||
|
||||
found, err := repo.FindByGoogleID("google_sub_123")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, user.ID, found.UserID)
|
||||
}
|
||||
|
||||
func TestUserRepository_FindByGoogleID_NotFound(t *testing.T) {
|
||||
db := testutil.SetupTestDB(t)
|
||||
repo := NewUserRepository(db)
|
||||
|
||||
_, err := repo.FindByGoogleID("nonexistent_google_id")
|
||||
assert.ErrorIs(t, err, ErrGoogleAuthNotFound)
|
||||
}
|
||||
|
||||
func TestUserRepository_CreateAndUpdateAppleSocialAuth(t *testing.T) {
|
||||
db := testutil.SetupTestDB(t)
|
||||
repo := NewUserRepository(db)
|
||||
|
||||
user := testutil.CreateTestUser(t, db, "appleuser", "apple@test.com", "Password123")
|
||||
|
||||
auth := &models.AppleSocialAuth{
|
||||
UserID: user.ID,
|
||||
AppleID: "apple_sub_456",
|
||||
Email: "apple@test.com",
|
||||
}
|
||||
err := repo.CreateAppleSocialAuth(auth)
|
||||
require.NoError(t, err)
|
||||
assert.NotZero(t, auth.ID)
|
||||
|
||||
auth.Email = "updated@test.com"
|
||||
err = repo.UpdateAppleSocialAuth(auth)
|
||||
require.NoError(t, err)
|
||||
|
||||
found, err := repo.FindByAppleID("apple_sub_456")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "updated@test.com", found.Email)
|
||||
}
|
||||
|
||||
func TestUserRepository_CreateAndUpdateGoogleSocialAuth(t *testing.T) {
|
||||
db := testutil.SetupTestDB(t)
|
||||
repo := NewUserRepository(db)
|
||||
|
||||
user := testutil.CreateTestUser(t, db, "googleuser", "google@test.com", "Password123")
|
||||
|
||||
auth := &models.GoogleSocialAuth{
|
||||
UserID: user.ID,
|
||||
GoogleID: "google_sub_456",
|
||||
Email: "google@test.com",
|
||||
Name: "Test User",
|
||||
}
|
||||
err := repo.CreateGoogleSocialAuth(auth)
|
||||
require.NoError(t, err)
|
||||
assert.NotZero(t, auth.ID)
|
||||
|
||||
auth.Name = "Updated Name"
|
||||
err = repo.UpdateGoogleSocialAuth(auth)
|
||||
require.NoError(t, err)
|
||||
|
||||
found, err := repo.FindByGoogleID("google_sub_456")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "Updated Name", found.Name)
|
||||
}
|
||||
|
||||
func TestUserRepository_SearchUsers(t *testing.T) {
|
||||
db := testutil.SetupTestDB(t)
|
||||
repo := NewUserRepository(db)
|
||||
|
||||
testutil.CreateTestUser(t, db, "john_doe", "john@example.com", "Password123")
|
||||
testutil.CreateTestUser(t, db, "jane_smith", "jane@example.com", "Password123")
|
||||
testutil.CreateTestUser(t, db, "bob_builder", "bob@example.com", "Password123")
|
||||
|
||||
users, total, err := repo.SearchUsers("john", 10, 0)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(1), total)
|
||||
assert.Len(t, users, 1)
|
||||
assert.Equal(t, "john_doe", users[0].Username)
|
||||
}
|
||||
|
||||
func TestUserRepository_ListUsers(t *testing.T) {
|
||||
db := testutil.SetupTestDB(t)
|
||||
repo := NewUserRepository(db)
|
||||
|
||||
testutil.CreateTestUser(t, db, "user1", "user1@example.com", "Password123")
|
||||
testutil.CreateTestUser(t, db, "user2", "user2@example.com", "Password123")
|
||||
testutil.CreateTestUser(t, db, "user3", "user3@example.com", "Password123")
|
||||
|
||||
users, total, err := repo.ListUsers(2, 0)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(3), total)
|
||||
assert.Len(t, users, 2) // Limited to 2
|
||||
|
||||
users, total, err = repo.ListUsers(2, 2)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(3), total)
|
||||
assert.Len(t, users, 1) // Only 1 remaining
|
||||
}
|
||||
Reference in New Issue
Block a user