veza/veza-backend-api/internal/services/role_service_test.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)
}