veza/veza-backend-api/internal/database/migrations_password_reset_test.go
2026-03-05 23:03:43 +01:00

213 lines
7.3 KiB
Go

package database
import (
"testing"
"time"
"veza-backend-api/internal/models"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
// 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")
}