212 lines
7.3 KiB
Go
212 lines
7.3 KiB
Go
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")
|
|
}
|