1103 lines
38 KiB
Go
1103 lines
38 KiB
Go
package handlers
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"errors"
|
|
"net/http"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
|
|
"wucher/internal/domain/auth"
|
|
"wucher/internal/service"
|
|
"wucher/internal/shared/pkg/uuidv7"
|
|
)
|
|
|
|
type memRoleRepo struct {
|
|
roles map[string]*auth.Role
|
|
permissions map[string]*auth.Permission
|
|
listRoles []auth.Role
|
|
listTotal int64
|
|
listErr error
|
|
listPermissions []auth.Permission
|
|
listPermissionsTotal int64
|
|
listPermissionsErr error
|
|
|
|
createErr error
|
|
updateErr error
|
|
deleteErr error
|
|
getByIDErr error
|
|
getPermissionErr error
|
|
permissionNotFound bool
|
|
assignPermissionErr error
|
|
removePermissionErr error
|
|
}
|
|
|
|
func newMemRoleRepo() *memRoleRepo {
|
|
return &memRoleRepo{
|
|
roles: map[string]*auth.Role{},
|
|
permissions: map[string]*auth.Permission{},
|
|
}
|
|
}
|
|
|
|
func (r *memRoleRepo) CreateRole(_ context.Context, role *auth.Role) error {
|
|
if len(role.ID) == 0 {
|
|
role.ID = uuidv7.MustBytes()
|
|
}
|
|
r.roles[string(role.ID)] = role
|
|
return r.createErr
|
|
}
|
|
|
|
func (r *memRoleRepo) UpdateRole(_ context.Context, role *auth.Role) error {
|
|
r.roles[string(role.ID)] = role
|
|
return r.updateErr
|
|
}
|
|
|
|
func (r *memRoleRepo) DeleteRole(_ context.Context, id []byte) error {
|
|
delete(r.roles, string(id))
|
|
return r.deleteErr
|
|
}
|
|
|
|
func (r *memRoleRepo) GetRoleByID(_ context.Context, id []byte) (*auth.Role, error) {
|
|
return r.roles[string(id)], r.getByIDErr
|
|
}
|
|
|
|
func (r *memRoleRepo) GetRoleByName(_ context.Context, name string) (*auth.Role, error) {
|
|
for _, role := range r.roles {
|
|
if role.Name == name {
|
|
return role, nil
|
|
}
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
func (r *memRoleRepo) ListRoles(_ context.Context, _ string, _ string, _ int, _ int) ([]auth.Role, int64, error) {
|
|
return r.listRoles, r.listTotal, r.listErr
|
|
}
|
|
|
|
func (r *memRoleRepo) ListPermissions(_ context.Context, _ string, _ string, _ int, _ int) ([]auth.Permission, int64, error) {
|
|
return r.listPermissions, r.listPermissionsTotal, r.listPermissionsErr
|
|
}
|
|
func (r *memRoleRepo) ListPermissionsByRoleID(_ context.Context, _ []byte) ([]auth.Permission, error) {
|
|
return []auth.Permission{}, nil
|
|
}
|
|
|
|
func (r *memRoleRepo) HasRolePermission(_ context.Context, _ []byte, _ string) (bool, error) {
|
|
return true, nil
|
|
}
|
|
|
|
func (r *memRoleRepo) GetPermissionByID(_ context.Context, id []byte) (*auth.Permission, error) {
|
|
if r.permissionNotFound {
|
|
return nil, r.getPermissionErr
|
|
}
|
|
if permission, ok := r.permissions[string(id)]; ok {
|
|
return permission, r.getPermissionErr
|
|
}
|
|
return &auth.Permission{}, r.getPermissionErr
|
|
}
|
|
|
|
func (r *memRoleRepo) GetPermissionByKey(_ context.Context, key string) (*auth.Permission, error) {
|
|
if r.permissionNotFound {
|
|
return nil, r.getPermissionErr
|
|
}
|
|
for _, permission := range r.permissions {
|
|
if permission.Key == key {
|
|
return permission, r.getPermissionErr
|
|
}
|
|
}
|
|
return &auth.Permission{}, r.getPermissionErr
|
|
}
|
|
|
|
func (r *memRoleRepo) UpdatePermission(_ context.Context, permission *auth.Permission) error {
|
|
if permission != nil {
|
|
r.permissions[string(permission.ID)] = permission
|
|
}
|
|
return r.updateErr
|
|
}
|
|
|
|
func (r *memRoleRepo) AssignPermission(_ context.Context, roleID, permissionID []byte) (*auth.RolePermission, error) {
|
|
return &auth.RolePermission{ID: uuidv7.MustBytes(), RoleID: roleID, PermissionID: permissionID}, r.assignPermissionErr
|
|
}
|
|
|
|
func (r *memRoleRepo) RemovePermission(_ context.Context, _ []byte, _ []byte) error {
|
|
return r.removePermissionErr
|
|
}
|
|
|
|
func TestRoleHandler_Update_MissingBodyID(t *testing.T) {
|
|
repo := newMemRoleRepo()
|
|
roleID := uuidv7.MustBytes()
|
|
repo.roles[string(roleID)] = &auth.Role{ID: roleID, Name: "admin"}
|
|
|
|
svc := service.NewRoleService(repo)
|
|
h := NewRoleHandler(svc)
|
|
app := fiber.New()
|
|
app.Patch("/api/v1/roles/update/:uuid", h.Update)
|
|
|
|
payload := []byte(`{"data":{"type":"role","attributes":{"name":"test_role"}}}`)
|
|
idStr, _ := uuidv7.BytesToString(roleID)
|
|
req, _ := http.NewRequest(http.MethodPatch, "/api/v1/roles/update/"+idStr, bytes.NewReader(payload))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, err := app.Test(req)
|
|
if err != nil {
|
|
t.Fatalf("app.Test: %v", err)
|
|
}
|
|
if resp.StatusCode != http.StatusUnprocessableEntity {
|
|
t.Fatalf("expected 422, got %d", resp.StatusCode)
|
|
}
|
|
}
|
|
|
|
func TestRoleHandler_Update_IDMismatch(t *testing.T) {
|
|
repo := newMemRoleRepo()
|
|
roleID := uuidv7.MustBytes()
|
|
repo.roles[string(roleID)] = &auth.Role{ID: roleID, Name: "admin"}
|
|
|
|
svc := service.NewRoleService(repo)
|
|
h := NewRoleHandler(svc)
|
|
app := fiber.New()
|
|
app.Patch("/api/v1/roles/update/:uuid", h.Update)
|
|
|
|
pathID, _ := uuidv7.BytesToString(roleID)
|
|
otherID, _ := uuidv7.BytesToString(uuidv7.MustBytes())
|
|
payload := []byte(`{"data":{"type":"role","id":"` + otherID + `","attributes":{"name":"test_role"}}}`)
|
|
req, _ := http.NewRequest(http.MethodPatch, "/api/v1/roles/update/"+pathID, bytes.NewReader(payload))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, err := app.Test(req)
|
|
if err != nil {
|
|
t.Fatalf("app.Test: %v", err)
|
|
}
|
|
if resp.StatusCode != http.StatusUnprocessableEntity {
|
|
t.Fatalf("expected 422, got %d", resp.StatusCode)
|
|
}
|
|
}
|
|
|
|
func TestRoleHandler_Update_Success(t *testing.T) {
|
|
repo := newMemRoleRepo()
|
|
roleID := uuidv7.MustBytes()
|
|
repo.roles[string(roleID)] = &auth.Role{ID: roleID, Name: "admin"}
|
|
|
|
svc := service.NewRoleService(repo)
|
|
h := NewRoleHandler(svc)
|
|
app := fiber.New()
|
|
app.Patch("/api/v1/roles/update/:uuid", h.Update)
|
|
|
|
idStr, _ := uuidv7.BytesToString(roleID)
|
|
payload := []byte(`{"data":{"type":"role","id":"` + idStr + `","attributes":{"name":"test_role"}}}`)
|
|
req, _ := http.NewRequest(http.MethodPatch, "/api/v1/roles/update/"+idStr, bytes.NewReader(payload))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, err := app.Test(req)
|
|
if err != nil {
|
|
t.Fatalf("app.Test: %v", err)
|
|
}
|
|
if resp.StatusCode != http.StatusOK {
|
|
t.Fatalf("expected 200, got %d", resp.StatusCode)
|
|
}
|
|
if repo.roles[string(roleID)].Name != "test_role" {
|
|
t.Fatalf("expected role name updated")
|
|
}
|
|
}
|
|
|
|
func TestRoleHandler_Create_Success(t *testing.T) {
|
|
repo := newMemRoleRepo()
|
|
svc := service.NewRoleService(repo)
|
|
h := NewRoleHandler(svc)
|
|
app := fiber.New()
|
|
actor := uuidv7.MustBytes()
|
|
app.Use(func(c *fiber.Ctx) error {
|
|
c.Locals("user_id", actor)
|
|
return c.Next()
|
|
})
|
|
app.Post("/api/v1/roles/create", h.Create)
|
|
|
|
payload := []byte(`{"data":{"type":"role","attributes":{"name":"admin","description":"full"}}}`)
|
|
req, _ := http.NewRequest(http.MethodPost, "/api/v1/roles/create", bytes.NewReader(payload))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, err := app.Test(req)
|
|
if err != nil {
|
|
t.Fatalf("app.Test: %v", err)
|
|
}
|
|
if resp.StatusCode != http.StatusCreated {
|
|
t.Fatalf("expected 201, got %d", resp.StatusCode)
|
|
}
|
|
for _, created := range repo.roles {
|
|
if string(created.CreatedBy) != string(actor) {
|
|
t.Fatalf("expected created_by from actor")
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRoleHandler_Create_InvalidJSON(t *testing.T) {
|
|
repo := newMemRoleRepo()
|
|
svc := service.NewRoleService(repo)
|
|
h := NewRoleHandler(svc)
|
|
app := fiber.New()
|
|
app.Post("/api/v1/roles/create", h.Create)
|
|
|
|
payload := []byte(`{"data":`)
|
|
req, _ := http.NewRequest(http.MethodPost, "/api/v1/roles/create", bytes.NewReader(payload))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, err := app.Test(req)
|
|
if err != nil {
|
|
t.Fatalf("app.Test: %v", err)
|
|
}
|
|
if resp.StatusCode != http.StatusBadRequest {
|
|
t.Fatalf("expected 400, got %d", resp.StatusCode)
|
|
}
|
|
}
|
|
|
|
func TestRoleHandler_Create_ValidationError(t *testing.T) {
|
|
repo := newMemRoleRepo()
|
|
svc := service.NewRoleService(repo)
|
|
h := NewRoleHandler(svc)
|
|
app := fiber.New()
|
|
app.Post("/api/v1/roles/create", h.Create)
|
|
|
|
payload := []byte(`{"data":{"type":"role","attributes":{"name":""}}}`)
|
|
req, _ := http.NewRequest(http.MethodPost, "/api/v1/roles/create", bytes.NewReader(payload))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, err := app.Test(req)
|
|
if err != nil {
|
|
t.Fatalf("app.Test: %v", err)
|
|
}
|
|
if resp.StatusCode != http.StatusUnprocessableEntity {
|
|
t.Fatalf("expected 422, got %d", resp.StatusCode)
|
|
}
|
|
}
|
|
|
|
func TestRoleHandler_Create_ServiceError(t *testing.T) {
|
|
repo := newMemRoleRepo()
|
|
repo.createErr = errors.New("db error")
|
|
svc := service.NewRoleService(repo)
|
|
h := NewRoleHandler(svc)
|
|
app := fiber.New()
|
|
app.Post("/api/v1/roles/create", h.Create)
|
|
|
|
payload := []byte(`{"data":{"type":"role","attributes":{"name":"admin"}}}`)
|
|
req, _ := http.NewRequest(http.MethodPost, "/api/v1/roles/create", bytes.NewReader(payload))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, err := app.Test(req)
|
|
if err != nil {
|
|
t.Fatalf("app.Test: %v", err)
|
|
}
|
|
if resp.StatusCode != http.StatusBadRequest {
|
|
t.Fatalf("expected 400, got %d", resp.StatusCode)
|
|
}
|
|
}
|
|
|
|
func TestRoleHandler_Delete_Success(t *testing.T) {
|
|
repo := newMemRoleRepo()
|
|
roleID := uuidv7.MustBytes()
|
|
repo.roles[string(roleID)] = &auth.Role{ID: roleID, Name: "admin"}
|
|
|
|
svc := service.NewRoleService(repo)
|
|
h := NewRoleHandler(svc)
|
|
app := fiber.New()
|
|
app.Delete("/api/v1/roles/delete/:uuid", h.Delete)
|
|
|
|
idStr, _ := uuidv7.BytesToString(roleID)
|
|
req, _ := http.NewRequest(http.MethodDelete, "/api/v1/roles/delete/"+idStr, nil)
|
|
resp, err := app.Test(req)
|
|
if err != nil {
|
|
t.Fatalf("app.Test: %v", err)
|
|
}
|
|
if resp.StatusCode != http.StatusOK {
|
|
t.Fatalf("expected 200, got %d", resp.StatusCode)
|
|
}
|
|
}
|
|
|
|
func TestRoleHandler_Delete_InvalidID(t *testing.T) {
|
|
repo := newMemRoleRepo()
|
|
svc := service.NewRoleService(repo)
|
|
h := NewRoleHandler(svc)
|
|
app := fiber.New()
|
|
app.Delete("/api/v1/roles/delete/:uuid", h.Delete)
|
|
|
|
req, _ := http.NewRequest(http.MethodDelete, "/api/v1/roles/delete/not-a-uuid", nil)
|
|
resp, err := app.Test(req)
|
|
if err != nil {
|
|
t.Fatalf("app.Test: %v", err)
|
|
}
|
|
if resp.StatusCode != http.StatusUnprocessableEntity {
|
|
t.Fatalf("expected 422, got %d", resp.StatusCode)
|
|
}
|
|
}
|
|
|
|
func TestRoleHandler_Delete_ServiceError(t *testing.T) {
|
|
repo := newMemRoleRepo()
|
|
repo.deleteErr = errors.New("db error")
|
|
roleID := uuidv7.MustBytes()
|
|
repo.roles[string(roleID)] = &auth.Role{ID: roleID, Name: "admin"}
|
|
|
|
svc := service.NewRoleService(repo)
|
|
h := NewRoleHandler(svc)
|
|
app := fiber.New()
|
|
app.Delete("/api/v1/roles/delete/:uuid", h.Delete)
|
|
|
|
idStr, _ := uuidv7.BytesToString(roleID)
|
|
req, _ := http.NewRequest(http.MethodDelete, "/api/v1/roles/delete/"+idStr, nil)
|
|
resp, err := app.Test(req)
|
|
if err != nil {
|
|
t.Fatalf("app.Test: %v", err)
|
|
}
|
|
if resp.StatusCode != http.StatusBadRequest {
|
|
t.Fatalf("expected 400, got %d", resp.StatusCode)
|
|
}
|
|
}
|
|
|
|
func TestRoleHandler_GetByID_Success(t *testing.T) {
|
|
repo := newMemRoleRepo()
|
|
roleID := uuidv7.MustBytes()
|
|
repo.roles[string(roleID)] = &auth.Role{ID: roleID, Name: "admin"}
|
|
|
|
svc := service.NewRoleService(repo)
|
|
h := NewRoleHandler(svc)
|
|
app := fiber.New()
|
|
app.Get("/api/v1/roles/get/:uuid", h.GetByID)
|
|
|
|
idStr, _ := uuidv7.BytesToString(roleID)
|
|
req, _ := http.NewRequest(http.MethodGet, "/api/v1/roles/get/"+idStr, nil)
|
|
resp, err := app.Test(req)
|
|
if err != nil {
|
|
t.Fatalf("app.Test: %v", err)
|
|
}
|
|
if resp.StatusCode != http.StatusOK {
|
|
t.Fatalf("expected 200, got %d", resp.StatusCode)
|
|
}
|
|
}
|
|
|
|
func TestRoleHandler_GetByID_NotFound(t *testing.T) {
|
|
repo := newMemRoleRepo()
|
|
svc := service.NewRoleService(repo)
|
|
h := NewRoleHandler(svc)
|
|
app := fiber.New()
|
|
app.Get("/api/v1/roles/get/:uuid", h.GetByID)
|
|
|
|
idStr, _ := uuidv7.BytesToString(uuidv7.MustBytes())
|
|
req, _ := http.NewRequest(http.MethodGet, "/api/v1/roles/get/"+idStr, nil)
|
|
resp, err := app.Test(req)
|
|
if err != nil {
|
|
t.Fatalf("app.Test: %v", err)
|
|
}
|
|
if resp.StatusCode != http.StatusNotFound {
|
|
t.Fatalf("expected 404, got %d", resp.StatusCode)
|
|
}
|
|
}
|
|
|
|
func TestRoleHandler_List_Success(t *testing.T) {
|
|
repo := newMemRoleRepo()
|
|
roleID := uuidv7.MustBytes()
|
|
repo.listRoles = []auth.Role{{ID: roleID, Name: "admin"}}
|
|
repo.listTotal = 1
|
|
|
|
svc := service.NewRoleService(repo)
|
|
h := NewRoleHandler(svc)
|
|
app := fiber.New()
|
|
app.Get("/api/v1/roles/get-all", h.List)
|
|
|
|
req, _ := http.NewRequest(http.MethodGet, "/api/v1/roles/get-all?page[number]=1&page[size]=10&filter[name]=ad", nil)
|
|
resp, err := app.Test(req)
|
|
if err != nil {
|
|
t.Fatalf("app.Test: %v", err)
|
|
}
|
|
if resp.StatusCode != http.StatusOK {
|
|
t.Fatalf("expected 200, got %d", resp.StatusCode)
|
|
}
|
|
}
|
|
|
|
func TestRoleHandler_ListDatatable_Success(t *testing.T) {
|
|
repo := newMemRoleRepo()
|
|
roleID := uuidv7.MustBytes()
|
|
repo.listRoles = []auth.Role{{ID: roleID, Name: "admin"}}
|
|
repo.listTotal = 1
|
|
|
|
svc := service.NewRoleService(repo)
|
|
h := NewRoleHandler(svc)
|
|
app := fiber.New()
|
|
app.Get("/api/v1/roles/get-all/dt", h.ListDatatable)
|
|
|
|
req, _ := http.NewRequest(http.MethodGet, "/api/v1/roles/get-all/dt?page=1&size=10&search=ad", nil)
|
|
resp, err := app.Test(req)
|
|
if err != nil {
|
|
t.Fatalf("app.Test: %v", err)
|
|
}
|
|
if resp.StatusCode != http.StatusOK {
|
|
t.Fatalf("expected 200, got %d", resp.StatusCode)
|
|
}
|
|
}
|
|
|
|
func TestParseIntDefault(t *testing.T) {
|
|
if got := parseIntDefault("", 7); got != 7 {
|
|
t.Fatalf("expected default value")
|
|
}
|
|
if got := parseIntDefault("abc", 7); got != 7 {
|
|
t.Fatalf("expected default on invalid")
|
|
}
|
|
if got := parseIntDefault("9", 7); got != 9 {
|
|
t.Fatalf("expected parsed value")
|
|
}
|
|
}
|
|
|
|
func TestRoleHandler_Update_InvalidID(t *testing.T) {
|
|
repo := newMemRoleRepo()
|
|
svc := service.NewRoleService(repo)
|
|
h := NewRoleHandler(svc)
|
|
app := fiber.New()
|
|
app.Patch("/api/v1/roles/update/:uuid", h.Update)
|
|
|
|
payload := []byte(`{"data":{"type":"role","id":"bad","attributes":{"name":"test_role"}}}`)
|
|
req, _ := http.NewRequest(http.MethodPatch, "/api/v1/roles/update/not-a-uuid", bytes.NewReader(payload))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, err := app.Test(req)
|
|
if err != nil {
|
|
t.Fatalf("app.Test: %v", err)
|
|
}
|
|
if resp.StatusCode != http.StatusUnprocessableEntity {
|
|
t.Fatalf("expected 422, got %d", resp.StatusCode)
|
|
}
|
|
}
|
|
|
|
func TestRoleHandler_Update_NoAttributes(t *testing.T) {
|
|
repo := newMemRoleRepo()
|
|
roleID := uuidv7.MustBytes()
|
|
repo.roles[string(roleID)] = &auth.Role{ID: roleID, Name: "admin"}
|
|
|
|
svc := service.NewRoleService(repo)
|
|
h := NewRoleHandler(svc)
|
|
app := fiber.New()
|
|
app.Patch("/api/v1/roles/update/:uuid", h.Update)
|
|
|
|
idStr, _ := uuidv7.BytesToString(roleID)
|
|
payload := []byte(`{"data":{"type":"role","id":"` + idStr + `","attributes":{}}}`)
|
|
req, _ := http.NewRequest(http.MethodPatch, "/api/v1/roles/update/"+idStr, bytes.NewReader(payload))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, err := app.Test(req)
|
|
if err != nil {
|
|
t.Fatalf("app.Test: %v", err)
|
|
}
|
|
if resp.StatusCode != http.StatusUnprocessableEntity {
|
|
t.Fatalf("expected 422, got %d", resp.StatusCode)
|
|
}
|
|
}
|
|
|
|
func TestRoleHandler_Update_ServiceError(t *testing.T) {
|
|
repo := newMemRoleRepo()
|
|
repo.updateErr = errors.New("db error")
|
|
roleID := uuidv7.MustBytes()
|
|
repo.roles[string(roleID)] = &auth.Role{ID: roleID, Name: "admin"}
|
|
|
|
svc := service.NewRoleService(repo)
|
|
h := NewRoleHandler(svc)
|
|
app := fiber.New()
|
|
app.Patch("/api/v1/roles/update/:uuid", h.Update)
|
|
|
|
idStr, _ := uuidv7.BytesToString(roleID)
|
|
payload := []byte(`{"data":{"type":"role","id":"` + idStr + `","attributes":{"name":"test_role"}}}`)
|
|
req, _ := http.NewRequest(http.MethodPatch, "/api/v1/roles/update/"+idStr, bytes.NewReader(payload))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, err := app.Test(req)
|
|
if err != nil {
|
|
t.Fatalf("app.Test: %v", err)
|
|
}
|
|
if resp.StatusCode != http.StatusBadRequest {
|
|
t.Fatalf("expected 400, got %d", resp.StatusCode)
|
|
}
|
|
}
|
|
|
|
func TestRoleHandler_AssignPermission_Success(t *testing.T) {
|
|
repo := newMemRoleRepo()
|
|
roleID := uuidv7.MustBytes()
|
|
repo.roles[string(roleID)] = &auth.Role{ID: roleID, Name: "admin"}
|
|
|
|
svc := service.NewRoleService(repo)
|
|
h := NewRoleHandler(svc)
|
|
app := fiber.New()
|
|
app.Post("/api/v1/roles/:uuid/permissions", h.AssignPermission)
|
|
|
|
idStr, _ := uuidv7.BytesToString(roleID)
|
|
permID, _ := uuidv7.BytesToString(uuidv7.MustBytes())
|
|
payload := []byte(`{"data":{"type":"role_permission","attributes":{"permission_id":"` + permID + `"}}}`)
|
|
req, _ := http.NewRequest(http.MethodPost, "/api/v1/roles/"+idStr+"/permissions", bytes.NewReader(payload))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, err := app.Test(req)
|
|
if err != nil {
|
|
t.Fatalf("app.Test: %v", err)
|
|
}
|
|
if resp.StatusCode != http.StatusOK {
|
|
t.Fatalf("expected 200, got %d", resp.StatusCode)
|
|
}
|
|
}
|
|
|
|
func TestRoleHandler_RemovePermission_Success(t *testing.T) {
|
|
repo := newMemRoleRepo()
|
|
roleID := uuidv7.MustBytes()
|
|
repo.roles[string(roleID)] = &auth.Role{ID: roleID, Name: "admin"}
|
|
|
|
svc := service.NewRoleService(repo)
|
|
h := NewRoleHandler(svc)
|
|
app := fiber.New()
|
|
app.Delete("/api/v1/roles/:uuid/permissions/:permission_uuid", h.RemovePermission)
|
|
|
|
idStr, _ := uuidv7.BytesToString(roleID)
|
|
permID, _ := uuidv7.BytesToString(uuidv7.MustBytes())
|
|
req, _ := http.NewRequest(http.MethodDelete, "/api/v1/roles/"+idStr+"/permissions/"+permID, nil)
|
|
resp, err := app.Test(req)
|
|
if err != nil {
|
|
t.Fatalf("app.Test: %v", err)
|
|
}
|
|
if resp.StatusCode != http.StatusOK {
|
|
t.Fatalf("expected 200, got %d", resp.StatusCode)
|
|
}
|
|
}
|
|
|
|
func TestRoleHandler_AssignPermissionsBulk_Success(t *testing.T) {
|
|
repo := newMemRoleRepo()
|
|
roleID := uuidv7.MustBytes()
|
|
repo.roles[string(roleID)] = &auth.Role{ID: roleID, Name: "admin"}
|
|
|
|
svc := service.NewRoleService(repo)
|
|
h := NewRoleHandler(svc)
|
|
app := fiber.New()
|
|
app.Post("/api/v1/roles/:uuid/permissions/assign-bulk", h.AssignPermissionsBulk)
|
|
|
|
idStr, _ := uuidv7.BytesToString(roleID)
|
|
permID1, _ := uuidv7.BytesToString(uuidv7.MustBytes())
|
|
permID2, _ := uuidv7.BytesToString(uuidv7.MustBytes())
|
|
payload := []byte(`{"data":{"type":"role_assign_permission_bulk","attributes":{"permission_ids":["` + permID1 + `","` + permID2 + `"]}}}`)
|
|
req, _ := http.NewRequest(http.MethodPost, "/api/v1/roles/"+idStr+"/permissions/assign-bulk", bytes.NewReader(payload))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, err := app.Test(req)
|
|
if err != nil {
|
|
t.Fatalf("app.Test: %v", err)
|
|
}
|
|
if resp.StatusCode != http.StatusOK {
|
|
t.Fatalf("expected 200, got %d", resp.StatusCode)
|
|
}
|
|
}
|
|
|
|
func TestRoleHandler_RemovePermissionsBulk_Success(t *testing.T) {
|
|
repo := newMemRoleRepo()
|
|
roleID := uuidv7.MustBytes()
|
|
repo.roles[string(roleID)] = &auth.Role{ID: roleID, Name: "admin"}
|
|
|
|
svc := service.NewRoleService(repo)
|
|
h := NewRoleHandler(svc)
|
|
app := fiber.New()
|
|
app.Post("/api/v1/roles/:uuid/permissions/remove-bulk", h.RemovePermissionsBulk)
|
|
|
|
idStr, _ := uuidv7.BytesToString(roleID)
|
|
permID1, _ := uuidv7.BytesToString(uuidv7.MustBytes())
|
|
permID2, _ := uuidv7.BytesToString(uuidv7.MustBytes())
|
|
payload := []byte(`{"data":{"type":"role_remove_permission_bulk","attributes":{"permission_ids":["` + permID1 + `","` + permID2 + `"]}}}`)
|
|
req, _ := http.NewRequest(http.MethodPost, "/api/v1/roles/"+idStr+"/permissions/remove-bulk", bytes.NewReader(payload))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, err := app.Test(req)
|
|
if err != nil {
|
|
t.Fatalf("app.Test: %v", err)
|
|
}
|
|
if resp.StatusCode != http.StatusOK {
|
|
t.Fatalf("expected 200, got %d", resp.StatusCode)
|
|
}
|
|
}
|
|
|
|
func TestRoleHandler_AssignPermission_InvalidAndErrorPaths(t *testing.T) {
|
|
t.Run("invalid role id", func(t *testing.T) {
|
|
repo := newMemRoleRepo()
|
|
svc := service.NewRoleService(repo)
|
|
h := NewRoleHandler(svc)
|
|
app := fiber.New()
|
|
app.Post("/api/v1/roles/:uuid/permissions", h.AssignPermission)
|
|
|
|
payload := []byte(`{"data":{"type":"role_permission","attributes":{"permission_id":"bad"}}}`)
|
|
req, _ := http.NewRequest(http.MethodPost, "/api/v1/roles/not-uuid/permissions", bytes.NewReader(payload))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, _ := app.Test(req)
|
|
if resp.StatusCode != http.StatusUnprocessableEntity {
|
|
t.Fatalf("expected 422, got %d", resp.StatusCode)
|
|
}
|
|
})
|
|
|
|
t.Run("permission not found", func(t *testing.T) {
|
|
repo := newMemRoleRepo()
|
|
repo.permissionNotFound = true
|
|
roleID := uuidv7.MustBytes()
|
|
repo.roles[string(roleID)] = &auth.Role{ID: roleID, Name: "admin"}
|
|
svc := service.NewRoleService(repo)
|
|
h := NewRoleHandler(svc)
|
|
app := fiber.New()
|
|
app.Post("/api/v1/roles/:uuid/permissions", h.AssignPermission)
|
|
|
|
idStr, _ := uuidv7.BytesToString(roleID)
|
|
permID, _ := uuidv7.BytesToString(uuidv7.MustBytes())
|
|
payload := []byte(`{"data":{"type":"role_permission","attributes":{"permission_id":"` + permID + `"}}}`)
|
|
req, _ := http.NewRequest(http.MethodPost, "/api/v1/roles/"+idStr+"/permissions", bytes.NewReader(payload))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, _ := app.Test(req)
|
|
if resp.StatusCode != http.StatusNotFound {
|
|
t.Fatalf("expected 404, got %d", resp.StatusCode)
|
|
}
|
|
})
|
|
|
|
t.Run("assign service error", func(t *testing.T) {
|
|
repo := newMemRoleRepo()
|
|
repo.assignPermissionErr = errors.New("db error")
|
|
roleID := uuidv7.MustBytes()
|
|
repo.roles[string(roleID)] = &auth.Role{ID: roleID, Name: "admin"}
|
|
svc := service.NewRoleService(repo)
|
|
h := NewRoleHandler(svc)
|
|
app := fiber.New()
|
|
app.Post("/api/v1/roles/:uuid/permissions", h.AssignPermission)
|
|
|
|
idStr, _ := uuidv7.BytesToString(roleID)
|
|
permID, _ := uuidv7.BytesToString(uuidv7.MustBytes())
|
|
payload := []byte(`{"data":{"type":"role_permission","attributes":{"permission_id":"` + permID + `"}}}`)
|
|
req, _ := http.NewRequest(http.MethodPost, "/api/v1/roles/"+idStr+"/permissions", bytes.NewReader(payload))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, _ := app.Test(req)
|
|
if resp.StatusCode != http.StatusBadRequest {
|
|
t.Fatalf("expected 400, got %d", resp.StatusCode)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestRoleHandler_RemovePermission_ErrorPaths(t *testing.T) {
|
|
repo := newMemRoleRepo()
|
|
roleID := uuidv7.MustBytes()
|
|
repo.roles[string(roleID)] = &auth.Role{ID: roleID, Name: "admin"}
|
|
repo.removePermissionErr = errors.New("db error")
|
|
svc := service.NewRoleService(repo)
|
|
h := NewRoleHandler(svc)
|
|
app := fiber.New()
|
|
app.Delete("/api/v1/roles/:uuid/permissions/:permission_uuid", h.RemovePermission)
|
|
|
|
idStr, _ := uuidv7.BytesToString(roleID)
|
|
permID, _ := uuidv7.BytesToString(uuidv7.MustBytes())
|
|
req, _ := http.NewRequest(http.MethodDelete, "/api/v1/roles/"+idStr+"/permissions/"+permID, nil)
|
|
resp, _ := app.Test(req)
|
|
if resp.StatusCode != http.StatusBadRequest {
|
|
t.Fatalf("expected 400, got %d", resp.StatusCode)
|
|
}
|
|
}
|
|
|
|
func TestRoleHandler_RemovePermission_InvalidPermissionID(t *testing.T) {
|
|
repo := newMemRoleRepo()
|
|
roleID := uuidv7.MustBytes()
|
|
repo.roles[string(roleID)] = &auth.Role{ID: roleID, Name: "admin"}
|
|
svc := service.NewRoleService(repo)
|
|
h := NewRoleHandler(svc)
|
|
app := fiber.New()
|
|
app.Delete("/api/v1/roles/:uuid/permissions/:permission_uuid", h.RemovePermission)
|
|
|
|
idStr, _ := uuidv7.BytesToString(roleID)
|
|
req, _ := http.NewRequest(http.MethodDelete, "/api/v1/roles/"+idStr+"/permissions/not-uuid", nil)
|
|
resp, _ := app.Test(req)
|
|
if resp.StatusCode != http.StatusUnprocessableEntity {
|
|
t.Fatalf("expected 422, got %d", resp.StatusCode)
|
|
}
|
|
}
|
|
|
|
func TestRoleHandler_AssignPermissionsBulk_ErrorPaths(t *testing.T) {
|
|
t.Run("empty list", func(t *testing.T) {
|
|
repo := newMemRoleRepo()
|
|
roleID := uuidv7.MustBytes()
|
|
repo.roles[string(roleID)] = &auth.Role{ID: roleID, Name: "admin"}
|
|
svc := service.NewRoleService(repo)
|
|
h := NewRoleHandler(svc)
|
|
app := fiber.New()
|
|
app.Post("/api/v1/roles/:uuid/permissions/assign-bulk", h.AssignPermissionsBulk)
|
|
|
|
idStr, _ := uuidv7.BytesToString(roleID)
|
|
payload := []byte(`{"data":{"type":"role_assign_permission_bulk","attributes":{"permission_ids":[]}}}`)
|
|
req, _ := http.NewRequest(http.MethodPost, "/api/v1/roles/"+idStr+"/permissions/assign-bulk", bytes.NewReader(payload))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, _ := app.Test(req)
|
|
if resp.StatusCode != http.StatusUnprocessableEntity {
|
|
t.Fatalf("expected 422, got %d", resp.StatusCode)
|
|
}
|
|
})
|
|
|
|
t.Run("invalid permission id", func(t *testing.T) {
|
|
repo := newMemRoleRepo()
|
|
roleID := uuidv7.MustBytes()
|
|
repo.roles[string(roleID)] = &auth.Role{ID: roleID, Name: "admin"}
|
|
svc := service.NewRoleService(repo)
|
|
h := NewRoleHandler(svc)
|
|
app := fiber.New()
|
|
app.Post("/api/v1/roles/:uuid/permissions/assign-bulk", h.AssignPermissionsBulk)
|
|
|
|
idStr, _ := uuidv7.BytesToString(roleID)
|
|
payload := []byte(`{"data":{"type":"role_assign_permission_bulk","attributes":{"permission_ids":["bad"]}}}`)
|
|
req, _ := http.NewRequest(http.MethodPost, "/api/v1/roles/"+idStr+"/permissions/assign-bulk", bytes.NewReader(payload))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, _ := app.Test(req)
|
|
if resp.StatusCode != http.StatusUnprocessableEntity {
|
|
t.Fatalf("expected 422, got %d", resp.StatusCode)
|
|
}
|
|
})
|
|
|
|
t.Run("assign error", func(t *testing.T) {
|
|
repo := newMemRoleRepo()
|
|
repo.assignPermissionErr = errors.New("db error")
|
|
roleID := uuidv7.MustBytes()
|
|
repo.roles[string(roleID)] = &auth.Role{ID: roleID, Name: "admin"}
|
|
svc := service.NewRoleService(repo)
|
|
h := NewRoleHandler(svc)
|
|
app := fiber.New()
|
|
app.Post("/api/v1/roles/:uuid/permissions/assign-bulk", h.AssignPermissionsBulk)
|
|
|
|
idStr, _ := uuidv7.BytesToString(roleID)
|
|
permID, _ := uuidv7.BytesToString(uuidv7.MustBytes())
|
|
payload := []byte(`{"data":{"type":"role_assign_permission_bulk","attributes":{"permission_ids":["` + permID + `"]}}}`)
|
|
req, _ := http.NewRequest(http.MethodPost, "/api/v1/roles/"+idStr+"/permissions/assign-bulk", bytes.NewReader(payload))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, _ := app.Test(req)
|
|
if resp.StatusCode != http.StatusBadRequest {
|
|
t.Fatalf("expected 400, got %d", resp.StatusCode)
|
|
}
|
|
})
|
|
t.Run("invalid type", func(t *testing.T) {
|
|
repo := newMemRoleRepo()
|
|
roleID := uuidv7.MustBytes()
|
|
repo.roles[string(roleID)] = &auth.Role{ID: roleID, Name: "admin"}
|
|
svc := service.NewRoleService(repo)
|
|
h := NewRoleHandler(svc)
|
|
app := fiber.New()
|
|
app.Post("/api/v1/roles/:uuid/permissions/assign-bulk", h.AssignPermissionsBulk)
|
|
|
|
idStr, _ := uuidv7.BytesToString(roleID)
|
|
permID, _ := uuidv7.BytesToString(uuidv7.MustBytes())
|
|
payload := []byte(`{"data":{"type":"role_remove_permission_bulk","attributes":{"permission_ids":["` + permID + `"]}}}`)
|
|
req, _ := http.NewRequest(http.MethodPost, "/api/v1/roles/"+idStr+"/permissions/assign-bulk", bytes.NewReader(payload))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, _ := app.Test(req)
|
|
if resp.StatusCode != http.StatusUnprocessableEntity {
|
|
t.Fatalf("expected 422, got %d", resp.StatusCode)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestRoleHandler_RemovePermissionsBulk_ErrorPaths(t *testing.T) {
|
|
t.Run("remove error", func(t *testing.T) {
|
|
repo := newMemRoleRepo()
|
|
repo.removePermissionErr = errors.New("db error")
|
|
roleID := uuidv7.MustBytes()
|
|
repo.roles[string(roleID)] = &auth.Role{ID: roleID, Name: "admin"}
|
|
svc := service.NewRoleService(repo)
|
|
h := NewRoleHandler(svc)
|
|
app := fiber.New()
|
|
app.Post("/api/v1/roles/:uuid/permissions/remove-bulk", h.RemovePermissionsBulk)
|
|
|
|
idStr, _ := uuidv7.BytesToString(roleID)
|
|
permID, _ := uuidv7.BytesToString(uuidv7.MustBytes())
|
|
payload := []byte(`{"data":{"type":"role_remove_permission_bulk","attributes":{"permission_ids":["` + permID + `"]}}}`)
|
|
req, _ := http.NewRequest(http.MethodPost, "/api/v1/roles/"+idStr+"/permissions/remove-bulk", bytes.NewReader(payload))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, _ := app.Test(req)
|
|
if resp.StatusCode != http.StatusBadRequest {
|
|
t.Fatalf("expected 400, got %d", resp.StatusCode)
|
|
}
|
|
})
|
|
|
|
t.Run("invalid type", func(t *testing.T) {
|
|
repo := newMemRoleRepo()
|
|
roleID := uuidv7.MustBytes()
|
|
repo.roles[string(roleID)] = &auth.Role{ID: roleID, Name: "admin"}
|
|
svc := service.NewRoleService(repo)
|
|
h := NewRoleHandler(svc)
|
|
app := fiber.New()
|
|
app.Post("/api/v1/roles/:uuid/permissions/remove-bulk", h.RemovePermissionsBulk)
|
|
|
|
idStr, _ := uuidv7.BytesToString(roleID)
|
|
permID, _ := uuidv7.BytesToString(uuidv7.MustBytes())
|
|
payload := []byte(`{"data":{"type":"role_assign_permission_bulk","attributes":{"permission_ids":["` + permID + `"]}}}`)
|
|
req, _ := http.NewRequest(http.MethodPost, "/api/v1/roles/"+idStr+"/permissions/remove-bulk", bytes.NewReader(payload))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, _ := app.Test(req)
|
|
if resp.StatusCode != http.StatusUnprocessableEntity {
|
|
t.Fatalf("expected 422, got %d", resp.StatusCode)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestRoleHandler_AssignPermissionsBulk_InvalidIDAndRoleNotFound(t *testing.T) {
|
|
repo := newMemRoleRepo()
|
|
svc := service.NewRoleService(repo)
|
|
h := NewRoleHandler(svc)
|
|
app := fiber.New()
|
|
app.Post("/api/v1/roles/:uuid/permissions/assign-bulk", h.AssignPermissionsBulk)
|
|
|
|
req1, _ := http.NewRequest(http.MethodPost, "/api/v1/roles/not-uuid/permissions/assign-bulk", bytes.NewReader([]byte(`{}`)))
|
|
req1.Header.Set("Content-Type", "application/json")
|
|
resp1, _ := app.Test(req1)
|
|
if resp1.StatusCode != http.StatusUnprocessableEntity {
|
|
t.Fatalf("expected 422, got %d", resp1.StatusCode)
|
|
}
|
|
|
|
roleID := uuidv7.MustBytes()
|
|
idStr, _ := uuidv7.BytesToString(roleID)
|
|
permID, _ := uuidv7.BytesToString(uuidv7.MustBytes())
|
|
payload := []byte(`{"data":{"type":"role_assign_permission_bulk","attributes":{"permission_ids":["` + permID + `"]}}}`)
|
|
req2, _ := http.NewRequest(http.MethodPost, "/api/v1/roles/"+idStr+"/permissions/assign-bulk", bytes.NewReader(payload))
|
|
req2.Header.Set("Content-Type", "application/json")
|
|
resp2, _ := app.Test(req2)
|
|
if resp2.StatusCode != http.StatusNotFound {
|
|
t.Fatalf("expected 404, got %d", resp2.StatusCode)
|
|
}
|
|
}
|
|
|
|
func TestRoleHandler_AssignPermissionsBulk_PermissionNotFound(t *testing.T) {
|
|
repo := newMemRoleRepo()
|
|
repo.permissionNotFound = true
|
|
roleID := uuidv7.MustBytes()
|
|
repo.roles[string(roleID)] = &auth.Role{ID: roleID, Name: "admin"}
|
|
svc := service.NewRoleService(repo)
|
|
h := NewRoleHandler(svc)
|
|
app := fiber.New()
|
|
app.Post("/api/v1/roles/:uuid/permissions/assign-bulk", h.AssignPermissionsBulk)
|
|
|
|
idStr, _ := uuidv7.BytesToString(roleID)
|
|
permID, _ := uuidv7.BytesToString(uuidv7.MustBytes())
|
|
payload := []byte(`{"data":{"type":"role_assign_permission_bulk","attributes":{"permission_ids":["` + permID + `"]}}}`)
|
|
req, _ := http.NewRequest(http.MethodPost, "/api/v1/roles/"+idStr+"/permissions/assign-bulk", bytes.NewReader(payload))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, _ := app.Test(req)
|
|
if resp.StatusCode != http.StatusNotFound {
|
|
t.Fatalf("expected 404, got %d", resp.StatusCode)
|
|
}
|
|
}
|
|
|
|
func TestRoleHandler_RemovePermissionsBulk_ValidationAndNotFoundPaths(t *testing.T) {
|
|
repo := newMemRoleRepo()
|
|
svc := service.NewRoleService(repo)
|
|
h := NewRoleHandler(svc)
|
|
app := fiber.New()
|
|
app.Post("/api/v1/roles/:uuid/permissions/remove-bulk", h.RemovePermissionsBulk)
|
|
|
|
req1, _ := http.NewRequest(http.MethodPost, "/api/v1/roles/not-uuid/permissions/remove-bulk", bytes.NewReader([]byte(`{}`)))
|
|
req1.Header.Set("Content-Type", "application/json")
|
|
resp1, _ := app.Test(req1)
|
|
if resp1.StatusCode != http.StatusUnprocessableEntity {
|
|
t.Fatalf("expected 422, got %d", resp1.StatusCode)
|
|
}
|
|
|
|
roleID := uuidv7.MustBytes()
|
|
idStr, _ := uuidv7.BytesToString(roleID)
|
|
payloadEmpty := []byte(`{"data":{"type":"role_remove_permission_bulk","attributes":{"permission_ids":[]}}}`)
|
|
req2, _ := http.NewRequest(http.MethodPost, "/api/v1/roles/"+idStr+"/permissions/remove-bulk", bytes.NewReader(payloadEmpty))
|
|
req2.Header.Set("Content-Type", "application/json")
|
|
resp2, _ := app.Test(req2)
|
|
if resp2.StatusCode != http.StatusUnprocessableEntity {
|
|
t.Fatalf("expected 422, got %d", resp2.StatusCode)
|
|
}
|
|
|
|
permID, _ := uuidv7.BytesToString(uuidv7.MustBytes())
|
|
payload := []byte(`{"data":{"type":"role_remove_permission_bulk","attributes":{"permission_ids":["` + permID + `"]}}}`)
|
|
req3, _ := http.NewRequest(http.MethodPost, "/api/v1/roles/"+idStr+"/permissions/remove-bulk", bytes.NewReader(payload))
|
|
req3.Header.Set("Content-Type", "application/json")
|
|
resp3, _ := app.Test(req3)
|
|
if resp3.StatusCode != http.StatusNotFound {
|
|
t.Fatalf("expected 404, got %d", resp3.StatusCode)
|
|
}
|
|
}
|
|
|
|
func TestRoleHandler_ListPermissions_Success(t *testing.T) {
|
|
repo := newMemRoleRepo()
|
|
repo.listPermissions = []auth.Permission{
|
|
{
|
|
ID: uuidv7.MustBytes(),
|
|
Name: "Read User",
|
|
Key: "user.read",
|
|
Description: "Read users",
|
|
},
|
|
}
|
|
repo.listPermissionsTotal = 1
|
|
|
|
svc := service.NewRoleService(repo)
|
|
h := NewRoleHandler(svc)
|
|
app := fiber.New()
|
|
app.Get("/api/v1/roles/permissions/get-all", h.ListPermissions)
|
|
|
|
req, _ := http.NewRequest(http.MethodGet, "/api/v1/roles/permissions/get-all?page[number]=1&page[size]=10&filter[name]=read&sort=name", nil)
|
|
resp, err := app.Test(req)
|
|
if err != nil {
|
|
t.Fatalf("app.Test: %v", err)
|
|
}
|
|
if resp.StatusCode != http.StatusOK {
|
|
t.Fatalf("expected 200, got %d", resp.StatusCode)
|
|
}
|
|
}
|
|
|
|
func TestRoleHandler_ListPermissions_Error(t *testing.T) {
|
|
repo := newMemRoleRepo()
|
|
repo.listPermissionsErr = errors.New("db error")
|
|
|
|
svc := service.NewRoleService(repo)
|
|
h := NewRoleHandler(svc)
|
|
app := fiber.New()
|
|
app.Get("/api/v1/roles/permissions/get-all", h.ListPermissions)
|
|
|
|
req, _ := http.NewRequest(http.MethodGet, "/api/v1/roles/permissions/get-all", nil)
|
|
resp, err := app.Test(req)
|
|
if err != nil {
|
|
t.Fatalf("app.Test: %v", err)
|
|
}
|
|
if resp.StatusCode != http.StatusBadRequest {
|
|
t.Fatalf("expected 400, got %d", resp.StatusCode)
|
|
}
|
|
}
|
|
|
|
func TestRoleHandler_UpdatePermission_Success(t *testing.T) {
|
|
repo := newMemRoleRepo()
|
|
permissionID := uuidv7.MustBytes()
|
|
repo.permissions[string(permissionID)] = &auth.Permission{
|
|
ID: permissionID,
|
|
Name: "Delete User",
|
|
Key: "user.delete",
|
|
Description: "Delete users",
|
|
RequiresPIN: false,
|
|
}
|
|
|
|
svc := service.NewRoleService(repo)
|
|
h := NewRoleHandler(svc)
|
|
app := fiber.New()
|
|
app.Patch("/api/v1/roles/permissions/:permission_uuid", h.UpdatePermission)
|
|
|
|
permissionIDStr, _ := uuidv7.BytesToString(permissionID)
|
|
payload := []byte(`{"data":{"type":"permission_update","id":"` + permissionIDStr + `","attributes":{"requires_pin":true}}}`)
|
|
req, _ := http.NewRequest(http.MethodPatch, "/api/v1/roles/permissions/"+permissionIDStr, bytes.NewReader(payload))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, err := app.Test(req)
|
|
if err != nil {
|
|
t.Fatalf("app.Test: %v", err)
|
|
}
|
|
if resp.StatusCode != http.StatusOK {
|
|
t.Fatalf("expected 200, got %d", resp.StatusCode)
|
|
}
|
|
if !repo.permissions[string(permissionID)].RequiresPIN {
|
|
t.Fatalf("expected permission requires_pin updated")
|
|
}
|
|
}
|
|
|
|
func TestRoleHandler_UpdatePermission_NotFound(t *testing.T) {
|
|
repo := newMemRoleRepo()
|
|
repo.permissionNotFound = true
|
|
|
|
svc := service.NewRoleService(repo)
|
|
h := NewRoleHandler(svc)
|
|
app := fiber.New()
|
|
app.Patch("/api/v1/roles/permissions/:permission_uuid", h.UpdatePermission)
|
|
|
|
permissionIDStr, _ := uuidv7.BytesToString(uuidv7.MustBytes())
|
|
payload := []byte(`{"data":{"type":"permission_update","id":"` + permissionIDStr + `","attributes":{"requires_pin":true}}}`)
|
|
req, _ := http.NewRequest(http.MethodPatch, "/api/v1/roles/permissions/"+permissionIDStr, bytes.NewReader(payload))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, err := app.Test(req)
|
|
if err != nil {
|
|
t.Fatalf("app.Test: %v", err)
|
|
}
|
|
if resp.StatusCode != http.StatusNotFound {
|
|
t.Fatalf("expected 404, got %d", resp.StatusCode)
|
|
}
|
|
}
|
|
|
|
func TestRoleHandler_UpdatePermission_ErrorBranches(t *testing.T) {
|
|
repo := newMemRoleRepo()
|
|
svc := service.NewRoleService(repo)
|
|
h := NewRoleHandler(svc)
|
|
app := fiber.New()
|
|
app.Patch("/api/v1/roles/permissions/:permission_uuid", h.UpdatePermission)
|
|
|
|
t.Run("invalid path id", func(t *testing.T) {
|
|
req, _ := http.NewRequest(http.MethodPatch, "/api/v1/roles/permissions/not-a-uuid", bytes.NewReader([]byte(`{"data":{"type":"permission_update","id":"x","attributes":{"requires_pin":true}}}`)))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, _ := app.Test(req)
|
|
if resp.StatusCode != http.StatusUnprocessableEntity {
|
|
t.Fatalf("expected 422, got %d", resp.StatusCode)
|
|
}
|
|
})
|
|
|
|
t.Run("invalid json", func(t *testing.T) {
|
|
idStr, _ := uuidv7.BytesToString(uuidv7.MustBytes())
|
|
req, _ := http.NewRequest(http.MethodPatch, "/api/v1/roles/permissions/"+idStr, bytes.NewReader([]byte(`{"data":`)))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, _ := app.Test(req)
|
|
if resp.StatusCode != http.StatusBadRequest {
|
|
t.Fatalf("expected 400, got %d", resp.StatusCode)
|
|
}
|
|
})
|
|
|
|
t.Run("missing data id", func(t *testing.T) {
|
|
idStr, _ := uuidv7.BytesToString(uuidv7.MustBytes())
|
|
req, _ := http.NewRequest(http.MethodPatch, "/api/v1/roles/permissions/"+idStr, bytes.NewReader([]byte(`{"data":{"type":"permission_update","attributes":{"requires_pin":true}}}`)))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, _ := app.Test(req)
|
|
if resp.StatusCode != http.StatusUnprocessableEntity {
|
|
t.Fatalf("expected 422, got %d", resp.StatusCode)
|
|
}
|
|
})
|
|
|
|
t.Run("id mismatch", func(t *testing.T) {
|
|
pathID, _ := uuidv7.BytesToString(uuidv7.MustBytes())
|
|
otherID, _ := uuidv7.BytesToString(uuidv7.MustBytes())
|
|
req, _ := http.NewRequest(http.MethodPatch, "/api/v1/roles/permissions/"+pathID, bytes.NewReader([]byte(`{"data":{"type":"permission_update","id":"`+otherID+`","attributes":{"requires_pin":true}}}`)))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, _ := app.Test(req)
|
|
if resp.StatusCode != http.StatusUnprocessableEntity {
|
|
t.Fatalf("expected 422, got %d", resp.StatusCode)
|
|
}
|
|
})
|
|
|
|
t.Run("missing requires_pin", func(t *testing.T) {
|
|
pathID, _ := uuidv7.BytesToString(uuidv7.MustBytes())
|
|
req, _ := http.NewRequest(http.MethodPatch, "/api/v1/roles/permissions/"+pathID, bytes.NewReader([]byte(`{"data":{"type":"permission_update","id":"`+pathID+`","attributes":{}}}`)))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, _ := app.Test(req)
|
|
if resp.StatusCode != http.StatusUnprocessableEntity {
|
|
t.Fatalf("expected 422, got %d", resp.StatusCode)
|
|
}
|
|
})
|
|
|
|
t.Run("update service error", func(t *testing.T) {
|
|
id := uuidv7.MustBytes()
|
|
idStr, _ := uuidv7.BytesToString(id)
|
|
repo.permissions[string(id)] = &auth.Permission{ID: id, Key: "x", Name: "x"}
|
|
repo.updateErr = errors.New("update failed")
|
|
defer func() { repo.updateErr = nil }()
|
|
req, _ := http.NewRequest(http.MethodPatch, "/api/v1/roles/permissions/"+idStr, bytes.NewReader([]byte(`{"data":{"type":"permission_update","id":"`+idStr+`","attributes":{"requires_pin":true}}}`)))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, _ := app.Test(req)
|
|
if resp.StatusCode != http.StatusBadRequest {
|
|
t.Fatalf("expected 400, got %d", resp.StatusCode)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestParseIntToString(t *testing.T) {
|
|
if got := parseIntToString(0); got != "0" {
|
|
t.Fatalf("expected 0, got %s", got)
|
|
}
|
|
if got := parseIntToString(123); got != "123" {
|
|
t.Fatalf("expected 123, got %s", got)
|
|
}
|
|
}
|
|
|
|
func TestRoleResource(t *testing.T) {
|
|
now := time.Now().UTC()
|
|
role := &auth.Role{
|
|
ID: uuidv7.MustBytes(),
|
|
Name: "admin",
|
|
Description: "full access",
|
|
CreatedBy: uuidv7.MustBytes(),
|
|
CreatedAt: now,
|
|
UpdatedAt: now,
|
|
}
|
|
|
|
res := roleResource(role)
|
|
if res.Type != "role" || res.ID == "" {
|
|
t.Fatalf("expected role resource type/id")
|
|
}
|
|
if res.Attributes.CreatedBy == "" {
|
|
t.Fatalf("expected created_by in role resource")
|
|
}
|
|
}
|