Download internal/auth/session_probe_test.go from a3216/ds2api: direct link, hf CLI and curl.
- Browser
- Download file 7.94 kB
-
https://huggingface.co/spaces/a3216/ds2api/resolve/main/internal/auth/session_probe_test.go
- Command line
-
hf download hf://spaces/a3216/ds2api/internal/auth/session_probe_test.go
-
curl -L -o session_probe_test.go https://huggingface.co/spaces/a3216/ds2api/resolve/main/internal/auth/session_probe_test.go
7.94 kB
| package auth | |
| import ( | |
| "context" | |
| "errors" | |
| "fmt" | |
| "sync/atomic" | |
| "testing" | |
| "time" | |
| "ds2api/internal/account" | |
| "ds2api/internal/config" | |
| ) | |
| func newProbeTestResolver(t *testing.T, login LoginFunc) (*Resolver, *config.Store) { | |
| t.Helper() | |
| t.Setenv("DS2API_CONFIG_JSON", `{ | |
| "keys":["managed-key"], | |
| "accounts":[{"email":"acc@example.com","password":"pwd"}] | |
| }`) | |
| store := config.LoadStore() | |
| if err := store.UpdateAccountToken("acc@example.com", "session-token"); err != nil { | |
| t.Fatalf("seed token failed: %v", err) | |
| } | |
| return NewResolver(store, account.NewPool(store), login), store | |
| } | |
| func newProbeTestAuth(token string) *RequestAuth { | |
| return &RequestAuth{ | |
| UseConfigToken: true, | |
| AccountID: "acc@example.com", | |
| Account: config.Account{Email: "acc@example.com", Password: "pwd", Token: token}, | |
| DeepSeekToken: token, | |
| TriedAccounts: map[string]bool{}, | |
| } | |
| } | |
| func countingLogin(loginCount *int32, token string) LoginFunc { | |
| return func(_ context.Context, _ config.Account) (string, error) { | |
| atomic.AddInt32(loginCount, 1) | |
| return token, nil | |
| } | |
| } | |
| // 探针确认会话仍有效时,刷新不应提交密码。 | |
| func TestRefreshTokenUsesProbeWithoutLogin(t *testing.T) { | |
| var loginCount int32 | |
| r, store := newProbeTestResolver(t, countingLogin(&loginCount, "login-token")) | |
| r.RefreshSession = func(_ context.Context, acc config.Account) (string, error) { | |
| if acc.Token != "session-token" { | |
| t.Fatalf("probe should see current token, got %q", acc.Token) | |
| } | |
| return "session-token", nil | |
| } | |
| a := newProbeTestAuth("session-token") | |
| if !r.RefreshToken(context.Background(), a) { | |
| t.Fatal("expected refresh to succeed via session probe") | |
| } | |
| if got := atomic.LoadInt32(&loginCount); got != 0 { | |
| t.Fatalf("expected no password login, got %d", got) | |
| } | |
| if a.DeepSeekToken != "session-token" { | |
| t.Fatalf("expected existing token to be kept, got %q", a.DeepSeekToken) | |
| } | |
| if token := findTestToken(t, store); token != "session-token" { | |
| t.Fatalf("expected persisted token unchanged, got %q", token) | |
| } | |
| } | |
| // 服务端主动轮换时,探针拿回的新 token 要落盘并生效。 | |
| func TestRefreshTokenAdoptsRotatedTokenFromProbe(t *testing.T) { | |
| var loginCount int32 | |
| r, store := newProbeTestResolver(t, countingLogin(&loginCount, "login-token")) | |
| r.RefreshSession = func(_ context.Context, _ config.Account) (string, error) { | |
| return "rotated-token", nil | |
| } | |
| a := newProbeTestAuth("session-token") | |
| if !r.RefreshToken(context.Background(), a) { | |
| t.Fatal("expected refresh to succeed via session probe") | |
| } | |
| if got := atomic.LoadInt32(&loginCount); got != 0 { | |
| t.Fatalf("expected no password login, got %d", got) | |
| } | |
| if a.DeepSeekToken != "rotated-token" { | |
| t.Fatalf("expected rotated token on auth, got %q", a.DeepSeekToken) | |
| } | |
| if token := findTestToken(t, store); token != "rotated-token" { | |
| t.Fatalf("expected rotated token persisted, got %q", token) | |
| } | |
| } | |
| // 探针明确判定会话失效时才回退到密码登录。 | |
| func TestRefreshTokenFallsBackToLoginWhenSessionRejected(t *testing.T) { | |
| var loginCount int32 | |
| r, store := newProbeTestResolver(t, countingLogin(&loginCount, "login-token")) | |
| r.RefreshSession = func(_ context.Context, _ config.Account) (string, error) { | |
| return "", fmt.Errorf("check session: %w", ErrSessionExpired) | |
| } | |
| a := newProbeTestAuth("session-token") | |
| if !r.RefreshToken(context.Background(), a) { | |
| t.Fatal("expected fallback login to succeed") | |
| } | |
| if got := atomic.LoadInt32(&loginCount); got != 1 { | |
| t.Fatalf("expected exactly one login, got %d", got) | |
| } | |
| if a.DeepSeekToken != "login-token" { | |
| t.Fatalf("expected login token, got %q", a.DeepSeekToken) | |
| } | |
| if token := findTestToken(t, store); token != "login-token" { | |
| t.Fatalf("expected login token persisted, got %q", token) | |
| } | |
| } | |
| // 探针无法判定时仍保留密码登录兜底,避免把可恢复的请求判死。 | |
| func TestRefreshTokenFallsBackToLoginWhenProbeInconclusive(t *testing.T) { | |
| var loginCount int32 | |
| r, _ := newProbeTestResolver(t, countingLogin(&loginCount, "login-token")) | |
| r.RefreshSession = func(_ context.Context, _ config.Account) (string, error) { | |
| return "", errors.New("dial tcp: connection refused") | |
| } | |
| a := newProbeTestAuth("session-token") | |
| if !r.RefreshToken(context.Background(), a) { | |
| t.Fatal("expected fallback login to succeed") | |
| } | |
| if got := atomic.LoadInt32(&loginCount); got != 1 { | |
| t.Fatalf("expected exactly one login, got %d", got) | |
| } | |
| if a.DeepSeekToken != "login-token" { | |
| t.Fatalf("expected login token, got %q", a.DeepSeekToken) | |
| } | |
| } | |
| // 定时体检:探针成功即完成,不应触发登录。 | |
| func TestScheduledRefreshUsesProbeWithoutLogin(t *testing.T) { | |
| var loginCount int32 | |
| r, _ := newProbeTestResolver(t, countingLogin(&loginCount, "login-token")) | |
| r.RefreshSession = func(_ context.Context, _ config.Account) (string, error) { | |
| return "session-token", nil | |
| } | |
| markRefreshDue(t, r) | |
| a := newProbeTestAuth("session-token") | |
| if err := r.ensureManagedToken(context.Background(), a); err != nil { | |
| t.Fatalf("ensure managed token failed: %v", err) | |
| } | |
| if got := atomic.LoadInt32(&loginCount); got != 0 { | |
| t.Fatalf("expected no password login, got %d", got) | |
| } | |
| if a.DeepSeekToken != "session-token" { | |
| t.Fatalf("expected token kept, got %q", a.DeepSeekToken) | |
| } | |
| } | |
| // 定时体检:探针结果不可判定时保留 token,不能因为一次网络抖动就提交密码。 | |
| func TestScheduledRefreshKeepsTokenWhenProbeInconclusive(t *testing.T) { | |
| var loginCount int32 | |
| r, _ := newProbeTestResolver(t, countingLogin(&loginCount, "login-token")) | |
| r.RefreshSession = func(_ context.Context, _ config.Account) (string, error) { | |
| return "", errors.New("connection reset by peer") | |
| } | |
| markRefreshDue(t, r) | |
| a := newProbeTestAuth("session-token") | |
| if err := r.ensureManagedToken(context.Background(), a); err != nil { | |
| t.Fatalf("ensure managed token failed: %v", err) | |
| } | |
| if got := atomic.LoadInt32(&loginCount); got != 0 { | |
| t.Fatalf("expected no password login on inconclusive probe, got %d", got) | |
| } | |
| if a.DeepSeekToken != "session-token" { | |
| t.Fatalf("expected token kept, got %q", a.DeepSeekToken) | |
| } | |
| } | |
| // 定时体检:探针明确判定失效时回退到密码登录。 | |
| func TestScheduledRefreshLogsInWhenSessionRejected(t *testing.T) { | |
| var loginCount int32 | |
| r, _ := newProbeTestResolver(t, countingLogin(&loginCount, "login-token")) | |
| r.RefreshSession = func(_ context.Context, _ config.Account) (string, error) { | |
| return "", ErrSessionExpired | |
| } | |
| markRefreshDue(t, r) | |
| a := newProbeTestAuth("session-token") | |
| if err := r.ensureManagedToken(context.Background(), a); err != nil { | |
| t.Fatalf("ensure managed token failed: %v", err) | |
| } | |
| if got := atomic.LoadInt32(&loginCount); got != 1 { | |
| t.Fatalf("expected exactly one login, got %d", got) | |
| } | |
| if a.DeepSeekToken != "login-token" { | |
| t.Fatalf("expected login token, got %q", a.DeepSeekToken) | |
| } | |
| } | |
| // 未注入探针时保持历史行为:定时到期直接登录。 | |
| func TestScheduledRefreshWithoutProbeFallsBackToLogin(t *testing.T) { | |
| var loginCount int32 | |
| r, _ := newProbeTestResolver(t, countingLogin(&loginCount, "login-token")) | |
| markRefreshDue(t, r) | |
| a := newProbeTestAuth("session-token") | |
| if err := r.ensureManagedToken(context.Background(), a); err != nil { | |
| t.Fatalf("ensure managed token failed: %v", err) | |
| } | |
| if got := atomic.LoadInt32(&loginCount); got != 1 { | |
| t.Fatalf("expected exactly one login, got %d", got) | |
| } | |
| } | |
| func markRefreshDue(t *testing.T, r *Resolver) { | |
| t.Helper() | |
| if err := r.Store.Update(func(c *config.Config) error { | |
| c.Runtime.TokenRefreshIntervalHours = 1 | |
| return nil | |
| }); err != nil { | |
| t.Fatalf("update runtime failed: %v", err) | |
| } | |
| r.mu.Lock() | |
| r.tokenRefreshedAt["acc@example.com"] = time.Now().Add(-2 * time.Hour) | |
| r.mu.Unlock() | |
| } | |
| func findTestToken(t *testing.T, store *config.Store) string { | |
| t.Helper() | |
| acc, ok := store.FindAccount("acc@example.com") | |
| if !ok { | |
| t.Fatal("account not found in store") | |
| } | |
| return acc.Token | |
| } | |