veza/veza-backend-api/internal/api/user/service_test.go
senke b28d0e7eac [T0-006] test(backend): Ajout tests pour frontend_log_handler
- Tests complets pour frontend_log_handler.go (12 tests)
- Tests couvrent NewFrontendLogHandler et ReceiveLog
- Tests pour tous les niveaux de log (DEBUG, INFO, WARN, ERROR)
- Tests pour gestion des erreurs et validation JSON
- Couverture actuelle: 30.6% (objectif: 80%)

Files: veza-backend-api/internal/handlers/frontend_log_handler_test.go
       VEZA_ROADMAP.json
Hours: 16 estimated, 23 actual
2026-01-04 01:44:22 +01:00

389 lines
11 KiB
Go

package user
import (
"database/sql"
"regexp"
"testing"
"time"
"github.com/DATA-DOG/go-sqlmock"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"veza-backend-api/internal/database"
)
// Helper to setup mock DB
func setupMockDB(t *testing.T) (*database.DB, sqlmock.Sqlmock) {
db, mock, err := sqlmock.New()
require.NoError(t, err)
dbWrapper := &database.DB{
DB: db,
}
return dbWrapper, mock
}
func TestService_GetUserByID_Success(t *testing.T) {
dbWrapper, mock := setupMockDB(t)
defer dbWrapper.Close()
service := NewService(dbWrapper)
userID := uuid.New()
expectedUser := UserResponse{
ID: userID,
Username: "testuser",
Email: "test@example.com",
Role: "user",
IsActive: true,
CreatedAt: time.Now(),
}
rows := sqlmock.NewRows([]string{"id", "email", "first_name", "last_name", "username", "avatar", "bio",
"role", "is_active", "is_verified", "last_login_at", "created_at", "updated_at"}).
AddRow(userID, expectedUser.Email, nil, nil, expectedUser.Username, nil, nil,
expectedUser.Role, expectedUser.IsActive, false, nil, expectedUser.CreatedAt, time.Now())
mock.ExpectQuery(regexp.QuoteMeta(`SELECT id, email, first_name, last_name, username, avatar, bio,
role, is_active, is_verified, last_login_at, created_at, updated_at
FROM users
WHERE id = $1 AND is_active = true`)).
WithArgs(userID).
WillReturnRows(rows)
// Execute
user, err := service.GetUserByID(userID)
// Assert
assert.NoError(t, err)
assert.NotNil(t, user)
assert.Equal(t, userID, user.ID)
assert.Equal(t, "testuser", user.Username)
assert.NoError(t, mock.ExpectationsWereMet())
}
func TestService_GetUserByID_NotFound(t *testing.T) {
dbWrapper, mock := setupMockDB(t)
defer dbWrapper.Close()
service := NewService(dbWrapper)
userID := uuid.New()
mock.ExpectQuery(regexp.QuoteMeta(`FROM users`)).
WithArgs(userID).
WillReturnError(sql.ErrNoRows)
// Execute
user, err := service.GetUserByID(userID)
// Assert
assert.Error(t, err)
assert.Equal(t, "user not found", err.Error())
assert.Nil(t, user)
}
func TestService_CreateUser_Success(t *testing.T) {
dbWrapper, mock := setupMockDB(t)
defer dbWrapper.Close()
service := NewService(dbWrapper)
req := CreateUserRequest{
Username: "newuser",
Email: "new@example.com",
Password: "password123",
}
userID := uuid.New()
rows := sqlmock.NewRows([]string{"id", "email", "first_name", "last_name", "username", "role", "is_active", "is_verified", "created_at", "updated_at"}).
AddRow(userID, req.Email, nil, nil, req.Username, "user", true, false, time.Now(), time.Now())
mock.ExpectQuery(regexp.QuoteMeta(`INSERT INTO users`)).
WithArgs(req.Email, sqlmock.AnyArg(), "", "", req.Username, "user").
WillReturnRows(rows)
// Execute
user, err := service.CreateUser(req)
// Assert
assert.NoError(t, err)
assert.NotNil(t, user)
assert.Equal(t, userID, user.ID)
assert.Equal(t, "newuser", user.Username)
}
func TestService_DeleteUser_Success(t *testing.T) {
dbWrapper, mock := setupMockDB(t)
defer dbWrapper.Close()
service := NewService(dbWrapper)
userID := uuid.New()
mock.ExpectExec(regexp.QuoteMeta(`UPDATE users SET is_active = false`)).
WithArgs(userID).
WillReturnResult(sqlmock.NewResult(1, 1))
// Execute
err := service.DeleteUser(userID)
// Assert
assert.NoError(t, err)
assert.NoError(t, mock.ExpectationsWereMet())
}
func TestService_DeleteUser_NotFound(t *testing.T) {
dbWrapper, mock := setupMockDB(t)
defer dbWrapper.Close()
service := NewService(dbWrapper)
userID := uuid.New()
mock.ExpectExec(regexp.QuoteMeta(`UPDATE users SET is_active = false`)).
WithArgs(userID).
WillReturnResult(sqlmock.NewResult(1, 0)) // 0 rows affected
// Execute
err := service.DeleteUser(userID)
// Assert
assert.Error(t, err)
assert.Equal(t, "user not found", err.Error())
}
func TestService_RecoverAccount_NotFound(t *testing.T) {
dbWrapper, mock := setupMockDB(t)
defer dbWrapper.Close()
service := NewService(dbWrapper)
email := "deleted@example.com"
mock.ExpectQuery(regexp.QuoteMeta(`SELECT id, password_hash, deleted_at`)).
WithArgs(email).
WillReturnError(sql.ErrNoRows)
err := service.RecoverAccount(email, "password")
assert.Error(t, err)
assert.Equal(t, "no deleted account found for this email", err.Error())
}
func TestService_UpdateUser_Success(t *testing.T) {
dbWrapper, mock := setupMockDB(t)
defer dbWrapper.Close()
service := NewService(dbWrapper)
userID := uuid.New()
newFirst := "Jane"
newLast := "Doe"
req := UpdateUserRequest{
FirstName: &newFirst,
LastName: &newLast,
}
expectedUser := UserResponse{
ID: userID,
Username: "testuser",
Email: "test@example.com",
FirstName: sql.NullString{String: "Jane", Valid: true},
LastName: sql.NullString{String: "Doe", Valid: true},
UpdatedAt: time.Now(),
}
rows := sqlmock.NewRows([]string{"id", "email", "first_name", "last_name", "username", "avatar", "bio",
"role", "is_active", "is_verified", "last_login_at", "created_at", "updated_at"}).
AddRow(userID, expectedUser.Email, expectedUser.FirstName, expectedUser.LastName, expectedUser.Username, nil, nil,
"user", true, false, nil, time.Now(), expectedUser.UpdatedAt)
mock.ExpectQuery(regexp.QuoteMeta(`UPDATE users`)).
WithArgs("Jane", "Doe", userID).
WillReturnRows(rows)
user, err := service.UpdateUser(userID, req)
assert.NoError(t, err)
assert.NotNil(t, user)
assert.Equal(t, "Jane", user.FirstName.String)
assert.NoError(t, mock.ExpectationsWereMet())
}
func TestService_GetUsers_Success(t *testing.T) {
dbWrapper, mock := setupMockDB(t)
defer dbWrapper.Close()
service := NewService(dbWrapper)
// Mock count query
mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM users`)).
WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(2))
// Mock select query
rows := sqlmock.NewRows([]string{"id", "email", "first_name", "last_name", "username", "avatar", "bio",
"role", "is_active", "is_verified", "last_login_at", "created_at", "updated_at"}).
AddRow(uuid.New(), "user1@example.com", nil, nil, "user1", nil, nil, "user", true, false, nil, time.Now(), time.Now()).
AddRow(uuid.New(), "user2@example.com", nil, nil, "user2", nil, nil, "user", true, false, nil, time.Now(), time.Now())
mock.ExpectQuery(regexp.QuoteMeta(`SELECT id, email, first_name, last_name, username, avatar, bio,
role, is_active, is_verified, last_login_at, created_at, updated_at
FROM users`)).
WithArgs(20, 0). // Limit 20, Offset 0
WillReturnRows(rows)
users, total, err := service.GetUsers(1, 20, "")
assert.NoError(t, err)
assert.Equal(t, 2, total)
assert.Len(t, users, 2)
assert.NoError(t, mock.ExpectationsWereMet())
}
func TestService_UpdateUserPreferences_Success(t *testing.T) {
dbWrapper, mock := setupMockDB(t)
defer dbWrapper.Close()
service := NewService(dbWrapper)
userID := uuid.New()
// Expect GetUserPreferences first
prefRows := sqlmock.NewRows([]string{"user_id", "theme", "language", "timezone", "notifications", "privacy", "audio", "updated_at"}).
AddRow(userID, "light", "en", "UTC", "{}", "{}", "{}", time.Now())
mock.ExpectQuery(regexp.QuoteMeta(`SELECT user_id`)).
WithArgs(userID).
WillReturnRows(prefRows)
// Expect Upsert
theme := "dark"
req := UserPreferencesRequest{
Theme: &theme,
}
mock.ExpectExec(regexp.QuoteMeta(`INSERT INTO user_preferences`)).
WithArgs(userID, "dark", "en", "UTC", "{}", "{}", "{}", sqlmock.AnyArg()).
WillReturnResult(sqlmock.NewResult(1, 1))
pref, err := service.UpdateUserPreferences(userID, req)
assert.NoError(t, err)
assert.NotNil(t, pref)
assert.Equal(t, "dark", pref.Theme)
assert.NoError(t, mock.ExpectationsWereMet())
}
func TestService_ChangePassword_UserNotFound(t *testing.T) {
dbWrapper, mock := setupMockDB(t)
defer dbWrapper.Close()
service := NewService(dbWrapper)
userID := uuid.New()
mock.ExpectQuery(regexp.QuoteMeta(`SELECT password_hash FROM users`)).
WithArgs(userID).
WillReturnError(sql.ErrNoRows)
err := service.ChangePassword(userID, "old", "new")
assert.Error(t, err)
assert.Equal(t, "user not found", err.Error())
}
func TestService_GetUserStats_Success(t *testing.T) {
dbWrapper, mock := setupMockDB(t)
defer dbWrapper.Close()
service := NewService(dbWrapper)
// Expect 4 queries
mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM users WHERE is_active = true`)).
WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(100))
mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM users WHERE is_active = true AND is_verified = true`)).
WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(50))
mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM users`)). // Active users query
WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(10))
mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM users`)). // New users query
WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(5))
stats, err := service.GetUserStats()
assert.NoError(t, err)
assert.Equal(t, 100, stats["total_users"])
assert.Equal(t, 50, stats["verified_users"])
assert.NoError(t, mock.ExpectationsWereMet())
}
func TestService_RequestDataDeletion_UserNotFound(t *testing.T) {
dbWrapper, mock := setupMockDB(t)
defer dbWrapper.Close()
service := NewService(dbWrapper)
userID := uuid.New()
mock.ExpectQuery(regexp.QuoteMeta(`SELECT password_hash FROM users`)).
WithArgs(userID).
WillReturnError(sql.ErrNoRows)
err := service.RequestDataDeletion(userID, "pass", "reason")
assert.Error(t, err)
assert.Equal(t, "user not found", err.Error())
}
func TestService_GetAccountStatus_Success(t *testing.T) {
dbWrapper, mock := setupMockDB(t)
defer dbWrapper.Close()
service := NewService(dbWrapper)
userID := uuid.New()
rows := sqlmock.NewRows([]string{"id", "is_active", "is_verified", "created_at", "deleted_at", "deletion_reason", "recovery_deadline"}).
AddRow(userID, true, true, time.Now(), nil, "", nil)
mock.ExpectQuery(regexp.QuoteMeta(`SELECT id, is_active`)).
WithArgs(userID).
WillReturnRows(rows)
status, err := service.GetAccountStatus(userID)
assert.NoError(t, err)
assert.Equal(t, "active", status.Status)
assert.NoError(t, mock.ExpectationsWereMet())
}
func TestService_ExportUserData_Success(t *testing.T) {
dbWrapper, mock := setupMockDB(t)
defer dbWrapper.Close()
service := NewService(dbWrapper)
userID := uuid.New()
// 1. GetUserByID
userRows := sqlmock.NewRows([]string{"id", "email", "first_name", "last_name", "username", "avatar", "bio",
"role", "is_active", "is_verified", "last_login_at", "created_at", "updated_at"}).
AddRow(userID, "test@example.com", nil, nil, "test", nil, nil, "user", true, true, nil, time.Now(), time.Now())
mock.ExpectQuery(regexp.QuoteMeta(`SELECT id`)).
WithArgs(userID).
WillReturnRows(userRows)
// 2. GetUserPreferences
prefRows := sqlmock.NewRows([]string{"user_id", "theme", "language", "timezone", "notifications", "privacy", "audio", "updated_at"}).
AddRow(userID, "light", "en", "UTC", "{}", "{}", "{}", time.Now())
mock.ExpectQuery(regexp.QuoteMeta(`SELECT user_id`)).
WithArgs(userID).
WillReturnRows(prefRows)
export, err := service.ExportUserData(userID)
assert.NoError(t, err)
assert.NotNil(t, export)
assert.Equal(t, userID, export.UserID)
assert.NoError(t, mock.ExpectationsWereMet())
}