456 lines
12 KiB
Go
456 lines
12 KiB
Go
|
|
package handler_test
|
||
|
|
|
||
|
|
import (
|
||
|
|
"encoding/json"
|
||
|
|
"fmt"
|
||
|
|
"net/http"
|
||
|
|
"testing"
|
||
|
|
)
|
||
|
|
|
||
|
|
func TestPermissionHandler_CreatePermission(t *testing.T) {
|
||
|
|
server, cleanup := setupHandlerTestServer(t)
|
||
|
|
defer cleanup()
|
||
|
|
|
||
|
|
t.Setenv("BOOTSTRAP_SECRET", "perm-bootstrap-secret")
|
||
|
|
adminToken := bootstrapAdmin(server.URL, "perm-bootstrap-secret", "permadmin", "permadmin@test.com", "AdminPass123!")
|
||
|
|
if adminToken == "" {
|
||
|
|
t.Fatal("bootstrap admin failed")
|
||
|
|
}
|
||
|
|
|
||
|
|
if ok := registerUser(server.URL, "permuser", "permuser@test.com", "UserPass123!"); !ok {
|
||
|
|
t.Fatal("register user failed")
|
||
|
|
}
|
||
|
|
userToken := getToken(server.URL, "permuser", "UserPass123!")
|
||
|
|
if userToken == "" {
|
||
|
|
t.Fatal("get user token failed")
|
||
|
|
}
|
||
|
|
|
||
|
|
tests := []struct {
|
||
|
|
name string
|
||
|
|
payload map[string]interface{}
|
||
|
|
token string
|
||
|
|
wantStatus int
|
||
|
|
}{
|
||
|
|
{
|
||
|
|
name: "success",
|
||
|
|
payload: map[string]interface{}{
|
||
|
|
"name": "Test Permission",
|
||
|
|
"code": "test:permission:create",
|
||
|
|
"type": 2,
|
||
|
|
},
|
||
|
|
token: adminToken,
|
||
|
|
wantStatus: http.StatusCreated,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "unauthorized",
|
||
|
|
payload: map[string]interface{}{
|
||
|
|
"name": "Test Permission",
|
||
|
|
"code": "test:permission:unauth",
|
||
|
|
"type": 2,
|
||
|
|
},
|
||
|
|
token: "",
|
||
|
|
wantStatus: http.StatusUnauthorized,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "forbidden",
|
||
|
|
payload: map[string]interface{}{
|
||
|
|
"name": "Test Permission",
|
||
|
|
"code": "test:permission:forbid",
|
||
|
|
"type": 2,
|
||
|
|
},
|
||
|
|
token: userToken,
|
||
|
|
wantStatus: http.StatusForbidden,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "invalid_type",
|
||
|
|
payload: map[string]interface{}{
|
||
|
|
"name": "Test Permission",
|
||
|
|
"code": "test:permission:badtype",
|
||
|
|
"type": 5,
|
||
|
|
},
|
||
|
|
token: adminToken,
|
||
|
|
wantStatus: http.StatusBadRequest,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "missing_required_fields",
|
||
|
|
payload: map[string]interface{}{"name": "Missing Code"},
|
||
|
|
token: adminToken,
|
||
|
|
wantStatus: http.StatusBadRequest,
|
||
|
|
},
|
||
|
|
}
|
||
|
|
|
||
|
|
for _, tt := range tests {
|
||
|
|
t.Run(tt.name, func(t *testing.T) {
|
||
|
|
resp, body := doPost(server.URL+"/api/v1/permissions", tt.token, tt.payload)
|
||
|
|
defer resp.Body.Close()
|
||
|
|
if resp.StatusCode != tt.wantStatus {
|
||
|
|
t.Errorf("expected status %d, got %d, body: %s", tt.wantStatus, resp.StatusCode, body)
|
||
|
|
}
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestPermissionHandler_ListPermissions(t *testing.T) {
|
||
|
|
server, cleanup := setupHandlerTestServer(t)
|
||
|
|
defer cleanup()
|
||
|
|
|
||
|
|
t.Setenv("BOOTSTRAP_SECRET", "perm-bootstrap-secret")
|
||
|
|
adminToken := bootstrapAdmin(server.URL, "perm-bootstrap-secret", "permadmin", "permadmin@test.com", "AdminPass123!")
|
||
|
|
if adminToken == "" {
|
||
|
|
t.Fatal("bootstrap admin failed")
|
||
|
|
}
|
||
|
|
|
||
|
|
if ok := registerUser(server.URL, "permuser", "permuser@test.com", "UserPass123!"); !ok {
|
||
|
|
t.Fatal("register user failed")
|
||
|
|
}
|
||
|
|
userToken := getToken(server.URL, "permuser", "UserPass123!")
|
||
|
|
if userToken == "" {
|
||
|
|
t.Fatal("get user token failed")
|
||
|
|
}
|
||
|
|
|
||
|
|
tests := []struct {
|
||
|
|
name string
|
||
|
|
token string
|
||
|
|
wantStatus int
|
||
|
|
}{
|
||
|
|
{
|
||
|
|
name: "success_admin",
|
||
|
|
token: adminToken,
|
||
|
|
wantStatus: http.StatusOK,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "forbidden_regular_user",
|
||
|
|
token: userToken,
|
||
|
|
wantStatus: http.StatusForbidden,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "unauthorized",
|
||
|
|
token: "",
|
||
|
|
wantStatus: http.StatusUnauthorized,
|
||
|
|
},
|
||
|
|
}
|
||
|
|
|
||
|
|
for _, tt := range tests {
|
||
|
|
t.Run(tt.name, func(t *testing.T) {
|
||
|
|
resp, body := doGet(server.URL+"/api/v1/permissions", tt.token)
|
||
|
|
defer resp.Body.Close()
|
||
|
|
if resp.StatusCode != tt.wantStatus {
|
||
|
|
t.Errorf("expected status %d, got %d, body: %s", tt.wantStatus, resp.StatusCode, body)
|
||
|
|
}
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestPermissionHandler_GetPermission(t *testing.T) {
|
||
|
|
server, cleanup := setupHandlerTestServer(t)
|
||
|
|
defer cleanup()
|
||
|
|
|
||
|
|
t.Setenv("BOOTSTRAP_SECRET", "perm-bootstrap-secret")
|
||
|
|
adminToken := bootstrapAdmin(server.URL, "perm-bootstrap-secret", "permadmin", "permadmin@test.com", "AdminPass123!")
|
||
|
|
if adminToken == "" {
|
||
|
|
t.Fatal("bootstrap admin failed")
|
||
|
|
}
|
||
|
|
|
||
|
|
// Create a permission to retrieve
|
||
|
|
createResp, createBody := doPost(server.URL+"/api/v1/permissions", adminToken, map[string]interface{}{
|
||
|
|
"name": "Get Permission Test",
|
||
|
|
"code": "test:permission:get",
|
||
|
|
"type": 2,
|
||
|
|
})
|
||
|
|
defer createResp.Body.Close()
|
||
|
|
if createResp.StatusCode != http.StatusCreated {
|
||
|
|
t.Fatalf("create permission failed: %d %s", createResp.StatusCode, createBody)
|
||
|
|
}
|
||
|
|
var createResult map[string]interface{}
|
||
|
|
if err := json.Unmarshal([]byte(createBody), &createResult); err != nil {
|
||
|
|
t.Fatalf("parse create response failed: %v", err)
|
||
|
|
}
|
||
|
|
permData, ok := createResult["data"].(map[string]interface{})
|
||
|
|
if !ok {
|
||
|
|
t.Fatalf("expected data in create response, got %s", createBody)
|
||
|
|
}
|
||
|
|
permID := int64(permData["id"].(float64))
|
||
|
|
|
||
|
|
tests := []struct {
|
||
|
|
name string
|
||
|
|
permID string
|
||
|
|
token string
|
||
|
|
wantStatus int
|
||
|
|
}{
|
||
|
|
{
|
||
|
|
name: "success",
|
||
|
|
permID: fmt.Sprintf("%d", permID),
|
||
|
|
token: adminToken,
|
||
|
|
wantStatus: http.StatusOK,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "not_found",
|
||
|
|
permID: "99999",
|
||
|
|
token: adminToken,
|
||
|
|
wantStatus: http.StatusNotFound,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "invalid_id",
|
||
|
|
permID: "invalid",
|
||
|
|
token: adminToken,
|
||
|
|
wantStatus: http.StatusBadRequest,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "unauthorized",
|
||
|
|
permID: fmt.Sprintf("%d", permID),
|
||
|
|
token: "",
|
||
|
|
wantStatus: http.StatusUnauthorized,
|
||
|
|
},
|
||
|
|
}
|
||
|
|
|
||
|
|
for _, tt := range tests {
|
||
|
|
t.Run(tt.name, func(t *testing.T) {
|
||
|
|
resp, body := doGet(server.URL+"/api/v1/permissions/"+tt.permID, tt.token)
|
||
|
|
defer resp.Body.Close()
|
||
|
|
if resp.StatusCode != tt.wantStatus {
|
||
|
|
t.Errorf("expected status %d, got %d, body: %s", tt.wantStatus, resp.StatusCode, body)
|
||
|
|
}
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestPermissionHandler_UpdatePermission(t *testing.T) {
|
||
|
|
server, cleanup := setupHandlerTestServer(t)
|
||
|
|
defer cleanup()
|
||
|
|
|
||
|
|
t.Setenv("BOOTSTRAP_SECRET", "perm-bootstrap-secret")
|
||
|
|
adminToken := bootstrapAdmin(server.URL, "perm-bootstrap-secret", "permadmin", "permadmin@test.com", "AdminPass123!")
|
||
|
|
if adminToken == "" {
|
||
|
|
t.Fatal("bootstrap admin failed")
|
||
|
|
}
|
||
|
|
|
||
|
|
// Create a permission to update
|
||
|
|
createResp, createBody := doPost(server.URL+"/api/v1/permissions", adminToken, map[string]interface{}{
|
||
|
|
"name": "Update Permission Test",
|
||
|
|
"code": "test:permission:update",
|
||
|
|
"type": 2,
|
||
|
|
})
|
||
|
|
defer createResp.Body.Close()
|
||
|
|
if createResp.StatusCode != http.StatusCreated {
|
||
|
|
t.Fatalf("create permission failed: %d %s", createResp.StatusCode, createBody)
|
||
|
|
}
|
||
|
|
var createResult map[string]interface{}
|
||
|
|
if err := json.Unmarshal([]byte(createBody), &createResult); err != nil {
|
||
|
|
t.Fatalf("parse create response failed: %v", err)
|
||
|
|
}
|
||
|
|
permData := createResult["data"].(map[string]interface{})
|
||
|
|
permID := int64(permData["id"].(float64))
|
||
|
|
|
||
|
|
tests := []struct {
|
||
|
|
name string
|
||
|
|
permID string
|
||
|
|
payload map[string]interface{}
|
||
|
|
token string
|
||
|
|
wantStatus int
|
||
|
|
}{
|
||
|
|
{
|
||
|
|
name: "success",
|
||
|
|
permID: fmt.Sprintf("%d", permID),
|
||
|
|
payload: map[string]interface{}{
|
||
|
|
"name": "Updated Permission Name",
|
||
|
|
},
|
||
|
|
token: adminToken,
|
||
|
|
wantStatus: http.StatusOK,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "invalid_id",
|
||
|
|
permID: "invalid",
|
||
|
|
payload: map[string]interface{}{
|
||
|
|
"name": "Updated Permission Name",
|
||
|
|
},
|
||
|
|
token: adminToken,
|
||
|
|
wantStatus: http.StatusBadRequest,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "unauthorized",
|
||
|
|
permID: fmt.Sprintf("%d", permID),
|
||
|
|
payload: map[string]interface{}{
|
||
|
|
"name": "Updated Permission Name",
|
||
|
|
},
|
||
|
|
token: "",
|
||
|
|
wantStatus: http.StatusUnauthorized,
|
||
|
|
},
|
||
|
|
}
|
||
|
|
|
||
|
|
for _, tt := range tests {
|
||
|
|
t.Run(tt.name, func(t *testing.T) {
|
||
|
|
resp, body := doPut(server.URL+"/api/v1/permissions/"+tt.permID, tt.token, tt.payload)
|
||
|
|
defer resp.Body.Close()
|
||
|
|
if resp.StatusCode != tt.wantStatus {
|
||
|
|
t.Errorf("expected status %d, got %d, body: %s", tt.wantStatus, resp.StatusCode, body)
|
||
|
|
}
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestPermissionHandler_DeletePermission(t *testing.T) {
|
||
|
|
server, cleanup := setupHandlerTestServer(t)
|
||
|
|
defer cleanup()
|
||
|
|
|
||
|
|
t.Setenv("BOOTSTRAP_SECRET", "perm-bootstrap-secret")
|
||
|
|
adminToken := bootstrapAdmin(server.URL, "perm-bootstrap-secret", "permadmin", "permadmin@test.com", "AdminPass123!")
|
||
|
|
if adminToken == "" {
|
||
|
|
t.Fatal("bootstrap admin failed")
|
||
|
|
}
|
||
|
|
|
||
|
|
// Create a permission to delete
|
||
|
|
createResp, createBody := doPost(server.URL+"/api/v1/permissions", adminToken, map[string]interface{}{
|
||
|
|
"name": "Delete Permission Test",
|
||
|
|
"code": "test:permission:delete",
|
||
|
|
"type": 2,
|
||
|
|
})
|
||
|
|
defer createResp.Body.Close()
|
||
|
|
if createResp.StatusCode != http.StatusCreated {
|
||
|
|
t.Fatalf("create permission failed: %d %s", createResp.StatusCode, createBody)
|
||
|
|
}
|
||
|
|
var createResult map[string]interface{}
|
||
|
|
if err := json.Unmarshal([]byte(createBody), &createResult); err != nil {
|
||
|
|
t.Fatalf("parse create response failed: %v", err)
|
||
|
|
}
|
||
|
|
permData := createResult["data"].(map[string]interface{})
|
||
|
|
permID := int64(permData["id"].(float64))
|
||
|
|
|
||
|
|
tests := []struct {
|
||
|
|
name string
|
||
|
|
permID string
|
||
|
|
token string
|
||
|
|
wantStatus int
|
||
|
|
}{
|
||
|
|
{
|
||
|
|
name: "success",
|
||
|
|
permID: fmt.Sprintf("%d", permID),
|
||
|
|
token: adminToken,
|
||
|
|
wantStatus: http.StatusOK,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "invalid_id",
|
||
|
|
permID: "invalid",
|
||
|
|
token: adminToken,
|
||
|
|
wantStatus: http.StatusBadRequest,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "unauthorized",
|
||
|
|
permID: fmt.Sprintf("%d", permID),
|
||
|
|
token: "",
|
||
|
|
wantStatus: http.StatusUnauthorized,
|
||
|
|
},
|
||
|
|
}
|
||
|
|
|
||
|
|
for _, tt := range tests {
|
||
|
|
t.Run(tt.name, func(t *testing.T) {
|
||
|
|
resp, body := doDelete(server.URL+"/api/v1/permissions/"+tt.permID, tt.token)
|
||
|
|
defer resp.Body.Close()
|
||
|
|
if resp.StatusCode != tt.wantStatus {
|
||
|
|
t.Errorf("expected status %d, got %d, body: %s", tt.wantStatus, resp.StatusCode, body)
|
||
|
|
}
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestPermissionHandler_UpdatePermissionStatus(t *testing.T) {
|
||
|
|
server, cleanup := setupHandlerTestServer(t)
|
||
|
|
defer cleanup()
|
||
|
|
|
||
|
|
t.Setenv("BOOTSTRAP_SECRET", "perm-bootstrap-secret")
|
||
|
|
adminToken := bootstrapAdmin(server.URL, "perm-bootstrap-secret", "permadmin", "permadmin@test.com", "AdminPass123!")
|
||
|
|
if adminToken == "" {
|
||
|
|
t.Fatal("bootstrap admin failed")
|
||
|
|
}
|
||
|
|
|
||
|
|
// Create a permission
|
||
|
|
createResp, createBody := doPost(server.URL+"/api/v1/permissions", adminToken, map[string]interface{}{
|
||
|
|
"name": "Status Permission Test",
|
||
|
|
"code": "test:permission:status",
|
||
|
|
"type": 2,
|
||
|
|
})
|
||
|
|
defer createResp.Body.Close()
|
||
|
|
if createResp.StatusCode != http.StatusCreated {
|
||
|
|
t.Fatalf("create permission failed: %d %s", createResp.StatusCode, createBody)
|
||
|
|
}
|
||
|
|
var createResult map[string]interface{}
|
||
|
|
if err := json.Unmarshal([]byte(createBody), &createResult); err != nil {
|
||
|
|
t.Fatalf("parse create response failed: %v", err)
|
||
|
|
}
|
||
|
|
permData := createResult["data"].(map[string]interface{})
|
||
|
|
permID := int64(permData["id"].(float64))
|
||
|
|
|
||
|
|
tests := []struct {
|
||
|
|
name string
|
||
|
|
permID string
|
||
|
|
payload map[string]interface{}
|
||
|
|
token string
|
||
|
|
wantStatus int
|
||
|
|
}{
|
||
|
|
{
|
||
|
|
name: "success_numeric",
|
||
|
|
permID: fmt.Sprintf("%d", permID),
|
||
|
|
payload: map[string]interface{}{
|
||
|
|
"status": 0,
|
||
|
|
},
|
||
|
|
token: adminToken,
|
||
|
|
wantStatus: http.StatusOK,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "invalid_id",
|
||
|
|
permID: "invalid",
|
||
|
|
payload: map[string]interface{}{
|
||
|
|
"status": 0,
|
||
|
|
},
|
||
|
|
token: adminToken,
|
||
|
|
wantStatus: http.StatusBadRequest,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: "unauthorized",
|
||
|
|
permID: fmt.Sprintf("%d", permID),
|
||
|
|
payload: map[string]interface{}{
|
||
|
|
"status": 0,
|
||
|
|
},
|
||
|
|
token: "",
|
||
|
|
wantStatus: http.StatusUnauthorized,
|
||
|
|
},
|
||
|
|
}
|
||
|
|
|
||
|
|
for _, tt := range tests {
|
||
|
|
t.Run(tt.name, func(t *testing.T) {
|
||
|
|
resp, body := doPut(server.URL+"/api/v1/permissions/"+tt.permID+"/status", tt.token, tt.payload)
|
||
|
|
defer resp.Body.Close()
|
||
|
|
if resp.StatusCode != tt.wantStatus {
|
||
|
|
t.Errorf("expected status %d, got %d, body: %s", tt.wantStatus, resp.StatusCode, body)
|
||
|
|
}
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestPermissionHandler_GetPermissionTree(t *testing.T) {
|
||
|
|
server, cleanup := setupHandlerTestServer(t)
|
||
|
|
defer cleanup()
|
||
|
|
|
||
|
|
t.Setenv("BOOTSTRAP_SECRET", "perm-bootstrap-secret")
|
||
|
|
adminToken := bootstrapAdmin(server.URL, "perm-bootstrap-secret", "permadmin", "permadmin@test.com", "AdminPass123!")
|
||
|
|
if adminToken == "" {
|
||
|
|
t.Fatal("bootstrap admin failed")
|
||
|
|
}
|
||
|
|
|
||
|
|
resp, body := doGet(server.URL+"/api/v1/permissions/tree", adminToken)
|
||
|
|
defer resp.Body.Close()
|
||
|
|
if resp.StatusCode != http.StatusOK {
|
||
|
|
t.Fatalf("expected status %d, got %d, body: %s", http.StatusOK, resp.StatusCode, body)
|
||
|
|
}
|
||
|
|
|
||
|
|
var result map[string]interface{}
|
||
|
|
if err := json.Unmarshal([]byte(body), &result); err != nil {
|
||
|
|
t.Fatalf("parse response failed: %v", err)
|
||
|
|
}
|
||
|
|
if result["code"] != float64(0) {
|
||
|
|
t.Errorf("expected code 0, got %v", result["code"])
|
||
|
|
}
|
||
|
|
if result["data"] == nil {
|
||
|
|
t.Errorf("expected data in response")
|
||
|
|
}
|
||
|
|
}
|