mirror of
https://github.com/truewhile/MeBox.git
synced 2026-09-30 03:36:37 +08:00
95 lines
3.0 KiB
Go
95 lines
3.0 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/ShukeBta/MediaStationGo/internal/model"
|
|
)
|
|
|
|
func TestRegistrationCodeRedeemOnce(t *testing.T) {
|
|
ctx := context.Background()
|
|
repos, bot := newBotTestService(t)
|
|
|
|
code, err := bot.generateCode(ctx, model.RegistrationCodeRenew, 30, 0, "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// 首次校验通过
|
|
rc, msg := bot.lookupRedeemableCode(ctx, code.Code, model.RegistrationCodeRenew)
|
|
if rc == nil {
|
|
t.Fatalf("expected valid code, got msg=%q", msg)
|
|
}
|
|
// 标记使用后不可再用
|
|
if err := repos.RegCode.MarkUsed(ctx, rc.ID, "user-1"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, msg := bot.lookupRedeemableCode(ctx, code.Code, model.RegistrationCodeRenew); msg == "" {
|
|
t.Fatal("used code must not validate again")
|
|
}
|
|
// 第二次 MarkUsed 应失败(防止双花)
|
|
if err := repos.RegCode.MarkUsed(ctx, rc.ID, "user-2"); err == nil {
|
|
t.Fatal("double-spend should be rejected")
|
|
}
|
|
// 类型不匹配应被拒
|
|
reg, _ := bot.generateCode(ctx, model.RegistrationCodeRegister, 0, 0, "")
|
|
if _, msg := bot.lookupRedeemableCode(ctx, reg.Code, model.RegistrationCodeRenew); msg == "" {
|
|
t.Fatal("register code should not validate as renew")
|
|
}
|
|
}
|
|
|
|
func TestRegistrationCodeCanBeGeneratedForMultipleUses(t *testing.T) {
|
|
ctx := context.Background()
|
|
repos, bot := newBotTestService(t)
|
|
|
|
code, err := bot.generateCodeWithUses(ctx, model.RegistrationCodeRenew, 30, 0, 2, "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
rc, msg := bot.lookupRedeemableCode(ctx, code.Code, model.RegistrationCodeRenew)
|
|
if rc == nil {
|
|
t.Fatalf("expected valid code, got msg=%q", msg)
|
|
}
|
|
if err := repos.RegCode.MarkUsed(ctx, rc.ID, "user-1"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
rc, msg = bot.lookupRedeemableCode(ctx, code.Code, model.RegistrationCodeRenew)
|
|
if rc == nil {
|
|
t.Fatalf("code should remain redeemable after first use, got msg=%q", msg)
|
|
}
|
|
if err := repos.RegCode.MarkUsed(ctx, rc.ID, "user-2"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, msg := bot.lookupRedeemableCode(ctx, code.Code, model.RegistrationCodeRenew); msg == "" {
|
|
t.Fatal("code should be exhausted after max uses")
|
|
}
|
|
var used model.RegistrationCode
|
|
if err := repos.DB.Where("id = ?", code.ID).First(&used).Error; err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if used.UsedCount != 2 || used.UsedAt == nil {
|
|
t.Fatalf("expected exhausted code with used_count=2, got %+v", used)
|
|
}
|
|
}
|
|
|
|
func TestRenewalClearsExpiry(t *testing.T) {
|
|
ctx := context.Background()
|
|
repos, bot := newBotTestService(t)
|
|
past := time.Now().Add(-time.Hour)
|
|
u := &model.User{Username: "bob", PasswordHash: "x", Role: "user", IsActive: false, ExpiredAt: &past}
|
|
if err := repos.User.Create(ctx, u); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := bot.applyRenewal(ctx, u.ID, 30); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got, _ := repos.User.FindByID(ctx, u.ID)
|
|
if !got.IsActive {
|
|
t.Fatal("renewal should re-activate account")
|
|
}
|
|
if got.ExpiredAt == nil || got.ExpiredAt.Before(time.Now()) {
|
|
t.Fatalf("renewal should set future expiry, got %v", got.ExpiredAt)
|
|
}
|
|
}
|