Files
Edu/services/api-gateway/internal/middleware/admin_role_test.go

188 lines
5.0 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 (
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"github.com/gin-gonic/gin"
)
// setupAdminRoleRouter 构造一个仅含 AdminRoleMiddleware 的 gin 路由用于测试。
// nextCalled 标记后续 handler 是否被调用。
func setupAdminRoleRouter(t *testing.T) (*gin.Engine, *bool) {
t.Helper()
gin.SetMode(gin.TestMode)
r := gin.New()
called := false
r.Use(AdminRoleMiddleware())
r.Any("/test", func(c *gin.Context) {
called = true
c.Status(http.StatusOK)
})
return r, &called
}
// parseActionState 解析 ActionState 错误信封,返回 success/code/message。
func parseActionState(t *testing.T, w *httptest.ResponseRecorder) (bool, string, string) {
t.Helper()
var body struct {
Success bool `json:"success"`
Error struct {
Code string `json:"code"`
Message string `json:"message"`
} `json:"error"`
}
if err := json.Unmarshal(w.Body.Bytes(), &body); err != nil {
t.Fatalf("解析响应体失败: %v, body=%s", err, w.Body.String())
}
return body.Success, body.Error.Code, body.Error.Message
}
func TestAdminRoleMiddleware_PassesWhenAdminOnly(t *testing.T) {
r, called := setupAdminRoleRouter(t)
req := httptest.NewRequest(http.MethodGet, "/test", nil)
req.Header.Set("x-user-roles", "admin")
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
if w.Code != http.StatusOK {
t.Fatalf("纯 admin 角色应通过,期望 200实际 %d", w.Code)
}
if !*called {
t.Fatal("下游 handler 应被调用")
}
}
func TestAdminRoleMiddleware_PassesWhenAdminInList(t *testing.T) {
r, called := setupAdminRoleRouter(t)
// 多角色列表中包含 admin
req := httptest.NewRequest(http.MethodGet, "/test", nil)
req.Header.Set("x-user-roles", "teacher,admin")
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
if w.Code != http.StatusOK {
t.Fatalf("多角色包含 admin 应通过,期望 200实际 %d", w.Code)
}
if !*called {
t.Fatal("下游 handler 应被调用")
}
}
func TestAdminRoleMiddleware_RejectsWhenMissingRolesHeader(t *testing.T) {
r, called := setupAdminRoleRouter(t)
req := httptest.NewRequest(http.MethodGet, "/test", nil)
// 不设置 x-user-roles 头
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
if w.Code != http.StatusForbidden {
t.Fatalf("缺失 roles 头期望 403实际 %d", w.Code)
}
if *called {
t.Fatal("下游 handler 不应被调用")
}
success, code, _ := parseActionState(t, w)
if success {
t.Fatal("响应 success 应为 false")
}
if code != "GW_FORBIDDEN" {
t.Fatalf("错误码应为 GW_FORBIDDEN实际 %s", code)
}
}
func TestAdminRoleMiddleware_RejectsWhenNoAdminRole(t *testing.T) {
r, called := setupAdminRoleRouter(t)
req := httptest.NewRequest(http.MethodGet, "/test", nil)
req.Header.Set("x-user-roles", "teacher")
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
if w.Code != http.StatusForbidden {
t.Fatalf("非 admin 角色期望 403实际 %d", w.Code)
}
if *called {
t.Fatal("下游 handler 不应被调用")
}
_, code, msg := parseActionState(t, w)
if code != "GW_FORBIDDEN" {
t.Fatalf("错误码应为 GW_FORBIDDEN实际 %s", code)
}
if msg != "admin role required" {
t.Fatalf("错误消息应为 'admin role required',实际 %s", msg)
}
}
func TestAdminRoleMiddleware_RejectsStudentRole(t *testing.T) {
r, called := setupAdminRoleRouter(t)
req := httptest.NewRequest(http.MethodGet, "/test", nil)
req.Header.Set("x-user-roles", "student,parent")
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
if w.Code != http.StatusForbidden {
t.Fatalf("student/parent 角色期望 403实际 %d", w.Code)
}
if *called {
t.Fatal("下游 handler 不应被调用")
}
}
func TestAdminRoleMiddleware_RejectsEmptyRolesHeader(t *testing.T) {
r, called := setupAdminRoleRouter(t)
req := httptest.NewRequest(http.MethodGet, "/test", nil)
req.Header.Set("x-user-roles", "")
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
// 空字符串会被视为缺失 roles 头
if w.Code != http.StatusForbidden {
t.Fatalf("空 roles 头期望 403实际 %d", w.Code)
}
if *called {
t.Fatal("下游 handler 不应被调用")
}
}
func TestAdminRoleMiddleware_CaseSensitive(t *testing.T) {
r, called := setupAdminRoleRouter(t)
// "Admin"(大写)不应通过(大小写敏感)
req := httptest.NewRequest(http.MethodGet, "/test", nil)
req.Header.Set("x-user-roles", "Admin")
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
if w.Code != http.StatusForbidden {
t.Fatalf("'Admin'(大写)不应通过,期望 403实际 %d", w.Code)
}
if *called {
t.Fatal("下游 handler 不应被调用")
}
}
func TestHasAdminRole_Variants(t *testing.T) {
cases := []struct {
input string
want bool
}{
{"admin", true},
{"teacher,admin", true},
{"admin,teacher", true},
{" teacher , admin ", true}, // 含空格
{"teacher", false},
{"student,parent", false},
{"", false},
{"Admin", false}, // 大小写敏感
{"administrator", false},
{"admin-role", false},
}
for _, c := range cases {
got := hasAdminRole(c.input)
if got != c.want {
t.Errorf("hasAdminRole(%q) = %v, want %v", c.input, got, c.want)
}
}
}