229 lines
7.7 KiB
Go
229 lines
7.7 KiB
Go
package services
|
|
|
|
import (
|
|
"github.com/google/uuid"
|
|
"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"
|
|
)
|
|
|
|
// setupTestSessionServiceForT0204 crée un SessionService de test avec la table sessions
|
|
func setupTestSessionServiceForT0204(t *testing.T) (*SessionService, *gorm.DB, *database.Database) {
|
|
gormDB, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
|
|
require.NoError(t, err)
|
|
|
|
err = gormDB.AutoMigrate(&models.User{})
|
|
require.NoError(t, err)
|
|
|
|
// Créer la table sessions
|
|
err = gormDB.Exec(`
|
|
CREATE TABLE sessions (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
token_hash TEXT NOT NULL UNIQUE,
|
|
ip_address TEXT,
|
|
user_agent TEXT,
|
|
expires_at TIMESTAMP NOT NULL,
|
|
last_activity TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
)
|
|
`).Error
|
|
require.NoError(t, err)
|
|
|
|
user := &models.User{
|
|
Email: "test@example.com",
|
|
Username: "testuser",
|
|
Role: "user",
|
|
IsActive: true,
|
|
}
|
|
err = gormDB.Create(user).Error
|
|
require.NoError(t, err)
|
|
|
|
sqlDB, err := gormDB.DB()
|
|
require.NoError(t, err)
|
|
|
|
testDB := &database.Database{
|
|
DB: sqlDB,
|
|
}
|
|
|
|
logger, _ := zap.NewDevelopment()
|
|
service := NewSessionService(testDB, logger)
|
|
|
|
return service, gormDB, testDB
|
|
}
|
|
|
|
// TestUpdateLastActivityIfNeeded_Debounce teste que le debounce fonctionne correctement
|
|
func TestUpdateLastActivityIfNeeded_Debounce(t *testing.T) {
|
|
service, gormDB, _ := setupTestSessionServiceForT0204(t)
|
|
|
|
var user models.User
|
|
err := gormDB.First(&user).Error
|
|
require.NoError(t, err)
|
|
|
|
// Créer une session
|
|
token := "test-token-debounce"
|
|
ipAddress := "192.168.1.1"
|
|
userAgent := "Mozilla/5.0"
|
|
expiresAt := time.Now().Add(24 * time.Hour)
|
|
|
|
err = service.CreateSessionWithBIGINT(user.ID, token, ipAddress, userAgent, expiresAt)
|
|
require.NoError(t, err)
|
|
|
|
tokenHash := hashTokenForTest(token)
|
|
|
|
// Récupérer la session initiale
|
|
session, err := service.GetSessionWithBIGINT(tokenHash)
|
|
require.NoError(t, err)
|
|
initialLastActivity := session.LastActivity
|
|
|
|
// Attendre un peu
|
|
time.Sleep(50 * time.Millisecond)
|
|
|
|
// Première mise à jour (devrait mettre à jour)
|
|
err = service.UpdateLastActivityIfNeeded(tokenHash, 100*time.Millisecond)
|
|
assert.NoError(t, err)
|
|
|
|
// Vérifier que last_activity a été mis à jour
|
|
session, err = service.GetSessionWithBIGINT(tokenHash)
|
|
require.NoError(t, err)
|
|
assert.True(t, session.LastActivity.After(initialLastActivity), "First update should update last_activity")
|
|
|
|
// Deuxième mise à jour immédiatement (devrait être ignorée par debounce)
|
|
timeBeforeSecond := session.LastActivity
|
|
err = service.UpdateLastActivityIfNeeded(tokenHash, 100*time.Millisecond)
|
|
assert.NoError(t, err)
|
|
|
|
// Vérifier que last_activity n'a pas changé (debounce)
|
|
session, err = service.GetSessionWithBIGINT(tokenHash)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, timeBeforeSecond.Unix(), session.LastActivity.Unix(), "Second update should be debounced")
|
|
|
|
// Attendre plus que le debounce duration
|
|
time.Sleep(150 * time.Millisecond)
|
|
|
|
// Troisième mise à jour après le debounce (devrait mettre à jour)
|
|
err = service.UpdateLastActivityIfNeeded(tokenHash, 100*time.Millisecond)
|
|
assert.NoError(t, err)
|
|
|
|
// Vérifier que last_activity a été mis à jour
|
|
session, err = service.GetSessionWithBIGINT(tokenHash)
|
|
require.NoError(t, err)
|
|
assert.True(t, session.LastActivity.After(timeBeforeSecond), "Third update after debounce should update last_activity")
|
|
}
|
|
|
|
// TestUpdateLastActivityIfNeeded_ErrorHandling teste que les erreurs sont gérées silencieusement
|
|
func TestUpdateLastActivityIfNeeded_ErrorHandling(t *testing.T) {
|
|
service, _, _ := setupTestSessionServiceForT0204(t)
|
|
|
|
// Essayer de mettre à jour une session inexistante
|
|
// L'erreur ne doit pas être retournée (gestion silencieuse)
|
|
tokenHash := hashTokenForTest("non-existent-token")
|
|
err := service.UpdateLastActivityIfNeeded(tokenHash, 5*time.Minute)
|
|
assert.NoError(t, err, "Error should be handled silently")
|
|
}
|
|
|
|
// TestUpdateLastActivityIfNeeded_FirstUpdateAlwaysUpdates teste que la première mise à jour met toujours à jour
|
|
func TestUpdateLastActivityIfNeeded_FirstUpdateAlwaysUpdates(t *testing.T) {
|
|
service, gormDB, _ := setupTestSessionServiceForT0204(t)
|
|
|
|
var user models.User
|
|
err := gormDB.First(&user).Error
|
|
require.NoError(t, err)
|
|
|
|
// Créer une session
|
|
token := "test-token-first-update"
|
|
ipAddress := "192.168.1.1"
|
|
userAgent := "Mozilla/5.0"
|
|
expiresAt := time.Now().Add(24 * time.Hour)
|
|
|
|
err = service.CreateSessionWithBIGINT(user.ID, token, ipAddress, userAgent, expiresAt)
|
|
require.NoError(t, err)
|
|
|
|
tokenHash := hashTokenForTest(token)
|
|
|
|
// Récupérer la session initiale
|
|
session, err := service.GetSessionWithBIGINT(tokenHash)
|
|
require.NoError(t, err)
|
|
initialLastActivity := session.LastActivity
|
|
|
|
// Attendre un peu
|
|
time.Sleep(50 * time.Millisecond)
|
|
|
|
// Première mise à jour (devrait toujours mettre à jour)
|
|
err = service.UpdateLastActivityIfNeeded(tokenHash, 5*time.Minute)
|
|
assert.NoError(t, err)
|
|
|
|
// Vérifier que last_activity a été mis à jour
|
|
session, err = service.GetSessionWithBIGINT(tokenHash)
|
|
require.NoError(t, err)
|
|
assert.True(t, session.LastActivity.After(initialLastActivity), "First update should always update")
|
|
}
|
|
|
|
// TestUpdateLastActivityIfNeeded_MultipleTokens teste que le debounce fonctionne pour plusieurs tokens différents
|
|
func TestUpdateLastActivityIfNeeded_MultipleTokens(t *testing.T) {
|
|
service, gormDB, _ := setupTestSessionServiceForT0204(t)
|
|
|
|
var user models.User
|
|
err := gormDB.First(&user).Error
|
|
require.NoError(t, err)
|
|
|
|
// Créer deux sessions
|
|
token1 := "token-1"
|
|
token2 := "token-2"
|
|
ipAddress := "192.168.1.1"
|
|
userAgent := "Mozilla/5.0"
|
|
expiresAt := time.Now().Add(24 * time.Hour)
|
|
|
|
err = service.CreateSessionWithBIGINT(user.ID, token1, ipAddress, userAgent, expiresAt)
|
|
require.NoError(t, err)
|
|
err = service.CreateSessionWithBIGINT(user.ID, token2, ipAddress, userAgent, expiresAt)
|
|
require.NoError(t, err)
|
|
|
|
tokenHash1 := hashTokenForTest(token1)
|
|
tokenHash2 := hashTokenForTest(token2)
|
|
|
|
// Mettre à jour token1
|
|
err = service.UpdateLastActivityIfNeeded(tokenHash1, 100*time.Millisecond)
|
|
assert.NoError(t, err)
|
|
|
|
// Mettre à jour token2 immédiatement (devrait fonctionner car c'est un token différent)
|
|
err = service.UpdateLastActivityIfNeeded(tokenHash2, 100*time.Millisecond)
|
|
assert.NoError(t, err)
|
|
|
|
// Vérifier que les deux sessions ont été mises à jour
|
|
session1, err := service.GetSessionWithBIGINT(tokenHash1)
|
|
require.NoError(t, err)
|
|
session2, err := service.GetSessionWithBIGINT(tokenHash2)
|
|
require.NoError(t, err)
|
|
|
|
// Les deux devraient avoir été mises à jour (tokens différents)
|
|
assert.True(t, time.Since(session1.LastActivity) < 1*time.Second, "Session1 should be updated")
|
|
assert.True(t, time.Since(session2.LastActivity) < 1*time.Second, "Session2 should be updated")
|
|
}
|
|
|
|
// TestHashTokenForMiddleware teste que HashTokenForMiddleware retourne le bon hash
|
|
func TestHashTokenForMiddleware(t *testing.T) {
|
|
service, _, _ := setupTestSessionServiceForT0204(t)
|
|
|
|
token := "test-token-hash"
|
|
hash1 := service.HashTokenForMiddleware(token)
|
|
hash2 := service.HashTokenForMiddleware(token)
|
|
|
|
// Le hash doit être consistant
|
|
assert.Equal(t, hash1, hash2, "Hash should be consistent")
|
|
|
|
// Le hash doit être différent pour un token différent
|
|
token2 := "test-token-hash-2"
|
|
hash3 := service.HashTokenForMiddleware(token2)
|
|
assert.NotEqual(t, hash1, hash3, "Different tokens should have different hashes")
|
|
|
|
// Le hash doit avoir une longueur raisonnable (SHA256 = 64 caractères hex)
|
|
assert.Equal(t, 64, len(hash1), "SHA256 hash should be 64 characters")
|
|
}
|