滑动续期、网络错误归类、API Key 激活乐观锁与生效提示
This commit is contained in:
@@ -8,9 +8,11 @@ import (
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/glebarez/sqlite"
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/logger"
|
||||
|
||||
@@ -122,6 +124,30 @@ func doRequest(t *testing.T, r *gin.Engine, method, path, token, body string) *h
|
||||
return w
|
||||
}
|
||||
|
||||
type apiTestClaims struct {
|
||||
jwt.RegisteredClaims
|
||||
Ver uint `json:"ver"`
|
||||
}
|
||||
|
||||
func shortAPIToken(t *testing.T, token string) string {
|
||||
t.Helper()
|
||||
claims := &apiTestClaims{}
|
||||
_, err := jwt.ParseWithClaims(token, claims, func(*jwt.Token) (any, error) {
|
||||
return []byte("test-secret"), nil
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("parse login token: %v", err)
|
||||
}
|
||||
now := time.Now()
|
||||
claims.IssuedAt = jwt.NewNumericDate(now)
|
||||
claims.ExpiresAt = jwt.NewNumericDate(now.Add(time.Hour))
|
||||
short, err := jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString([]byte("test-secret"))
|
||||
if err != nil {
|
||||
t.Fatalf("sign short token: %v", err)
|
||||
}
|
||||
return short
|
||||
}
|
||||
|
||||
func TestLoginEndpoint(t *testing.T) {
|
||||
r, _, _ := newTestRouter(t)
|
||||
tests := []struct {
|
||||
@@ -171,6 +197,26 @@ func TestSecuredRoutesRequireToken(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadRequestRenewsSession(t *testing.T) {
|
||||
r, auth, _ := newTestRouter(t)
|
||||
token, _, err := auth.Login(context.Background(), "admin", "pass123", "",
|
||||
service.SessionMeta{ClientIP: "127.0.0.1"})
|
||||
if err != nil {
|
||||
t.Fatalf("login: %v", err)
|
||||
}
|
||||
w := doRequest(t, r, http.MethodGet, "/api/v1/auth/credentials", shortAPIToken(t, token), "")
|
||||
if w.Code != http.StatusOK {
|
||||
t.Fatalf("status = %d, want 200, body %s", w.Code, w.Body.String())
|
||||
}
|
||||
renewed := w.Header().Get("X-Renewed-Token")
|
||||
if renewed == "" {
|
||||
t.Fatal("X-Renewed-Token 为空, want 只读请求续期")
|
||||
}
|
||||
if _, err := auth.ParseToken(context.Background(), renewed); err != nil {
|
||||
t.Errorf("renewed token invalid: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSystemLogsEndpoint(t *testing.T) {
|
||||
r, auth, logs := newTestRouter(t)
|
||||
token, _, err := auth.Login(context.Background(), "admin", "pass123", "", service.SessionMeta{ClientIP: "127.0.0.1"})
|
||||
@@ -245,11 +291,17 @@ func TestRevokeSessionsEndpoint(t *testing.T) {
|
||||
if err := json.Unmarshal(login.Body.Bytes(), &sess); err != nil || sess.Token == "" {
|
||||
t.Fatalf("login: %s", login.Body.String())
|
||||
}
|
||||
w := doRequest(t, r, http.MethodPost, "/api/v1/auth/revoke-sessions", sess.Token, "")
|
||||
short := shortAPIToken(t, sess.Token)
|
||||
w := doRequest(t, r, http.MethodPost, "/api/v1/auth/revoke-sessions", short, "")
|
||||
if w.Code != http.StatusOK || !strings.Contains(w.Body.String(), "token") {
|
||||
t.Fatalf("revoke = %d %s", w.Code, w.Body.String())
|
||||
}
|
||||
w = doRequest(t, r, http.MethodGet, "/api/v1/auth/credentials", sess.Token, "")
|
||||
for _, name := range []string{"X-Renewed-Token", "X-Renewed-Expires-At"} {
|
||||
if got := w.Header().Get(name); got != "" {
|
||||
t.Errorf("写请求 %s = %q, want empty", name, got)
|
||||
}
|
||||
}
|
||||
w = doRequest(t, r, http.MethodGet, "/api/v1/auth/credentials", short, "")
|
||||
if w.Code != http.StatusUnauthorized {
|
||||
t.Errorf("撤销后旧 token 访问 = %d, want 401", w.Code)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user