veza/veza-backend-api/internal/jobs/cleanup_password_reset_tokens_test.go
2025-12-03 20:29:37 +01:00

227 lines
8.5 KiB
Go

package jobs
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/zap"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
"veza-backend-api/internal/database"
"veza-backend-api/internal/models"
)
// setupTestPasswordResetCleanupDB crée une base de données de test avec la table password_reset_tokens
func setupTestPasswordResetCleanupDB(t *testing.T) (*database.Database, *gorm.DB) {
// Créer une base de données GORM en mémoire
gormDB, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
require.NoError(t, err, "Failed to open test database")
// Auto-migrate pour créer la table users
err = gormDB.AutoMigrate(&models.User{})
require.NoError(t, err, "Failed to migrate users table")
// Créer la table password_reset_tokens manuellement
err = gormDB.Exec(`
CREATE TABLE password_reset_tokens (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
token TEXT NOT NULL UNIQUE,
expires_at TIMESTAMP NOT NULL,
used INTEGER NOT NULL DEFAULT 0,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
)
`).Error
require.NoError(t, err, "Failed to create password_reset_tokens table")
// Créer un utilisateur de test
user := &models.User{
Email: "test@example.com",
Username: "testuser",
Role: "user",
IsActive: true,
}
err = gormDB.Create(user).Error
require.NoError(t, err, "Failed to create test user")
// Obtenir le sql.DB depuis GORM
sqlDB, err := gormDB.DB()
require.NoError(t, err, "Failed to get sql.DB from GORM")
// Créer un Database wrapper
testDB := &database.Database{
DB: sqlDB,
}
return testDB, gormDB
}
// TestCleanupExpiredPasswordResetTokens_ExpiredTokens supprime les tokens expirés
func TestCleanupExpiredPasswordResetTokens_ExpiredTokens(t *testing.T) {
testDB, gormDB := setupTestPasswordResetCleanupDB(t)
logger, _ := zap.NewDevelopment()
// Créer des tokens expirés
expiredTime := time.Now().Add(-25 * time.Hour) // Expiré il y a 25 heures
err := gormDB.Exec(`
INSERT INTO password_reset_tokens (user_id, token, expires_at, used, created_at)
VALUES (?, ?, ?, ?, ?)
`, 1, "expired_token_1", expiredTime, false, time.Now().Add(-26*time.Hour)).Error
require.NoError(t, err)
err = gormDB.Exec(`
INSERT INTO password_reset_tokens (user_id, token, expires_at, used, created_at)
VALUES (?, ?, ?, ?, ?)
`, 1, "expired_token_2", expiredTime, false, time.Now().Add(-26*time.Hour)).Error
require.NoError(t, err)
// Créer un token valide (non expiré)
validTime := time.Now().Add(24 * time.Hour)
err = gormDB.Exec(`
INSERT INTO password_reset_tokens (user_id, token, expires_at, used, created_at)
VALUES (?, ?, ?, ?, ?)
`, 1, "valid_token", validTime, false, time.Now()).Error
require.NoError(t, err)
// Exécuter le nettoyage
err = CleanupExpiredPasswordResetTokens(testDB, logger)
assert.NoError(t, err)
// Vérifier que les tokens expirés ont été supprimés
var count int64
err = gormDB.Raw("SELECT COUNT(*) FROM password_reset_tokens WHERE token IN ('expired_token_1', 'expired_token_2')").Scan(&count).Error
require.NoError(t, err)
assert.Equal(t, int64(0), count, "Expired tokens should be deleted")
// Vérifier que le token valide est toujours présent
err = gormDB.Raw("SELECT COUNT(*) FROM password_reset_tokens WHERE token = 'valid_token'").Scan(&count).Error
require.NoError(t, err)
assert.Equal(t, int64(1), count, "Valid token should still exist")
}
// TestCleanupExpiredPasswordResetTokens_UsedTokens supprime les tokens utilisés plus anciens que 7 jours
func TestCleanupExpiredPasswordResetTokens_UsedTokens(t *testing.T) {
testDB, gormDB := setupTestPasswordResetCleanupDB(t)
logger, _ := zap.NewDevelopment()
// Créer un token utilisé il y a 8 jours (devrait être supprimé)
eightDaysAgo := time.Now().Add(-8 * 24 * time.Hour)
err := gormDB.Exec(`
INSERT INTO password_reset_tokens (user_id, token, expires_at, used, created_at)
VALUES (?, ?, ?, ?, ?)
`, 1, "used_token_old", time.Now().Add(24*time.Hour), true, eightDaysAgo).Error
require.NoError(t, err)
// Créer un token utilisé il y a 5 jours (ne devrait pas être supprimé)
fiveDaysAgo := time.Now().Add(-5 * 24 * time.Hour)
err = gormDB.Exec(`
INSERT INTO password_reset_tokens (user_id, token, expires_at, used, created_at)
VALUES (?, ?, ?, ?, ?)
`, 1, "used_token_recent", time.Now().Add(24*time.Hour), true, fiveDaysAgo).Error
require.NoError(t, err)
// Exécuter le nettoyage
err = CleanupExpiredPasswordResetTokens(testDB, logger)
assert.NoError(t, err)
// Vérifier que le token utilisé ancien a été supprimé
var count int64
err = gormDB.Raw("SELECT COUNT(*) FROM password_reset_tokens WHERE token = 'used_token_old'").Scan(&count).Error
require.NoError(t, err)
assert.Equal(t, int64(0), count, "Old used token should be deleted")
// Vérifier que le token utilisé récent est toujours présent
err = gormDB.Raw("SELECT COUNT(*) FROM password_reset_tokens WHERE token = 'used_token_recent'").Scan(&count).Error
require.NoError(t, err)
assert.Equal(t, int64(1), count, "Recent used token should still exist")
}
// TestCleanupExpiredPasswordResetTokens_MixedTokens supprime les tokens expirés et utilisés anciens
func TestCleanupExpiredPasswordResetTokens_MixedTokens(t *testing.T) {
testDB, gormDB := setupTestPasswordResetCleanupDB(t)
logger, _ := zap.NewDevelopment()
// Créer un token expiré
expiredTime := time.Now().Add(-25 * time.Hour)
err := gormDB.Exec(`
INSERT INTO password_reset_tokens (user_id, token, expires_at, used, created_at)
VALUES (?, ?, ?, ?, ?)
`, 1, "expired_token", expiredTime, false, time.Now().Add(-26*time.Hour)).Error
require.NoError(t, err)
// Créer un token utilisé ancien
eightDaysAgo := time.Now().Add(-8 * 24 * time.Hour)
err = gormDB.Exec(`
INSERT INTO password_reset_tokens (user_id, token, expires_at, used, created_at)
VALUES (?, ?, ?, ?, ?)
`, 1, "used_token_old", time.Now().Add(24*time.Hour), true, eightDaysAgo).Error
require.NoError(t, err)
// Créer un token valide
validTime := time.Now().Add(24 * time.Hour)
err = gormDB.Exec(`
INSERT INTO password_reset_tokens (user_id, token, expires_at, used, created_at)
VALUES (?, ?, ?, ?, ?)
`, 1, "valid_token", validTime, false, time.Now()).Error
require.NoError(t, err)
// Compter les tokens avant le nettoyage
var countBefore int64
err = gormDB.Raw("SELECT COUNT(*) FROM password_reset_tokens").Scan(&countBefore).Error
require.NoError(t, err)
assert.Equal(t, int64(3), countBefore)
// Exécuter le nettoyage
err = CleanupExpiredPasswordResetTokens(testDB, logger)
assert.NoError(t, err)
// Vérifier que seuls les tokens valides restent
var countAfter int64
err = gormDB.Raw("SELECT COUNT(*) FROM password_reset_tokens").Scan(&countAfter).Error
require.NoError(t, err)
assert.Equal(t, int64(1), countAfter, "Only valid token should remain")
// Vérifier que c'est bien le token valide qui reste
var countValid int64
err = gormDB.Raw("SELECT COUNT(*) FROM password_reset_tokens WHERE token = 'valid_token'").Scan(&countValid).Error
require.NoError(t, err)
assert.Equal(t, int64(1), countValid, "Valid token should still exist")
}
// TestCleanupExpiredPasswordResetTokens_NoTokensToClean ne fait rien s'il n'y a pas de tokens à nettoyer
func TestCleanupExpiredPasswordResetTokens_NoTokensToClean(t *testing.T) {
testDB, gormDB := setupTestPasswordResetCleanupDB(t)
logger, _ := zap.NewDevelopment()
// Créer uniquement des tokens valides
validTime := time.Now().Add(24 * time.Hour)
err := gormDB.Exec(`
INSERT INTO password_reset_tokens (user_id, token, expires_at, used, created_at)
VALUES (?, ?, ?, ?, ?)
`, 1, "valid_token_1", validTime, false, time.Now()).Error
require.NoError(t, err)
err = gormDB.Exec(`
INSERT INTO password_reset_tokens (user_id, token, expires_at, used, created_at)
VALUES (?, ?, ?, ?, ?)
`, 1, "valid_token_2", validTime, false, time.Now()).Error
require.NoError(t, err)
// Compter les tokens avant le nettoyage
var countBefore int64
err = gormDB.Raw("SELECT COUNT(*) FROM password_reset_tokens").Scan(&countBefore).Error
require.NoError(t, err)
assert.Equal(t, int64(2), countBefore)
// Exécuter le nettoyage
err = CleanupExpiredPasswordResetTokens(testDB, logger)
assert.NoError(t, err)
// Vérifier que tous les tokens sont toujours présents
var countAfter int64
err = gormDB.Raw("SELECT COUNT(*) FROM password_reset_tokens").Scan(&countAfter).Error
require.NoError(t, err)
assert.Equal(t, countBefore, countAfter, "All valid tokens should still exist")
}