test: 补齐 handler/repository/domain 层单元测试
This commit is contained in:
527
internal/api/handler/role_handler_test.go
Normal file
527
internal/api/handler/role_handler_test.go
Normal file
@@ -0,0 +1,527 @@
|
||||
package handler_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRoleHandler_CreateRole(t *testing.T) {
|
||||
server, cleanup := setupHandlerTestServer(t)
|
||||
defer cleanup()
|
||||
|
||||
t.Setenv("BOOTSTRAP_SECRET", "role-bootstrap-secret")
|
||||
adminToken := bootstrapAdmin(server.URL, "role-bootstrap-secret", "roleadmin", "roleadmin@test.com", "AdminPass123!")
|
||||
if adminToken == "" {
|
||||
t.Fatal("bootstrap admin failed")
|
||||
}
|
||||
|
||||
if ok := registerUser(server.URL, "roleuser", "roleuser@test.com", "UserPass123!"); !ok {
|
||||
t.Fatal("register user failed")
|
||||
}
|
||||
userToken := getToken(server.URL, "roleuser", "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 Role",
|
||||
"code": "test_role_create",
|
||||
},
|
||||
token: adminToken,
|
||||
wantStatus: http.StatusCreated,
|
||||
},
|
||||
{
|
||||
name: "unauthorized",
|
||||
payload: map[string]interface{}{
|
||||
"name": "Test Role Unauth",
|
||||
"code": "test_role_unauth",
|
||||
},
|
||||
token: "",
|
||||
wantStatus: http.StatusUnauthorized,
|
||||
},
|
||||
{
|
||||
name: "forbidden",
|
||||
payload: map[string]interface{}{
|
||||
"name": "Test Role Forbidden",
|
||||
"code": "test_role_forbidden",
|
||||
},
|
||||
token: userToken,
|
||||
wantStatus: http.StatusForbidden,
|
||||
},
|
||||
{
|
||||
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/roles", 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 TestRoleHandler_ListRoles(t *testing.T) {
|
||||
server, cleanup := setupHandlerTestServer(t)
|
||||
defer cleanup()
|
||||
|
||||
t.Setenv("BOOTSTRAP_SECRET", "role-bootstrap-secret")
|
||||
adminToken := bootstrapAdmin(server.URL, "role-bootstrap-secret", "roleadmin", "roleadmin@test.com", "AdminPass123!")
|
||||
if adminToken == "" {
|
||||
t.Fatal("bootstrap admin failed")
|
||||
}
|
||||
|
||||
if ok := registerUser(server.URL, "roleuser", "roleuser@test.com", "UserPass123!"); !ok {
|
||||
t.Fatal("register user failed")
|
||||
}
|
||||
userToken := getToken(server.URL, "roleuser", "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/roles", 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 TestRoleHandler_GetRole(t *testing.T) {
|
||||
server, cleanup := setupHandlerTestServer(t)
|
||||
defer cleanup()
|
||||
|
||||
t.Setenv("BOOTSTRAP_SECRET", "role-bootstrap-secret")
|
||||
adminToken := bootstrapAdmin(server.URL, "role-bootstrap-secret", "roleadmin", "roleadmin@test.com", "AdminPass123!")
|
||||
if adminToken == "" {
|
||||
t.Fatal("bootstrap admin failed")
|
||||
}
|
||||
|
||||
// Create a role to retrieve
|
||||
createResp, createBody := doPost(server.URL+"/api/v1/roles", adminToken, map[string]interface{}{
|
||||
"name": "Get Role Test",
|
||||
"code": "test_role_get",
|
||||
})
|
||||
defer createResp.Body.Close()
|
||||
if createResp.StatusCode != http.StatusCreated {
|
||||
t.Fatalf("create role 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)
|
||||
}
|
||||
roleData := createResult["data"].(map[string]interface{})
|
||||
roleID := int64(roleData["id"].(float64))
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
roleID string
|
||||
token string
|
||||
wantStatus int
|
||||
}{
|
||||
{
|
||||
name: "success",
|
||||
roleID: fmt.Sprintf("%d", roleID),
|
||||
token: adminToken,
|
||||
wantStatus: http.StatusOK,
|
||||
},
|
||||
{
|
||||
name: "not_found",
|
||||
roleID: "99999",
|
||||
token: adminToken,
|
||||
wantStatus: http.StatusNotFound,
|
||||
},
|
||||
{
|
||||
name: "invalid_id",
|
||||
roleID: "invalid",
|
||||
token: adminToken,
|
||||
wantStatus: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
name: "unauthorized",
|
||||
roleID: fmt.Sprintf("%d", roleID),
|
||||
token: "",
|
||||
wantStatus: http.StatusUnauthorized,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
resp, body := doGet(server.URL+"/api/v1/roles/"+tt.roleID, 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 TestRoleHandler_UpdateRole(t *testing.T) {
|
||||
server, cleanup := setupHandlerTestServer(t)
|
||||
defer cleanup()
|
||||
|
||||
t.Setenv("BOOTSTRAP_SECRET", "role-bootstrap-secret")
|
||||
adminToken := bootstrapAdmin(server.URL, "role-bootstrap-secret", "roleadmin", "roleadmin@test.com", "AdminPass123!")
|
||||
if adminToken == "" {
|
||||
t.Fatal("bootstrap admin failed")
|
||||
}
|
||||
|
||||
// Create a role to update
|
||||
createResp, createBody := doPost(server.URL+"/api/v1/roles", adminToken, map[string]interface{}{
|
||||
"name": "Update Role Test",
|
||||
"code": "test_role_update",
|
||||
})
|
||||
defer createResp.Body.Close()
|
||||
if createResp.StatusCode != http.StatusCreated {
|
||||
t.Fatalf("create role 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)
|
||||
}
|
||||
roleData := createResult["data"].(map[string]interface{})
|
||||
roleID := int64(roleData["id"].(float64))
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
roleID string
|
||||
payload map[string]interface{}
|
||||
token string
|
||||
wantStatus int
|
||||
}{
|
||||
{
|
||||
name: "success",
|
||||
roleID: fmt.Sprintf("%d", roleID),
|
||||
payload: map[string]interface{}{
|
||||
"name": "Updated Role Name",
|
||||
},
|
||||
token: adminToken,
|
||||
wantStatus: http.StatusOK,
|
||||
},
|
||||
{
|
||||
name: "invalid_id",
|
||||
roleID: "invalid",
|
||||
payload: map[string]interface{}{
|
||||
"name": "Updated Role Name",
|
||||
},
|
||||
token: adminToken,
|
||||
wantStatus: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
name: "unauthorized",
|
||||
roleID: fmt.Sprintf("%d", roleID),
|
||||
payload: map[string]interface{}{
|
||||
"name": "Updated Role Name",
|
||||
},
|
||||
token: "",
|
||||
wantStatus: http.StatusUnauthorized,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
resp, body := doPut(server.URL+"/api/v1/roles/"+tt.roleID, 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 TestRoleHandler_DeleteRole(t *testing.T) {
|
||||
server, cleanup := setupHandlerTestServer(t)
|
||||
defer cleanup()
|
||||
|
||||
t.Setenv("BOOTSTRAP_SECRET", "role-bootstrap-secret")
|
||||
adminToken := bootstrapAdmin(server.URL, "role-bootstrap-secret", "roleadmin", "roleadmin@test.com", "AdminPass123!")
|
||||
if adminToken == "" {
|
||||
t.Fatal("bootstrap admin failed")
|
||||
}
|
||||
|
||||
// Create a role to delete
|
||||
createResp, createBody := doPost(server.URL+"/api/v1/roles", adminToken, map[string]interface{}{
|
||||
"name": "Delete Role Test",
|
||||
"code": "test_role_delete",
|
||||
})
|
||||
defer createResp.Body.Close()
|
||||
if createResp.StatusCode != http.StatusCreated {
|
||||
t.Fatalf("create role 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)
|
||||
}
|
||||
roleData := createResult["data"].(map[string]interface{})
|
||||
roleID := int64(roleData["id"].(float64))
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
roleID string
|
||||
token string
|
||||
wantStatus int
|
||||
}{
|
||||
{
|
||||
name: "success",
|
||||
roleID: fmt.Sprintf("%d", roleID),
|
||||
token: adminToken,
|
||||
wantStatus: http.StatusOK,
|
||||
},
|
||||
{
|
||||
name: "invalid_id",
|
||||
roleID: "invalid",
|
||||
token: adminToken,
|
||||
wantStatus: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
name: "unauthorized",
|
||||
roleID: fmt.Sprintf("%d", roleID),
|
||||
token: "",
|
||||
wantStatus: http.StatusUnauthorized,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
resp, body := doDelete(server.URL+"/api/v1/roles/"+tt.roleID, 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 TestRoleHandler_UpdateRoleStatus(t *testing.T) {
|
||||
server, cleanup := setupHandlerTestServer(t)
|
||||
defer cleanup()
|
||||
|
||||
t.Setenv("BOOTSTRAP_SECRET", "role-bootstrap-secret")
|
||||
adminToken := bootstrapAdmin(server.URL, "role-bootstrap-secret", "roleadmin", "roleadmin@test.com", "AdminPass123!")
|
||||
if adminToken == "" {
|
||||
t.Fatal("bootstrap admin failed")
|
||||
}
|
||||
|
||||
// Create a role
|
||||
createResp, createBody := doPost(server.URL+"/api/v1/roles", adminToken, map[string]interface{}{
|
||||
"name": "Status Role Test",
|
||||
"code": "test_role_status",
|
||||
})
|
||||
defer createResp.Body.Close()
|
||||
if createResp.StatusCode != http.StatusCreated {
|
||||
t.Fatalf("create role 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)
|
||||
}
|
||||
roleData := createResult["data"].(map[string]interface{})
|
||||
roleID := int64(roleData["id"].(float64))
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
roleID string
|
||||
payload map[string]interface{}
|
||||
token string
|
||||
wantStatus int
|
||||
}{
|
||||
{
|
||||
name: "success_disabled",
|
||||
roleID: fmt.Sprintf("%d", roleID),
|
||||
payload: map[string]interface{}{
|
||||
"status": "disabled",
|
||||
},
|
||||
token: adminToken,
|
||||
wantStatus: http.StatusOK,
|
||||
},
|
||||
{
|
||||
name: "success_enabled",
|
||||
roleID: fmt.Sprintf("%d", roleID),
|
||||
payload: map[string]interface{}{
|
||||
"status": "enabled",
|
||||
},
|
||||
token: adminToken,
|
||||
wantStatus: http.StatusOK,
|
||||
},
|
||||
{
|
||||
name: "invalid_status",
|
||||
roleID: fmt.Sprintf("%d", roleID),
|
||||
payload: map[string]interface{}{
|
||||
"status": "invalid_status",
|
||||
},
|
||||
token: adminToken,
|
||||
wantStatus: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
name: "invalid_id",
|
||||
roleID: "invalid",
|
||||
payload: map[string]interface{}{
|
||||
"status": "disabled",
|
||||
},
|
||||
token: adminToken,
|
||||
wantStatus: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
name: "unauthorized",
|
||||
roleID: fmt.Sprintf("%d", roleID),
|
||||
payload: map[string]interface{}{
|
||||
"status": "disabled",
|
||||
},
|
||||
token: "",
|
||||
wantStatus: http.StatusUnauthorized,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
resp, body := doPut(server.URL+"/api/v1/roles/"+tt.roleID+"/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 TestRoleHandler_GetRolePermissions(t *testing.T) {
|
||||
server, cleanup := setupHandlerTestServer(t)
|
||||
defer cleanup()
|
||||
|
||||
t.Setenv("BOOTSTRAP_SECRET", "role-bootstrap-secret")
|
||||
adminToken := bootstrapAdmin(server.URL, "role-bootstrap-secret", "roleadmin", "roleadmin@test.com", "AdminPass123!")
|
||||
if adminToken == "" {
|
||||
t.Fatal("bootstrap admin failed")
|
||||
}
|
||||
|
||||
// Use the admin role (id=1) for testing
|
||||
resp, body := doGet(server.URL+"/api/v1/roles/1/permissions", 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")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRoleHandler_AssignPermissions(t *testing.T) {
|
||||
server, cleanup := setupHandlerTestServer(t)
|
||||
defer cleanup()
|
||||
|
||||
t.Setenv("BOOTSTRAP_SECRET", "role-bootstrap-secret")
|
||||
adminToken := bootstrapAdmin(server.URL, "role-bootstrap-secret", "roleadmin", "roleadmin@test.com", "AdminPass123!")
|
||||
if adminToken == "" {
|
||||
t.Fatal("bootstrap admin failed")
|
||||
}
|
||||
|
||||
// Create a role
|
||||
createResp, createBody := doPost(server.URL+"/api/v1/roles", adminToken, map[string]interface{}{
|
||||
"name": "Assign Perm Role Test",
|
||||
"code": "test_role_assign_perm",
|
||||
})
|
||||
defer createResp.Body.Close()
|
||||
if createResp.StatusCode != http.StatusCreated {
|
||||
t.Fatalf("create role 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)
|
||||
}
|
||||
roleData := createResult["data"].(map[string]interface{})
|
||||
roleID := int64(roleData["id"].(float64))
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
roleID string
|
||||
payload map[string]interface{}
|
||||
token string
|
||||
wantStatus int
|
||||
}{
|
||||
{
|
||||
name: "success",
|
||||
roleID: fmt.Sprintf("%d", roleID),
|
||||
payload: map[string]interface{}{
|
||||
"permission_ids": []int64{1, 2},
|
||||
},
|
||||
token: adminToken,
|
||||
wantStatus: http.StatusOK,
|
||||
},
|
||||
{
|
||||
name: "invalid_id",
|
||||
roleID: "invalid",
|
||||
payload: map[string]interface{}{
|
||||
"permission_ids": []int64{1},
|
||||
},
|
||||
token: adminToken,
|
||||
wantStatus: http.StatusBadRequest,
|
||||
},
|
||||
{
|
||||
name: "unauthorized",
|
||||
roleID: fmt.Sprintf("%d", roleID),
|
||||
payload: map[string]interface{}{
|
||||
"permission_ids": []int64{1},
|
||||
},
|
||||
token: "",
|
||||
wantStatus: http.StatusUnauthorized,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
resp, body := doPut(server.URL+"/api/v1/roles/"+tt.roleID+"/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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user