Files
go-admin/common/actions/permission_test.go
T
zhangwenjian f4e3f04d30 refactor🎨: turn common/actions' data permission into a thin forward
DataPermission, PermissionAction, Permission, GetPermissionFromContext,
IsValidDataScope, PermissionKey and the five DataScope* constants now
forward to go-admin-core's sdk/contract/actions, which carries the
already-fixed logic from feat/006-security-prereq (PRD 006 F14/H1-H3).
create.go/delete.go/index.go/update.go/view.go - the five generic CRUD
actions - are untouched: they call Permission and
GetPermissionFromContext by the same names, which now resolve to
forwards with identical behaviour, and stay in this package rather
than moving to core (PRD 006 F3: core's exports are a permanent
promise every fork inherits, and CRUD shape is this framework's most
volatile surface).

PermissionKey is declared as `const PermissionKey =
contractactions.PermissionKey`, a direct reference rather than a
restated literal, per PRD 006's hard constraint 4: PermissionAction
sets this gin context key and GetPermissionFromContext reads it back,
and an independently declared copy could silently drift from core's if
one were ever edited without the other. permission_test.go replaces
the detailed data-permission regression suite - which now lives in
core, next to the logic itself - with a test of this package's own
wiring: that PermissionAction and both of this package's own read
paths (GetPermissionFromContext, and c.Get(actions.PermissionKey)
directly) still meet on the same key.

Counterproof performed and reverted (not part of this commit): with
PermissionKey redeclared here as the literal "dataPermission" and
core's copy changed to a different value, TestPermissionKeyMatches-
WhatPermissionActionSets went red while GetPermissionFromContext's own
round-trip stayed green - confirming the exported constant, not the
GetPermissionFromContext wrapper, is what an independent literal would
put at risk.

PRD 006 F3/F5.

Claude-Session: https://claude.ai/code/session_01HPTAw8b8tAdFNFn8rKdPYx
2026-09-05 10:15:58 +08:00

107 lines
4.2 KiB
Go

package actions_test
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/gin-gonic/gin"
jwt "github.com/go-admin-team/go-admin-core/v2/jwtauth"
"github.com/go-admin-team/go-admin-core/v2/sdk/config"
"go-admin/common/actions"
)
// The detailed data-permission regression suite (claims parsing, the
// GetOrm-unavailable abort, the SQL each data scope produces) now lives in
// go-admin-core's sdk/contract/actions, alongside the logic itself (PRD 006
// F3). What is left to test here is the shim's own wiring: that this
// package's exported names still round-trip through the same *gin.Context
// key core's PermissionAction and GetPermissionFromContext use.
//
// This file lives in package actions_test, an external test, deliberately:
// it exercises PermissionAction and GetPermissionFromContext exactly as an
// app/admin Service does, through this package's public API only, not
// through anything internal a forward could paper over.
// TestPermissionKeyMatchesWhatPermissionActionSets guards PRD 006's hard
// constraint 4: PermissionKey must be declared as
// `const PermissionKey = contractactions.PermissionKey`, a direct
// reference, never a restated literal (see type.go). PermissionAction is
// core's middleware and always writes under core's own key. This test reads
// the value back with actions.PermissionKey exactly as code outside
// GetPermissionFromContext would - c.Get(actions.PermissionKey) is a real,
// if uncommon, way to read the value go-admin has always allowed, and it is
// the one call site where an independently declared PermissionKey would
// stop working without GetPermissionFromContext's own forward hiding it.
//
// If PermissionKey were ever re-declared as an independent literal in this
// package, a later edit to core's copy would make this test fail without a
// single byte of this package having changed - which is the silent-failure
// mode hard constraint 4 exists to rule out (evaluation S2).
func TestPermissionKeyMatchesWhatPermissionActionSets(t *testing.T) {
previous := config.ApplicationConfig.EnableDP
config.ApplicationConfig.EnableDP = true
t.Cleanup(func() { config.ApplicationConfig.EnableDP = previous })
gin.SetMode(gin.TestMode)
c, _ := gin.CreateTestContext(httptest.NewRecorder())
c.Request = httptest.NewRequest(http.MethodGet, "/", nil)
c.Set(jwt.JwtPayloadKey, jwt.MapClaims{
"identity": float64(7),
"roleid": float64(3),
"deptid": float64(5),
"datascope": actions.DataScopeDeptTree,
})
actions.PermissionAction()(c)
value, ok := c.Get(actions.PermissionKey)
if !ok {
t.Fatal("PermissionAction did not set the key actions.PermissionKey names; the two have diverged")
}
p, ok := value.(*actions.DataPermission)
if !ok || p.DataScope != actions.DataScopeDeptTree || p.DeptId != 5 {
t.Fatalf("value under actions.PermissionKey = %#v, want a DataPermission carrying the token's scope", value)
}
}
// TestGetPermissionFromContextRoundTrips is the same guard from the other
// exported entry point: GetPermissionFromContext must read back exactly
// what PermissionAction wrote, both reached through this package's own
// forwards rather than core's directly.
func TestGetPermissionFromContextRoundTrips(t *testing.T) {
previous := config.ApplicationConfig.EnableDP
config.ApplicationConfig.EnableDP = true
t.Cleanup(func() { config.ApplicationConfig.EnableDP = previous })
gin.SetMode(gin.TestMode)
c, _ := gin.CreateTestContext(httptest.NewRecorder())
c.Request = httptest.NewRequest(http.MethodGet, "/", nil)
c.Set(jwt.JwtPayloadKey, jwt.MapClaims{
"identity": float64(7),
"roleid": float64(3),
"deptid": float64(5),
"datascope": actions.DataScopeSelf,
})
actions.PermissionAction()(c)
p := actions.GetPermissionFromContext(c)
if p.DataScope != actions.DataScopeSelf || p.UserId != 7 {
t.Fatalf("GetPermissionFromContext() = %+v, want DataScope=%q UserId=7", p, actions.DataScopeSelf)
}
}
func TestIsValidDataScope(t *testing.T) {
for _, s := range []string{actions.DataScopeAll, actions.DataScopeCustom, actions.DataScopeDept, actions.DataScopeDeptTree, actions.DataScopeSelf} {
if !actions.IsValidDataScope(s) {
t.Errorf("IsValidDataScope(%q) = false, want true", s)
}
}
if actions.IsValidDataScope("6") {
t.Error(`IsValidDataScope("6") = true, want false`)
}
}