package database import ( "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gorm.io/driver/sqlite" "gorm.io/gorm" "veza-backend-api/internal/models" ) // TestPasswordResetTokensTable_Creation teste que la table password_reset_tokens est créée correctement func TestPasswordResetTokensTable_Creation(t *testing.T) { // Créer une base de données en mémoire db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{}) require.NoError(t, err, "Failed to open test database") // Créer la table users d'abord (requis pour la foreign key) err = db.AutoMigrate(&models.User{}) require.NoError(t, err, "Failed to migrate users table") // Créer la table password_reset_tokens manuellement (simule la migration SQL) // Note: SQLite stocke UUIDs comme TEXT, user_id est maintenant UUID err = db.Exec(` CREATE TABLE password_reset_tokens ( id TEXT PRIMARY KEY, user_id TEXT 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 les index err = db.Exec("CREATE INDEX idx_password_reset_tokens_token ON password_reset_tokens(token)").Error require.NoError(t, err) err = db.Exec("CREATE INDEX idx_password_reset_tokens_user_id ON password_reset_tokens(user_id)").Error require.NoError(t, err) err = db.Exec("CREATE INDEX idx_password_reset_tokens_expires_at ON password_reset_tokens(expires_at)").Error require.NoError(t, err) // Vérifier que la table existe hasTable := db.Migrator().HasTable("password_reset_tokens") assert.True(t, hasTable, "password_reset_tokens table should exist") } // TestPasswordResetTokensTable_Columns teste que toutes les colonnes sont présentes func TestPasswordResetTokensTable_Columns(t *testing.T) { // Créer une base de données en mémoire db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{}) require.NoError(t, err) // Créer la table users err = db.AutoMigrate(&models.User{}) require.NoError(t, err) // Créer un utilisateur de test user := &models.User{ Email: "test@example.com", Username: "testuser", Role: "user", IsActive: true, } err = db.Create(user).Error require.NoError(t, err) // Créer la table password_reset_tokens err = db.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) // Vérifier que toutes les colonnes existent en insérant un token expiresAt := time.Now().Add(1 * time.Hour) err = db.Exec(` INSERT INTO password_reset_tokens (user_id, token, expires_at, used, created_at) VALUES (?, ?, ?, ?, ?) `, user.ID, "test-token-123", expiresAt, false, time.Now()).Error require.NoError(t, err, "Should be able to insert a password reset token") // Vérifier que le token a été inséré var count int64 err = db.Raw("SELECT COUNT(*) FROM password_reset_tokens WHERE token = ?", "test-token-123").Scan(&count).Error require.NoError(t, err) assert.Equal(t, int64(1), count, "Token should be inserted") } // TestPasswordResetTokensTable_ForeignKey teste que la foreign key fonctionne correctement func TestPasswordResetTokensTable_ForeignKey(t *testing.T) { // Créer une base de données en mémoire db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{}) require.NoError(t, err) // Activer les foreign keys pour SQLite (requis pour CASCADE DELETE) err = db.Exec("PRAGMA foreign_keys = ON").Error require.NoError(t, err) // Créer la table users err = db.AutoMigrate(&models.User{}) require.NoError(t, err) // Créer la table password_reset_tokens err = db.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) // Créer un utilisateur user := &models.User{ Email: "test@example.com", Username: "testuser", Role: "user", IsActive: true, } err = db.Create(user).Error require.NoError(t, err) // Insérer un token valide expiresAt := time.Now().Add(1 * time.Hour) err = db.Exec(` INSERT INTO password_reset_tokens (user_id, token, expires_at, used, created_at) VALUES (?, ?, ?, ?, ?) `, user.ID, "valid-token", expiresAt, false, time.Now()).Error require.NoError(t, err, "Should be able to insert token for existing user") // Tenter d'insérer un token avec un user_id inexistant (devrait échouer) // Utiliser un UUID valide mais inexistant fakeUserID := "00000000-0000-0000-0000-000000000999" err = db.Exec(` INSERT INTO password_reset_tokens (user_id, token, expires_at, used, created_at) VALUES (?, ?, ?, ?, ?) `, fakeUserID, "invalid-token", expiresAt, false, time.Now()).Error assert.Error(t, err, "Should not be able to insert token with non-existent user_id") // Vérifier que le CASCADE DELETE fonctionne // Utiliser Unscoped() pour forcer la suppression réelle (pas soft delete) err = db.Unscoped().Delete(user).Error require.NoError(t, err) // Vérifier que le token a été supprimé automatiquement var count int64 err = db.Raw("SELECT COUNT(*) FROM password_reset_tokens WHERE token = ?", "valid-token").Scan(&count).Error require.NoError(t, err) assert.Equal(t, int64(0), count, "Token should be deleted when user is deleted") } // TestPasswordResetTokensTable_UniqueToken teste que le token doit être unique func TestPasswordResetTokensTable_UniqueToken(t *testing.T) { // Créer une base de données en mémoire db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{}) require.NoError(t, err) // Créer la table users err = db.AutoMigrate(&models.User{}) require.NoError(t, err) // Créer la table password_reset_tokens err = db.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) // Créer un utilisateur user := &models.User{ Email: "test@example.com", Username: "testuser", Role: "user", IsActive: true, } err = db.Create(user).Error require.NoError(t, err) // Insérer un token expiresAt := time.Now().Add(1 * time.Hour) err = db.Exec(` INSERT INTO password_reset_tokens (user_id, token, expires_at, used, created_at) VALUES (?, ?, ?, ?, ?) `, user.ID, "unique-token", expiresAt, false, time.Now()).Error require.NoError(t, err, "Should be able to insert first token") // Tenter d'insérer un token avec le même token (devrait échouer) err = db.Exec(` INSERT INTO password_reset_tokens (user_id, token, expires_at, used, created_at) VALUES (?, ?, ?, ?, ?) `, user.ID, "unique-token", expiresAt, false, time.Now()).Error assert.Error(t, err, "Should not be able to insert duplicate token") }