mirror of
https://github.com/truewhile/MeBox.git
synced 2026-09-30 03:36:37 +08:00
136 lines
4.5 KiB
Go
136 lines
4.5 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/ShukeBta/MediaStationGo/internal/config"
|
|
"github.com/ShukeBta/MediaStationGo/internal/model"
|
|
"github.com/ShukeBta/MediaStationGo/internal/repository"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
func newBotTestService(t *testing.T) (*repository.Container, *TelegramBotService) {
|
|
t.Helper()
|
|
db := newServiceTestDB(t, model.AllModels()...)
|
|
repos := repository.New(db)
|
|
cfg := &config.Config{}
|
|
cfg.Secrets.JWTSecret = "test-secret"
|
|
log := zap.NewNop()
|
|
perms := NewPermissionService(log, repos)
|
|
tokenSvc := NewTokenService(cfg, log, repos)
|
|
auth := NewAuthService(cfg, log, repos, tokenSvc, perms)
|
|
crypto := NewCryptoService("test-secret", log)
|
|
bot := NewTelegramBotService(log, repos, crypto, auth)
|
|
return repos, bot
|
|
}
|
|
|
|
// ── pure logic ──────────────────────────────────────────────────────────────
|
|
|
|
func TestRenewExpiry(t *testing.T) {
|
|
// 永久(0 天)→ nil
|
|
if got := renewExpiry(nil, 0); got != nil {
|
|
t.Fatalf("expected nil for permanent, got %v", got)
|
|
}
|
|
// 从现在起 +30 天(当前为空)
|
|
got := renewExpiry(nil, 30)
|
|
if got == nil || got.Before(time.Now().Add(29*24*time.Hour)) {
|
|
t.Fatalf("expected ~30d expiry, got %v", got)
|
|
}
|
|
// 已有未来到期 → 在原到期基础上叠加
|
|
future := time.Now().Add(10 * 24 * time.Hour)
|
|
got = renewExpiry(&future, 30)
|
|
if got == nil || got.Before(future.Add(29*24*time.Hour)) {
|
|
t.Fatalf("expected stacking on future expiry, got %v", got)
|
|
}
|
|
// 已过期 → 从现在起算
|
|
past := time.Now().Add(-10 * 24 * time.Hour)
|
|
got = renewExpiry(&past, 5)
|
|
if got == nil || got.Before(time.Now().Add(4*24*time.Hour)) {
|
|
t.Fatalf("expected fresh window from now, got %v", got)
|
|
}
|
|
}
|
|
|
|
func TestCapacityRemaining(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
c capacityInfo
|
|
want int64
|
|
}{
|
|
{"license only", capacityInfo{UsedUsers: 5, MaxUsers: 20}, 15},
|
|
{"quota tighter", capacityInfo{UsedUsers: 5, MaxUsers: 100, OpenRegLimit: 10, OpenRegUsed: 3}, 7},
|
|
{"license tighter", capacityInfo{UsedUsers: 95, MaxUsers: 100, OpenRegLimit: 50, OpenRegUsed: 0}, 5},
|
|
{"full", capacityInfo{UsedUsers: 20, MaxUsers: 20}, 0},
|
|
{"quota exhausted", capacityInfo{UsedUsers: 1, MaxUsers: 100, OpenRegLimit: 5, OpenRegUsed: 5}, 0},
|
|
}
|
|
for _, tc := range cases {
|
|
if got := tc.c.Remaining(); got != tc.want {
|
|
t.Errorf("%s: Remaining()=%d want %d", tc.name, got, tc.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRandomWindowDays(t *testing.T) {
|
|
for i := 0; i < 200; i++ {
|
|
d := randomWindowDays(3, 5)
|
|
if d < 3 || d > 5 {
|
|
t.Fatalf("randomWindowDays(3,5)=%d out of range", d)
|
|
}
|
|
}
|
|
if d := randomWindowDays(4, 4); d != 4 {
|
|
t.Fatalf("randomWindowDays(4,4)=%d want 4", d)
|
|
}
|
|
}
|
|
|
|
func TestFingerprintStability(t *testing.T) {
|
|
a := fingerprint("Infuse", "iPhone")
|
|
b := fingerprint("infuse", " iPhone ")
|
|
if a != b {
|
|
t.Fatalf("fingerprint should be case/space-insensitive: %s != %s", a, b)
|
|
}
|
|
if a != fingerprint("Emby", "iPhone") {
|
|
t.Fatal("different apps on the same terminal must share one fingerprint")
|
|
}
|
|
if a == fingerprint("Infuse", "iPad") {
|
|
t.Fatal("different device names must yield different fingerprints")
|
|
}
|
|
}
|
|
|
|
// ── DB-backed ─────────────────────────────────────────────────────────────
|
|
|
|
func TestSignInStreak(t *testing.T) {
|
|
ctx := context.Background()
|
|
repos, bot := newBotTestService(t)
|
|
u := &model.User{Username: "alice", PasswordHash: "x", Role: "user"}
|
|
if err := repos.User.Create(ctx, u); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
res, err := bot.signIn(ctx, u.ID)
|
|
if err != nil || res.Streak != 1 || res.Total != 1 {
|
|
t.Fatalf("first sign-in: %+v err=%v", res, err)
|
|
}
|
|
// 同日重复签到 → 不增长
|
|
res, _ = bot.signIn(ctx, u.ID)
|
|
if !res.AlreadySigned || res.Streak != 1 {
|
|
t.Fatalf("same-day re-signin should be no-op: %+v", res)
|
|
}
|
|
// 模拟昨天签到 → 连续 +1
|
|
rec, _ := repos.SignIn.Get(ctx, u.ID)
|
|
rec.LastSignIn = time.Now().Add(-24 * time.Hour)
|
|
_ = repos.SignIn.Save(ctx, rec)
|
|
res, _ = bot.signIn(ctx, u.ID)
|
|
if res.Streak != 2 || res.Total != 2 {
|
|
t.Fatalf("consecutive day should bump streak: %+v", res)
|
|
}
|
|
// 中断(前天)→ 重置为 1
|
|
rec, _ = repos.SignIn.Get(ctx, u.ID)
|
|
rec.LastSignIn = time.Now().Add(-72 * time.Hour)
|
|
_ = repos.SignIn.Save(ctx, rec)
|
|
res, _ = bot.signIn(ctx, u.ID)
|
|
if res.Streak != 1 {
|
|
t.Fatalf("broken streak should reset to 1: %+v", res)
|
|
}
|
|
}
|