50 lines
1.7 KiB
Go
50 lines
1.7 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"infinite-canvas/backend/internal/model"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestRegistrationCooldownAndFailedSMTPDoesNotBlockRetry(t *testing.T) {
|
|
svc, db := newPasswordResetTestService(t)
|
|
db.Create(&model.User{ID: "admin", Username: "admin", Role: model.UserRoleAdmin, Status: model.UserStatusActive})
|
|
db.Create(&model.SystemSetting{Key: registrationSettingKey, ValueJSON: `{"enabled":true}`})
|
|
svc.mailSender = func(emailSettingValue, string, string, string) error { return errors.New("synthetic SMTP failure") }
|
|
if err := svc.SendRegistrationEmailCode("new@example.com"); err == nil {
|
|
t.Fatal("SMTP error hidden")
|
|
}
|
|
sent := 0
|
|
svc.mailSender = func(emailSettingValue, string, string, string) error { sent++; return nil }
|
|
if err := svc.SendRegistrationEmailCode("new@example.com"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var cooldown *EmailCodeCooldownError
|
|
if err := svc.SendRegistrationEmailCode("new@example.com"); !errors.As(err, &cooldown) || cooldown.Seconds < 58 || cooldown.Seconds > 60 {
|
|
t.Fatalf("cooldown: %v", err)
|
|
}
|
|
if sent != 1 {
|
|
t.Fatal("duplicate mail sent")
|
|
}
|
|
}
|
|
|
|
func TestRequestRetryAfterMatchesWindow(t *testing.T) {
|
|
s := &Service{coordinator: &runtimeCoordinator{localRate: map[string]localRateEntry{}}}
|
|
ctx := context.Background()
|
|
if ok, err := s.AllowRequest(ctx, "email-code:test", 1, time.Hour); err != nil || !ok {
|
|
t.Fatal(err)
|
|
}
|
|
if ok, _ := s.AllowRequest(ctx, "email-code:test", 1, time.Hour); ok {
|
|
t.Fatal("limit bypassed")
|
|
}
|
|
wait := s.RequestRetryAfter(ctx, "email-code:test", time.Hour)
|
|
if wait < 59*time.Minute || wait > time.Hour {
|
|
t.Fatalf("wrong wait: %v", wait)
|
|
}
|
|
if s.coordinator.localRate["email-code:test"].count != 1 {
|
|
t.Fatal("rejection consumed quota")
|
|
}
|
|
}
|