oggui/ogWebconsole/src/app/guards/role.guard.spec.ts

205 lines
9.3 KiB
TypeScript

import { TestBed } from '@angular/core/testing';
import { ActivatedRouteSnapshot, CanActivateFn, Router, RouterStateSnapshot } from '@angular/router';
import { roleGuard } from './role.guard';
import { AuthService } from '@services/auth.service';
// ─────────────────────────────────────────────────────────────────────────────
// Helper: ejecuta el guard en el contexto de inyección de Angular
// ─────────────────────────────────────────────────────────────────────────────
function runGuard(allowedRoles: string[], currentRole: string): boolean | any {
const route = { data: { allowedRoles } } as unknown as ActivatedRouteSnapshot;
const state = {} as RouterStateSnapshot;
const execute: CanActivateFn = (...args) =>
TestBed.runInInjectionContext(() => roleGuard(...args));
return execute(route, state);
}
describe('roleGuard — control de acceso por rol', () => {
let mockRouter: jasmine.SpyObj<Router>;
let mockAuth: jasmine.SpyObj<AuthService>;
beforeEach(() => {
mockRouter = jasmine.createSpyObj('Router', ['navigate']);
mockAuth = jasmine.createSpyObj('AuthService', ['getCurrentRole']);
TestBed.configureTestingModule({
providers: [
{ provide: Router, useValue: mockRouter },
{ provide: AuthService, useValue: mockAuth },
],
});
});
// ── Rutas solo para super-admin ────────────────────────────────────────────
describe('rutas solo para super-admin [users, roles, env-vars, import-legacy]', () => {
const onlySuperAdmin = ['super-admin'];
it('super-admin puede acceder', () => {
mockAuth.getCurrentRole.and.returnValue('super-admin');
expect(runGuard(onlySuperAdmin, 'super-admin')).toBeTrue();
});
it('ou-admin NO puede acceder → redirige a /groups', () => {
mockAuth.getCurrentRole.and.returnValue('ou-admin');
expect(runGuard(onlySuperAdmin, 'ou-admin')).toBeFalse();
expect(mockRouter.navigate).toHaveBeenCalledWith(['/groups']);
});
it('ou-operator NO puede acceder', () => {
mockAuth.getCurrentRole.and.returnValue('ou-operator');
expect(runGuard(onlySuperAdmin, 'ou-operator')).toBeFalse();
});
it('ou-minimal NO puede acceder', () => {
mockAuth.getCurrentRole.and.returnValue('ou-minimal');
expect(runGuard(onlySuperAdmin, 'ou-minimal')).toBeFalse();
});
});
// ── Rutas para super-admin + ou-admin ──────────────────────────────────────
describe('rutas para super-admin + ou-admin [commands, pxe, repositorios, etc.]', () => {
const adminRoutes = ['super-admin', 'ou-admin'];
it('super-admin puede acceder', () => {
mockAuth.getCurrentRole.and.returnValue('super-admin');
expect(runGuard(adminRoutes, 'super-admin')).toBeTrue();
});
it('ou-admin puede acceder', () => {
mockAuth.getCurrentRole.and.returnValue('ou-admin');
expect(runGuard(adminRoutes, 'ou-admin')).toBeTrue();
});
it('ou-operator NO puede acceder → redirige a /groups', () => {
mockAuth.getCurrentRole.and.returnValue('ou-operator');
expect(runGuard(adminRoutes, 'ou-operator')).toBeFalse();
expect(mockRouter.navigate).toHaveBeenCalledWith(['/groups']);
});
it('ou-minimal NO puede acceder', () => {
mockAuth.getCurrentRole.and.returnValue('ou-minimal');
expect(runGuard(adminRoutes, 'ou-minimal')).toBeFalse();
});
});
// ── Rutas para super-admin + ou-admin + ou-operator ────────────────────────
describe('rutas para admin + operador [deploy-image, partition-assistant, run-script]', () => {
const operatorRoutes = ['super-admin', 'ou-admin', 'ou-operator'];
it('super-admin puede acceder', () => {
mockAuth.getCurrentRole.and.returnValue('super-admin');
expect(runGuard(operatorRoutes, 'super-admin')).toBeTrue();
});
it('ou-admin puede acceder', () => {
mockAuth.getCurrentRole.and.returnValue('ou-admin');
expect(runGuard(operatorRoutes, 'ou-admin')).toBeTrue();
});
it('ou-operator puede acceder', () => {
mockAuth.getCurrentRole.and.returnValue('ou-operator');
expect(runGuard(operatorRoutes, 'ou-operator')).toBeTrue();
});
it('ou-minimal NO puede acceder → redirige a /groups', () => {
mockAuth.getCurrentRole.and.returnValue('ou-minimal');
expect(runGuard(operatorRoutes, 'ou-minimal')).toBeFalse();
expect(mockRouter.navigate).toHaveBeenCalledWith(['/groups']);
});
});
// ── Verificación de redirección coherente ─────────────────────────────────
describe('redirección al acceder a rutas no permitidas', () => {
it('siempre redirige a /groups cuando el acceso es denegado', () => {
mockAuth.getCurrentRole.and.returnValue('ou-minimal');
runGuard(['super-admin'], 'ou-minimal');
expect(mockRouter.navigate).toHaveBeenCalledWith(['/groups']);
});
it('NO redirige cuando el acceso es permitido', () => {
mockAuth.getCurrentRole.and.returnValue('super-admin');
runGuard(['super-admin'], 'super-admin');
expect(mockRouter.navigate).not.toHaveBeenCalled();
});
});
// ── Matriz completa de rutas de la aplicación ──────────────────────────────
describe('matriz de acceso — todas las rutas protegidas de la aplicación', () => {
interface RouteCase {
path: string;
allowedRoles: string[];
}
const routes: RouteCase[] = [
// solo super-admin
{ path: 'users', allowedRoles: ['super-admin'] },
{ path: 'env-vars', allowedRoles: ['super-admin'] },
{ path: 'roles', allowedRoles: ['super-admin'] },
{ path: 'import-legacy', allowedRoles: ['super-admin'] },
// super-admin + ou-admin
{ path: 'commands', allowedRoles: ['super-admin', 'ou-admin'] },
{ path: 'commands-task', allowedRoles: ['super-admin', 'ou-admin'] },
{ path: 'pxe-images', allowedRoles: ['super-admin', 'ou-admin'] },
{ path: 'pxe', allowedRoles: ['super-admin', 'ou-admin'] },
{ path: 'pxe-boot-file', allowedRoles: ['super-admin', 'ou-admin'] },
{ path: 'ogboot-status', allowedRoles: ['super-admin', 'ou-admin'] },
{ path: 'dhcp-servers', allowedRoles: ['super-admin', 'ou-admin'] },
{ path: 'boot-servers', allowedRoles: ['super-admin', 'ou-admin'] },
{ path: 'calendars', allowedRoles: ['super-admin', 'ou-admin'] },
{ path: 'repositories', allowedRoles: ['super-admin', 'ou-admin'] },
{ path: 'software', allowedRoles: ['super-admin', 'ou-admin'] },
{ path: 'software-profiles', allowedRoles: ['super-admin', 'ou-admin'] },
{ path: 'operative-systems', allowedRoles: ['super-admin', 'ou-admin'] },
{ path: 'menus', allowedRoles: ['super-admin', 'ou-admin'] },
{ path: 'hardware', allowedRoles: ['super-admin', 'ou-admin'] },
{ path: 'hardware-profiles', allowedRoles: ['super-admin', 'ou-admin'] },
{ path: 'hardware-types', allowedRoles: ['super-admin', 'ou-admin'] },
// super-admin + ou-admin + ou-operator
{ path: 'commands-logs', allowedRoles: ['super-admin', 'ou-admin', 'ou-operator'] },
{ path: 'clients/deploy-image', allowedRoles: ['super-admin', 'ou-admin', 'ou-operator'] },
{ path: 'clients/partition-assistant',allowedRoles: ['super-admin', 'ou-admin', 'ou-operator'] },
{ path: 'clients/run-script', allowedRoles: ['super-admin', 'ou-admin', 'ou-operator'] },
];
const rolesTested: Array<{ role: string; canAccess: (r: RouteCase) => boolean }> = [
{
role: 'super-admin',
canAccess: () => true, // puede acceder a todo
},
{
role: 'ou-admin',
canAccess: r => r.allowedRoles.includes('ou-admin'),
},
{
role: 'ou-operator',
canAccess: r => r.allowedRoles.includes('ou-operator'),
},
{
role: 'ou-minimal',
canAccess: () => false, // no puede acceder a ninguna ruta protegida
},
];
rolesTested.forEach(({ role, canAccess }) => {
routes.forEach(route => {
const shouldAccess = canAccess(route);
const label = shouldAccess
? `${role} PUEDE acceder a /${route.path}`
: `${role} NO PUEDE acceder a /${route.path}`;
it(label, () => {
mockAuth.getCurrentRole.and.returnValue(role);
const result = runGuard(route.allowedRoles, role);
if (shouldAccess) {
expect(result).toBeTrue();
} else {
expect(result).toBeFalse();
expect(mockRouter.navigate).toHaveBeenCalledWith(['/groups']);
}
mockRouter.navigate.calls.reset();
});
});
});
});
});