Files
backend/internal/middleware/verification_test.go
lan d9aa4b46c3
All checks were successful
Build Backend / build (push) Successful in 4m55s
Build Backend / build-docker (push) Successful in 10m34s
refactor(server): decouple services and improve architecture
- Introduce interfaces for all major services (JWT, PostAI, Comment, Message, Notification, QRCodeLogin, Upload, Vote, etc.) to support dependency inversion.
- Move query parameters from `internal/dto` to a new `internal/query` package to separate request payloads from data transfer objects.
- Refactor `internal/router` to use embedded `RouterDeps` for cleaner dependency management.
- Decouple handlers from repositories by injecting services instead of direct repository access, ensuring proper layering.
- Improve database initialization by moving it from `internal/model` to `internal/database`.
- Optimize message decryption by implementing a more efficient `BatchDecrypt` method in `MessageEncryptor` using a worker pool.
- Enhance error handling and security by implementing fail-fast checks for encryption key length during startup.
- Clean up unused code, including the `avatar` package and several unused DTOs.
2026-06-15 03:41:59 +08:00

111 lines
3.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package middleware
import (
"context"
"errors"
"net/http"
"net/http/httptest"
"testing"
"with_you/internal/model"
"with_you/internal/service"
"github.com/gin-gonic/gin"
)
// stubUserService 通过嵌入 service.UserService 接口nil仅覆盖 GetUserByID。
// 未覆盖方法若被调用会 panic可在测试中暴露非预期的依赖调用。
type stubUserService struct {
service.UserService // nil 嵌入
user *model.User
err error
}
func (s *stubUserService) GetUserByID(ctx context.Context, id string) (*model.User, error) {
if s.err != nil {
return nil, s.err
}
return s.user, nil
}
// runMiddleware 构造一个 gin 引擎,挂载 RequireVerified + 一个标记 handler
// 发起请求并返回 (status, body, nextCalled)。
func runMiddleware(t *testing.T, svc service.UserService, setUserID bool, userID any) (int, bool) {
t.Helper()
gin.SetMode(gin.TestMode)
nextCalled := false
r := gin.New()
r.Use(func(c *gin.Context) {
if setUserID {
c.Set("user_id", userID)
}
c.Next()
})
r.GET("/test", RequireVerified(svc), func(c *gin.Context) {
nextCalled = true
c.JSON(http.StatusOK, gin.H{"ok": true})
})
w := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, "/test", nil)
r.ServeHTTP(w, req)
return w.Code, nextCalled
}
// TestRequireVerified_Approved 已认证用户 → 放行200next 被调用)。
func TestRequireVerified_Approved(t *testing.T) {
svc := &stubUserService{
user: &model.User{ID: "u1", VerificationStatus: model.VerificationStatusApproved},
}
code, next := runMiddleware(t, svc, true, "u1")
if code != http.StatusOK {
t.Errorf("status = %d, want %d", code, http.StatusOK)
}
if !next {
t.Error("next handler should be called for verified user")
}
}
// TestRequireVerified_NotApproved 未通过认证用户 → 403 VERIFICATION_REQUIRED。
func TestRequireVerified_NotApproved(t *testing.T) {
svc := &stubUserService{
user: &model.User{ID: "u1", VerificationStatus: model.VerificationStatusPending},
}
code, next := runMiddleware(t, svc, true, "u1")
if code != http.StatusForbidden {
t.Errorf("status = %d, want %d", code, http.StatusForbidden)
}
if next {
t.Error("next handler should NOT be called for unverified user")
}
}
// TestRequireVerified_UserLookupError 查询用户失败 → 500。
func TestRequireVerified_UserLookupError(t *testing.T) {
svc := &stubUserService{err: errors.New("db down")}
code, next := runMiddleware(t, svc, true, "u1")
if code != http.StatusInternalServerError {
t.Errorf("status = %d, want %d", code, http.StatusInternalServerError)
}
if next {
t.Error("next handler should NOT be called on lookup error")
}
}
// TestRequireVerified_NoUserID 未登录(无 user_id→ 401。
func TestRequireVerified_NoUserID(t *testing.T) {
svc := &stubUserService{
user: &model.User{ID: "u1", VerificationStatus: model.VerificationStatusApproved},
}
code, next := runMiddleware(t, svc, false, nil)
if code != http.StatusUnauthorized {
t.Errorf("status = %d, want %d", code, http.StatusUnauthorized)
}
if next {
t.Error("next handler should NOT be called when user_id missing")
}
}