package middleware import ( "encoding/json" "net/http" "net/http/httptest" "testing" "github.com/gin-gonic/gin" "github.com/stretchr/testify/assert" ) // TestReadOnly 验证只读角色的写操作被拦截、读操作放行,且 403 带机器可读 code。 func TestReadOnly(t *testing.T) { gin.SetMode(gin.TestMode) // invoke 跑一次带 ReadOnly 的请求,返回(是否被拦截, 状态码, body)。 invoke := func(role, method string) (bool, int, map[string]any) { w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) c.Request = httptest.NewRequest(method, "/products", nil) c.Set(CtxRole, role) ReadOnly()(c) var body map[string]any _ = json.Unmarshal(w.Body.Bytes(), &body) return c.IsAborted(), w.Code, body } // 只读角色 + 写方法 → 403 + code=READONLY_USER for _, m := range []string{http.MethodPost, http.MethodPut, http.MethodDelete, http.MethodPatch} { aborted, code, body := invoke("readonly", m) assert.True(t, aborted, "readonly 用户 %s 应被拦截", m) assert.Equal(t, http.StatusForbidden, code) assert.Equal(t, "READONLY_USER", body["code"], "%s 应返回 code=READONLY_USER", m) } // 只读角色 + GET → 放行 aborted, _, _ := invoke("readonly", http.MethodGet) assert.False(t, aborted, "readonly 用户 GET 应放行") // 非只读角色 + 写方法 → 放行 for _, role := range []string{"operator", "admin", "superadmin"} { aborted, _, _ := invoke(role, http.MethodPost) assert.False(t, aborted, "%s 用户写操作应放行", role) } }