Files
ttstd-infinite-canvas/backend/internal/service/registration_limits_test.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")
}
}