585 lines
14 KiB
Go
585 lines
14 KiB
Go
package services
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"gorm.io/driver/sqlite"
|
|
"gorm.io/gorm"
|
|
|
|
"veza-backend-api/internal/models"
|
|
)
|
|
|
|
func setupTestRoleService(t *testing.T) (*RoleService, *gorm.DB, func()) {
|
|
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
|
|
require.NoError(t, err)
|
|
|
|
db.Exec("PRAGMA foreign_keys = ON")
|
|
|
|
err = db.AutoMigrate(
|
|
&models.User{},
|
|
&models.Role{},
|
|
&models.Permission{},
|
|
&models.UserRole{},
|
|
&models.RolePermission{},
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
service := NewRoleService(db)
|
|
|
|
cleanup := func() {
|
|
sqlDB, _ := db.DB()
|
|
if sqlDB != nil {
|
|
sqlDB.Close()
|
|
}
|
|
}
|
|
|
|
return service, db, cleanup
|
|
}
|
|
|
|
func TestRoleService_NewRoleService(t *testing.T) {
|
|
_, db, cleanup := setupTestRoleService(t)
|
|
defer cleanup()
|
|
|
|
service := NewRoleService(db)
|
|
|
|
assert.NotNil(t, service)
|
|
assert.NotNil(t, service.db)
|
|
}
|
|
|
|
func TestRoleService_GetRoles_Empty(t *testing.T) {
|
|
service, _, cleanup := setupTestRoleService(t)
|
|
defer cleanup()
|
|
|
|
ctx := context.Background()
|
|
roles, err := service.GetRoles(ctx)
|
|
|
|
assert.NoError(t, err)
|
|
assert.NotNil(t, roles)
|
|
assert.Len(t, roles, 0)
|
|
}
|
|
|
|
func TestRoleService_CreateRole_Success(t *testing.T) {
|
|
service, db, cleanup := setupTestRoleService(t)
|
|
defer cleanup()
|
|
|
|
ctx := context.Background()
|
|
role := &models.Role{
|
|
Name: "test_role",
|
|
Description: "Test role description",
|
|
IsSystem: false,
|
|
}
|
|
|
|
err := service.CreateRole(ctx, role)
|
|
assert.NoError(t, err)
|
|
assert.NotEqual(t, uuid.Nil, role.ID)
|
|
|
|
// Verify role was created
|
|
var createdRole models.Role
|
|
err = db.First(&createdRole, role.ID).Error
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, "test_role", createdRole.Name)
|
|
assert.Equal(t, "Test role description", createdRole.Description)
|
|
assert.False(t, createdRole.IsSystem)
|
|
}
|
|
|
|
func TestRoleService_GetRole_Success(t *testing.T) {
|
|
service, db, cleanup := setupTestRoleService(t)
|
|
defer cleanup()
|
|
|
|
ctx := context.Background()
|
|
role := &models.Role{
|
|
Name: "test_role",
|
|
Description: "Test role description",
|
|
IsSystem: false,
|
|
}
|
|
err := db.Create(role).Error
|
|
require.NoError(t, err)
|
|
|
|
retrievedRole, err := service.GetRole(ctx, role.ID)
|
|
assert.NoError(t, err)
|
|
assert.NotNil(t, retrievedRole)
|
|
assert.Equal(t, role.ID, retrievedRole.ID)
|
|
assert.Equal(t, "test_role", retrievedRole.Name)
|
|
}
|
|
|
|
func TestRoleService_GetRole_NotFound(t *testing.T) {
|
|
service, _, cleanup := setupTestRoleService(t)
|
|
defer cleanup()
|
|
|
|
ctx := context.Background()
|
|
nonExistentID := uuid.New()
|
|
|
|
role, err := service.GetRole(ctx, nonExistentID)
|
|
assert.Error(t, err)
|
|
assert.Nil(t, role)
|
|
assert.Contains(t, err.Error(), "role not found")
|
|
}
|
|
|
|
func TestRoleService_UpdateRole_Success(t *testing.T) {
|
|
service, db, cleanup := setupTestRoleService(t)
|
|
defer cleanup()
|
|
|
|
ctx := context.Background()
|
|
role := &models.Role{
|
|
Name: "test_role",
|
|
Description: "Original description",
|
|
IsSystem: false,
|
|
}
|
|
err := db.Create(role).Error
|
|
require.NoError(t, err)
|
|
|
|
updates := &models.Role{
|
|
Name: "updated_role",
|
|
Description: "Updated description",
|
|
}
|
|
|
|
err = service.UpdateRole(ctx, role.ID, updates)
|
|
assert.NoError(t, err)
|
|
|
|
// Verify role was updated
|
|
var updatedRole models.Role
|
|
err = db.First(&updatedRole, role.ID).Error
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, "updated_role", updatedRole.Name)
|
|
assert.Equal(t, "Updated description", updatedRole.Description)
|
|
}
|
|
|
|
func TestRoleService_UpdateRole_SystemRole(t *testing.T) {
|
|
service, db, cleanup := setupTestRoleService(t)
|
|
defer cleanup()
|
|
|
|
ctx := context.Background()
|
|
role := &models.Role{
|
|
Name: "system_role",
|
|
Description: "System role",
|
|
IsSystem: true,
|
|
}
|
|
err := db.Create(role).Error
|
|
require.NoError(t, err)
|
|
|
|
updates := &models.Role{
|
|
Name: "updated_system_role",
|
|
}
|
|
|
|
err = service.UpdateRole(ctx, role.ID, updates)
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "role not found or is system role")
|
|
}
|
|
|
|
func TestRoleService_UpdateRole_NotFound(t *testing.T) {
|
|
service, _, cleanup := setupTestRoleService(t)
|
|
defer cleanup()
|
|
|
|
ctx := context.Background()
|
|
nonExistentID := uuid.New()
|
|
|
|
updates := &models.Role{
|
|
Name: "updated_role",
|
|
}
|
|
|
|
err := service.UpdateRole(ctx, nonExistentID, updates)
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "role not found or is system role")
|
|
}
|
|
|
|
func TestRoleService_DeleteRole_Success(t *testing.T) {
|
|
service, db, cleanup := setupTestRoleService(t)
|
|
defer cleanup()
|
|
|
|
ctx := context.Background()
|
|
role := &models.Role{
|
|
Name: "test_role",
|
|
Description: "Test role",
|
|
IsSystem: false,
|
|
}
|
|
err := db.Create(role).Error
|
|
require.NoError(t, err)
|
|
|
|
err = service.DeleteRole(ctx, role.ID)
|
|
assert.NoError(t, err)
|
|
|
|
// Verify role was deleted
|
|
var deletedRole models.Role
|
|
err = db.First(&deletedRole, role.ID).Error
|
|
assert.Error(t, err)
|
|
assert.Equal(t, gorm.ErrRecordNotFound, err)
|
|
}
|
|
|
|
func TestRoleService_DeleteRole_SystemRole(t *testing.T) {
|
|
service, db, cleanup := setupTestRoleService(t)
|
|
defer cleanup()
|
|
|
|
ctx := context.Background()
|
|
role := &models.Role{
|
|
Name: "system_role",
|
|
Description: "System role",
|
|
IsSystem: true,
|
|
}
|
|
err := db.Create(role).Error
|
|
require.NoError(t, err)
|
|
|
|
err = service.DeleteRole(ctx, role.ID)
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "cannot delete system role")
|
|
}
|
|
|
|
func TestRoleService_DeleteRole_NotFound(t *testing.T) {
|
|
service, _, cleanup := setupTestRoleService(t)
|
|
defer cleanup()
|
|
|
|
ctx := context.Background()
|
|
nonExistentID := uuid.New()
|
|
|
|
err := service.DeleteRole(ctx, nonExistentID)
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "role not found")
|
|
}
|
|
|
|
func TestRoleService_AssignRoleToUser_Success(t *testing.T) {
|
|
service, db, cleanup := setupTestRoleService(t)
|
|
defer cleanup()
|
|
|
|
ctx := context.Background()
|
|
user := &models.User{
|
|
Username: "testuser",
|
|
Email: "test@example.com",
|
|
PasswordHash: "hash",
|
|
IsActive: true,
|
|
}
|
|
err := db.Create(user).Error
|
|
require.NoError(t, err)
|
|
|
|
role := &models.Role{
|
|
Name: "test_role",
|
|
Description: "Test role",
|
|
IsSystem: false,
|
|
}
|
|
err = db.Create(role).Error
|
|
require.NoError(t, err)
|
|
|
|
assignedBy := uuid.New()
|
|
err = service.AssignRoleToUser(ctx, user.ID, role.ID, assignedBy, nil)
|
|
assert.NoError(t, err)
|
|
|
|
// Verify role was assigned
|
|
var userRole models.UserRole
|
|
err = db.Where("user_id = ? AND role_id = ?", user.ID, role.ID).First(&userRole).Error
|
|
assert.NoError(t, err)
|
|
assert.True(t, userRole.IsActive)
|
|
}
|
|
|
|
func TestRoleService_RevokeRoleFromUser_Success(t *testing.T) {
|
|
service, db, cleanup := setupTestRoleService(t)
|
|
defer cleanup()
|
|
|
|
ctx := context.Background()
|
|
user := &models.User{
|
|
Username: "testuser",
|
|
Email: "test@example.com",
|
|
PasswordHash: "hash",
|
|
IsActive: true,
|
|
}
|
|
err := db.Create(user).Error
|
|
require.NoError(t, err)
|
|
|
|
role := &models.Role{
|
|
Name: "test_role",
|
|
Description: "Test role",
|
|
IsSystem: false,
|
|
}
|
|
err = db.Create(role).Error
|
|
require.NoError(t, err)
|
|
|
|
assignedBy := uuid.New()
|
|
err = service.AssignRoleToUser(ctx, user.ID, role.ID, assignedBy, nil)
|
|
require.NoError(t, err)
|
|
|
|
err = service.RevokeRoleFromUser(ctx, user.ID, role.ID)
|
|
assert.NoError(t, err)
|
|
|
|
// Verify role was revoked
|
|
var userRole models.UserRole
|
|
err = db.Where("user_id = ? AND role_id = ?", user.ID, role.ID).First(&userRole).Error
|
|
assert.NoError(t, err)
|
|
assert.False(t, userRole.IsActive)
|
|
}
|
|
|
|
func TestRoleService_RevokeRoleFromUser_NotFound(t *testing.T) {
|
|
service, db, cleanup := setupTestRoleService(t)
|
|
defer cleanup()
|
|
|
|
ctx := context.Background()
|
|
user := &models.User{
|
|
Username: "testuser",
|
|
Email: "test@example.com",
|
|
PasswordHash: "hash",
|
|
IsActive: true,
|
|
}
|
|
err := db.Create(user).Error
|
|
require.NoError(t, err)
|
|
|
|
role := &models.Role{
|
|
Name: "test_role",
|
|
Description: "Test role",
|
|
IsSystem: false,
|
|
}
|
|
err = db.Create(role).Error
|
|
require.NoError(t, err)
|
|
|
|
err = service.RevokeRoleFromUser(ctx, user.ID, role.ID)
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "role assignment not found")
|
|
}
|
|
|
|
func TestRoleService_GetUserRoles_Success(t *testing.T) {
|
|
service, db, cleanup := setupTestRoleService(t)
|
|
defer cleanup()
|
|
|
|
ctx := context.Background()
|
|
user := &models.User{
|
|
Username: "testuser",
|
|
Email: "test@example.com",
|
|
PasswordHash: "hash",
|
|
IsActive: true,
|
|
}
|
|
err := db.Create(user).Error
|
|
require.NoError(t, err)
|
|
|
|
role1 := &models.Role{
|
|
Name: "role1",
|
|
Description: "Role 1",
|
|
IsSystem: false,
|
|
}
|
|
err = db.Create(role1).Error
|
|
require.NoError(t, err)
|
|
|
|
role2 := &models.Role{
|
|
Name: "role2",
|
|
Description: "Role 2",
|
|
IsSystem: false,
|
|
}
|
|
err = db.Create(role2).Error
|
|
require.NoError(t, err)
|
|
|
|
assignedBy := uuid.New()
|
|
err = service.AssignRoleToUser(ctx, user.ID, role1.ID, assignedBy, nil)
|
|
require.NoError(t, err)
|
|
|
|
err = service.AssignRoleToUser(ctx, user.ID, role2.ID, assignedBy, nil)
|
|
require.NoError(t, err)
|
|
|
|
roles, err := service.GetUserRoles(ctx, user.ID)
|
|
assert.NoError(t, err)
|
|
assert.Len(t, roles, 2) // Both roles should be active
|
|
}
|
|
|
|
func TestRoleService_GetUserRoles_Empty(t *testing.T) {
|
|
service, db, cleanup := setupTestRoleService(t)
|
|
defer cleanup()
|
|
|
|
ctx := context.Background()
|
|
user := &models.User{
|
|
Username: "testuser",
|
|
Email: "test@example.com",
|
|
PasswordHash: "hash",
|
|
IsActive: true,
|
|
}
|
|
err := db.Create(user).Error
|
|
require.NoError(t, err)
|
|
|
|
roles, err := service.GetUserRoles(ctx, user.ID)
|
|
assert.NoError(t, err)
|
|
assert.Len(t, roles, 0)
|
|
}
|
|
|
|
func TestRoleService_HasRole_True(t *testing.T) {
|
|
service, db, cleanup := setupTestRoleService(t)
|
|
defer cleanup()
|
|
|
|
ctx := context.Background()
|
|
user := &models.User{
|
|
Username: "testuser",
|
|
Email: "test@example.com",
|
|
PasswordHash: "hash",
|
|
IsActive: true,
|
|
}
|
|
err := db.Create(user).Error
|
|
require.NoError(t, err)
|
|
|
|
role := &models.Role{
|
|
Name: "test_role",
|
|
Description: "Test role",
|
|
IsSystem: false,
|
|
}
|
|
err = db.Create(role).Error
|
|
require.NoError(t, err)
|
|
|
|
assignedBy := uuid.New()
|
|
err = service.AssignRoleToUser(ctx, user.ID, role.ID, assignedBy, nil)
|
|
require.NoError(t, err)
|
|
|
|
hasRole, err := service.HasRole(ctx, user.ID, "test_role")
|
|
assert.NoError(t, err)
|
|
assert.True(t, hasRole)
|
|
}
|
|
|
|
func TestRoleService_HasRole_False(t *testing.T) {
|
|
service, db, cleanup := setupTestRoleService(t)
|
|
defer cleanup()
|
|
|
|
ctx := context.Background()
|
|
user := &models.User{
|
|
Username: "testuser",
|
|
Email: "test@example.com",
|
|
PasswordHash: "hash",
|
|
IsActive: true,
|
|
}
|
|
err := db.Create(user).Error
|
|
require.NoError(t, err)
|
|
|
|
hasRole, err := service.HasRole(ctx, user.ID, "non_existent_role")
|
|
assert.NoError(t, err)
|
|
assert.False(t, hasRole)
|
|
}
|
|
|
|
func TestRoleService_HasPermission_True(t *testing.T) {
|
|
service, db, cleanup := setupTestRoleService(t)
|
|
defer cleanup()
|
|
|
|
ctx := context.Background()
|
|
user := &models.User{
|
|
Username: "testuser",
|
|
Email: "test@example.com",
|
|
PasswordHash: "hash",
|
|
IsActive: true,
|
|
}
|
|
err := db.Create(user).Error
|
|
require.NoError(t, err)
|
|
|
|
role := &models.Role{
|
|
Name: "test_role",
|
|
Description: "Test role",
|
|
IsSystem: false,
|
|
}
|
|
err = db.Create(role).Error
|
|
require.NoError(t, err)
|
|
|
|
permission := &models.Permission{
|
|
Name: "test_permission",
|
|
Description: "Test permission",
|
|
Resource: "tracks",
|
|
Action: "read",
|
|
}
|
|
err = db.Create(permission).Error
|
|
require.NoError(t, err)
|
|
|
|
rolePermission := &models.RolePermission{
|
|
RoleID: role.ID,
|
|
PermissionID: permission.ID,
|
|
}
|
|
err = db.Create(rolePermission).Error
|
|
require.NoError(t, err)
|
|
|
|
assignedBy := uuid.New()
|
|
err = service.AssignRoleToUser(ctx, user.ID, role.ID, assignedBy, nil)
|
|
require.NoError(t, err)
|
|
|
|
hasPermission, err := service.HasPermission(ctx, user.ID, "tracks", "read")
|
|
assert.NoError(t, err)
|
|
assert.True(t, hasPermission)
|
|
}
|
|
|
|
func TestRoleService_HasPermission_False(t *testing.T) {
|
|
service, db, cleanup := setupTestRoleService(t)
|
|
defer cleanup()
|
|
|
|
ctx := context.Background()
|
|
user := &models.User{
|
|
Username: "testuser",
|
|
Email: "test@example.com",
|
|
PasswordHash: "hash",
|
|
IsActive: true,
|
|
}
|
|
err := db.Create(user).Error
|
|
require.NoError(t, err)
|
|
|
|
hasPermission, err := service.HasPermission(ctx, user.ID, "tracks", "write")
|
|
assert.NoError(t, err)
|
|
assert.False(t, hasPermission)
|
|
}
|
|
|
|
func TestRoleService_GetRoles_WithPermissions(t *testing.T) {
|
|
service, db, cleanup := setupTestRoleService(t)
|
|
defer cleanup()
|
|
|
|
ctx := context.Background()
|
|
role := &models.Role{
|
|
Name: "test_role",
|
|
Description: "Test role",
|
|
IsSystem: false,
|
|
}
|
|
err := db.Create(role).Error
|
|
require.NoError(t, err)
|
|
|
|
permission := &models.Permission{
|
|
Name: "test_permission",
|
|
Description: "Test permission",
|
|
Resource: "tracks",
|
|
Action: "read",
|
|
}
|
|
err = db.Create(permission).Error
|
|
require.NoError(t, err)
|
|
|
|
rolePermission := &models.RolePermission{
|
|
RoleID: role.ID,
|
|
PermissionID: permission.ID,
|
|
}
|
|
err = db.Create(rolePermission).Error
|
|
require.NoError(t, err)
|
|
|
|
roles, err := service.GetRoles(ctx)
|
|
assert.NoError(t, err)
|
|
assert.Len(t, roles, 1)
|
|
assert.Len(t, roles[0].Permissions, 1)
|
|
assert.Equal(t, "test_permission", roles[0].Permissions[0].Name)
|
|
}
|
|
|
|
func TestRoleService_GetRole_WithPermissions(t *testing.T) {
|
|
service, db, cleanup := setupTestRoleService(t)
|
|
defer cleanup()
|
|
|
|
ctx := context.Background()
|
|
role := &models.Role{
|
|
Name: "test_role",
|
|
Description: "Test role",
|
|
IsSystem: false,
|
|
}
|
|
err := db.Create(role).Error
|
|
require.NoError(t, err)
|
|
|
|
permission := &models.Permission{
|
|
Name: "test_permission",
|
|
Description: "Test permission",
|
|
Resource: "tracks",
|
|
Action: "read",
|
|
}
|
|
err = db.Create(permission).Error
|
|
require.NoError(t, err)
|
|
|
|
rolePermission := &models.RolePermission{
|
|
RoleID: role.ID,
|
|
PermissionID: permission.ID,
|
|
}
|
|
err = db.Create(rolePermission).Error
|
|
require.NoError(t, err)
|
|
|
|
retrievedRole, err := service.GetRole(ctx, role.ID)
|
|
assert.NoError(t, err)
|
|
assert.NotNil(t, retrievedRole)
|
|
assert.Len(t, retrievedRole.Permissions, 1)
|
|
assert.Equal(t, "test_permission", retrievedRole.Permissions[0].Name)
|
|
}
|