package middleware import ( "context" "net/http" "net/http/httptest" "testing" "github.com/gin-gonic/gin" "github.com/sundynix/sundynix-gateway/internal/store" ) type fakeSpaceRole struct{ role string } func (f fakeSpaceRole) SpaceMemberRole(context.Context, string, string) string { return f.role } func spaceGateEngine(uid, space, memberRole, minRole string) *gin.Engine { gin.SetMode(gin.TestMode) r := gin.New() r.Use(func(c *gin.Context) { if uid != "" { c.Set(CtxUserID, uid) } if space != "" { c.Set(CtxSpaceID, space) } c.Next() }) r.POST("/agents", RequireSpaceRole(fakeSpaceRole{role: memberRole}, minRole), func(c *gin.Context) { c.String(http.StatusOK, "saved") }) return r } func TestRequireSpaceRole_Gate(t *testing.T) { cases := []struct { name string uid string space string memberRole string wantCode int }{ {"owner 放行", "u1", "s1", store.RoleOwner, http.StatusOK}, {"admin 放行", "u1", "s1", store.RoleAdmin, http.StatusOK}, {"member 放行", "u1", "s1", store.RoleMember, http.StatusOK}, {"viewer 拦下(空间只读)", "u1", "s1", store.RoleViewer, http.StatusForbidden}, {"非空间成员 拦下", "u1", "s1", "", http.StatusForbidden}, {"未登录 401", "", "s1", store.RoleOwner, http.StatusUnauthorized}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { r := spaceGateEngine(tc.uid, tc.space, tc.memberRole, store.RoleMember) w := httptest.NewRecorder() r.ServeHTTP(w, httptest.NewRequest(http.MethodPost, "/agents", nil)) if w.Code != tc.wantCode { t.Errorf("状态码=%d, 期望 %d(body=%s)", w.Code, tc.wantCode, w.Body.String()) } }) } }