Files
user-system/internal/repository/password_history_test.go

225 lines
5.9 KiB
Go

package repository
import (
"context"
"testing"
"time"
"github.com/user-management-system/internal/domain"
)
func TestPasswordHistoryRepository_Create(t *testing.T) {
db := openTestDB(t)
if err := db.AutoMigrate(&domain.PasswordHistory{}); err != nil {
t.Fatalf("migrate password_history failed: %v", err)
}
repo := NewPasswordHistoryRepository(db)
ctx := context.Background()
history := &domain.PasswordHistory{
UserID: 1,
PasswordHash: "hash1",
CreatedAt: time.Now(),
}
if err := repo.Create(ctx, history); err != nil {
t.Fatalf("create failed: %v", err)
}
if history.ID == 0 {
t.Error("expected ID to be set after create")
}
}
func TestPasswordHistoryRepository_GetByUserID(t *testing.T) {
db := openTestDB(t)
if err := db.AutoMigrate(&domain.PasswordHistory{}); err != nil {
t.Fatalf("migrate password_history failed: %v", err)
}
repo := NewPasswordHistoryRepository(db)
ctx := context.Background()
// Create multiple records for user 1
for i := 0; i < 5; i++ {
h := &domain.PasswordHistory{
UserID: 1,
PasswordHash: "hash",
CreatedAt: time.Now().Add(time.Duration(i) * time.Second),
}
if err := repo.Create(ctx, h); err != nil {
t.Fatalf("create failed: %v", err)
}
}
// Create record for user 2
if err := repo.Create(ctx, &domain.PasswordHistory{UserID: 2, PasswordHash: "hash", CreatedAt: time.Now()}); err != nil {
t.Fatalf("create failed: %v", err)
}
tests := []struct {
name string
userID int64
limit int
wantLen int
wantUser int64
}{
{"get all for user 1", 1, 10, 5, 1},
{"limit 3 for user 1", 1, 3, 3, 1},
{"get for user 2", 2, 10, 1, 2},
{"get for nonexistent user", 999, 10, 0, 999},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
histories, err := repo.GetByUserID(ctx, tc.userID, tc.limit)
if err != nil {
t.Fatalf("get failed: %v", err)
}
if len(histories) != tc.wantLen {
t.Errorf("expected %d histories, got %d", tc.wantLen, len(histories))
}
for _, h := range histories {
if h.UserID != tc.wantUser {
t.Errorf("expected user_id %d, got %d", tc.wantUser, h.UserID)
}
}
})
}
}
func TestPasswordHistoryRepository_GetByUserID_Order(t *testing.T) {
db := openTestDB(t)
if err := db.AutoMigrate(&domain.PasswordHistory{}); err != nil {
t.Fatalf("migrate password_history failed: %v", err)
}
repo := NewPasswordHistoryRepository(db)
ctx := context.Background()
// Create records with different timestamps
now := time.Now()
for i := 0; i < 3; i++ {
h := &domain.PasswordHistory{
UserID: 1,
PasswordHash: "hash",
CreatedAt: now.Add(time.Duration(i) * time.Hour),
}
if err := repo.Create(ctx, h); err != nil {
t.Fatalf("create failed: %v", err)
}
}
histories, err := repo.GetByUserID(ctx, 1, 10)
if err != nil {
t.Fatalf("get failed: %v", err)
}
if len(histories) != 3 {
t.Fatalf("expected 3 histories, got %d", len(histories))
}
// Should be ordered by created_at DESC (newest first)
for i := 0; i < len(histories)-1; i++ {
if !histories[i].CreatedAt.After(histories[i+1].CreatedAt) && !histories[i].CreatedAt.Equal(histories[i+1].CreatedAt) {
t.Errorf("expected descending order, got %v before %v", histories[i].CreatedAt, histories[i+1].CreatedAt)
}
}
}
func TestPasswordHistoryRepository_DeleteOldRecords(t *testing.T) {
db := openTestDB(t)
if err := db.AutoMigrate(&domain.PasswordHistory{}); err != nil {
t.Fatalf("migrate password_history failed: %v", err)
}
repo := NewPasswordHistoryRepository(db)
ctx := context.Background()
// Create 5 records for user 1
now := time.Now()
for i := 0; i < 5; i++ {
h := &domain.PasswordHistory{
UserID: 1,
PasswordHash: "hash",
CreatedAt: now.Add(time.Duration(i) * time.Hour),
}
if err := repo.Create(ctx, h); err != nil {
t.Fatalf("create failed: %v", err)
}
}
// Delete old records, keep only 3
if err := repo.DeleteOldRecords(ctx, 1, 3); err != nil {
t.Fatalf("delete old records failed: %v", err)
}
histories, err := repo.GetByUserID(ctx, 1, 10)
if err != nil {
t.Fatalf("get failed: %v", err)
}
if len(histories) != 3 {
t.Errorf("expected 3 histories after cleanup, got %d", len(histories))
}
}
func TestPasswordHistoryRepository_DeleteOldRecords_NoRecords(t *testing.T) {
db := openTestDB(t)
if err := db.AutoMigrate(&domain.PasswordHistory{}); err != nil {
t.Fatalf("migrate password_history failed: %v", err)
}
repo := NewPasswordHistoryRepository(db)
ctx := context.Background()
// Should not error when no records exist
if err := repo.DeleteOldRecords(ctx, 999, 3); err != nil {
t.Fatalf("delete old records on empty table should not error: %v", err)
}
}
func TestPasswordHistoryRepository_KeepsNewestRecords(t *testing.T) {
db := openTestDB(t)
if err := db.AutoMigrate(&domain.PasswordHistory{}); err != nil {
t.Fatalf("migrate password_history failed: %v", err)
}
repo := NewPasswordHistoryRepository(db)
ctx := context.Background()
// Create 5 records with different timestamps
now := time.Now()
var createdIDs []int64
for i := 0; i < 5; i++ {
h := &domain.PasswordHistory{
UserID: 1,
PasswordHash: "hash",
CreatedAt: now.Add(time.Duration(i) * time.Hour),
}
if err := repo.Create(ctx, h); err != nil {
t.Fatalf("create failed: %v", err)
}
createdIDs = append(createdIDs, h.ID)
}
// Delete old records, keep only 2
if err := repo.DeleteOldRecords(ctx, 1, 2); err != nil {
t.Fatalf("delete old records failed: %v", err)
}
histories, err := repo.GetByUserID(ctx, 1, 10)
if err != nil {
t.Fatalf("get failed: %v", err)
}
if len(histories) != 2 {
t.Fatalf("expected 2 histories after cleanup, got %d", len(histories))
}
// The remaining records should be the newest (last 2 created)
expectedIDs := map[int64]bool{createdIDs[3]: true, createdIDs[4]: true}
for _, h := range histories {
if !expectedIDs[h.ID] {
t.Errorf("expected remaining IDs to be %v, got %d", expectedIDs, h.ID)
}
}
}