Files
MeBox/internal/service/token_svc_pending_test.go
T

71 lines
2.4 KiB
Go

package service
import (
"testing"
"time"
"go.uber.org/zap"
"github.com/ShukeBta/MediaStationGo/internal/config"
"github.com/ShukeBta/MediaStationGo/internal/model"
"github.com/ShukeBta/MediaStationGo/internal/repository"
)
func newTokenTestRepo(t *testing.T) *repository.Container {
t.Helper()
db := newServiceTestDB(t, &model.User{}, &model.RefreshToken{}, &model.Setting{})
return repository.New(db)
}
// TestRefreshAcceptsPendingDelayedToken 验证:登录时因 SQLite 写压力未及时
// 落库的 refresh token(仍在后台补写队列中)在刷新时被接受,而不是把用户
// 踢回登录页(历史上「经常登录报错」的来源之一)。
func TestRefreshAcceptsPendingDelayedToken(t *testing.T) {
repos := newTokenTestRepo(t)
cfg := &config.Config{}
cfg.Secrets.JWTSecret = "test-secret"
svc := NewTokenService(cfg, zap.NewNop(), repos)
u := &model.User{Username: "u1", PasswordHash: "x", Role: "user", Tier: "free", IsActive: true}
if err := repos.User.Create(t.Context(), u); err != nil {
t.Fatal(err)
}
refreshToken := "pending-token-value"
hash := repository.HashToken(refreshToken)
if !svc.trackDelayedStore(u.ID, hash, time.Now().Add(time.Hour)) {
t.Fatal("trackDelayedStore returned false")
}
pair, err := svc.Refresh(t.Context(), refreshToken)
if err != nil {
t.Fatalf("Refresh rejected pending delayed token: %v", err)
}
if pair == nil || pair.AccessToken == "" || pair.RefreshToken == "" {
t.Fatalf("Refresh returned incomplete pair: %+v", pair)
}
// 轮换后旧令牌应从 pending 表移除,不能再次使用。
if _, still := svc.pendingDelayedStore(hash); still {
t.Fatal("rotated pending token still tracked")
}
if _, err := svc.Refresh(t.Context(), refreshToken); err == nil {
t.Fatal("rotated pending token should not refresh twice")
}
}
// TestRefreshRejectsExpiredPendingToken 验证过期的待落库令牌不会被接受。
func TestRefreshRejectsExpiredPendingToken(t *testing.T) {
repos := newTokenTestRepo(t)
cfg := &config.Config{}
cfg.Secrets.JWTSecret = "test-secret"
svc := NewTokenService(cfg, zap.NewNop(), repos)
refreshToken := "expired-pending"
hash := repository.HashToken(refreshToken)
svc.trackDelayedStore("user-x", hash, time.Now().Add(-time.Minute))
if _, err := svc.Refresh(t.Context(), refreshToken); err == nil {
t.Fatal("expired pending token should be rejected")
}
}