66 lines
2.8 KiB
TypeScript
66 lines
2.8 KiB
TypeScript
import { RoleSyncService } from '../src/modules/auth/role-sync.service';
|
|
|
|
describe('RoleSyncService', () => {
|
|
const mockPrisma: any = {};
|
|
const mockPermissionCache: any = { invalidate: jest.fn() };
|
|
const mockEvents: any = { publish: jest.fn() };
|
|
const mockGroupHash: any = { compute: (g: any) => require('crypto').createHash('sha256').update((g||[]).slice().sort().join(','), 'utf8').digest('hex') };
|
|
let service: RoleSyncService;
|
|
|
|
beforeEach(() => {
|
|
mockPrisma.user = { findUnique: jest.fn() };
|
|
mockPrisma.authGroupRoleMapping = { findMany: jest.fn() };
|
|
mockPrisma.userRole = { findMany: jest.fn() };
|
|
mockPrisma.auditLog = { create: jest.fn() };
|
|
mockPrisma.user = mockPrisma.user;
|
|
mockPrisma.$transaction = jest.fn(async (cb: any) => {
|
|
// simulate transaction by calling provided callback with tx = mockPrisma
|
|
await cb(mockPrisma);
|
|
});
|
|
|
|
service = new RoleSyncService(mockPrisma as any, mockGroupHash as any, mockPermissionCache as any, mockEvents as any);
|
|
});
|
|
|
|
test('computeGroupHash consistent and order independent', () => {
|
|
const a = ['b', 'a', 'c'];
|
|
const h1 = service.computeGroupHash(a);
|
|
const h2 = service.computeGroupHash(['a', 'b', 'c']);
|
|
expect(h1).toBe(h2);
|
|
});
|
|
|
|
test('skips sync when group hash unchanged', async () => {
|
|
const groups = ['RL-Owner'];
|
|
const hash = service.computeGroupHash(groups);
|
|
mockPrisma.user.findUnique.mockResolvedValue({ id: 'uid', lastGroupHash: hash });
|
|
|
|
const res = await service.syncUserRolesFromAuthentik('uid', groups);
|
|
expect(res.skipped).toBe(true);
|
|
expect(mockPrisma.$transaction).not.toHaveBeenCalled();
|
|
});
|
|
|
|
test('performs transaction and writes audit when changed', async () => {
|
|
const groups = ['RL-Owner'];
|
|
mockPrisma.user.findUnique.mockResolvedValue({ id: 'uid', lastGroupHash: 'old' });
|
|
mockPrisma.authGroupRoleMapping.findMany.mockResolvedValue([{ roleId: 'r1' }]);
|
|
mockPrisma.userRole.findMany.mockResolvedValue([{ roleId: 'r_old' }]);
|
|
|
|
// spy on tx ops
|
|
mockPrisma.userRole.deleteMany = jest.fn();
|
|
mockPrisma.userRole.createMany = jest.fn();
|
|
mockPrisma.user.update = jest.fn();
|
|
|
|
mockPrisma.auditLog.create = jest.fn();
|
|
|
|
const res = await service.syncUserRolesFromAuthentik('uid', groups);
|
|
|
|
expect(mockPrisma.$transaction).toHaveBeenCalled();
|
|
expect(mockPrisma.userRole.deleteMany).toHaveBeenCalledWith({ where: { userId: 'uid', source: 'AUTHENTIK' } });
|
|
expect(mockPrisma.userRole.createMany).toHaveBeenCalled();
|
|
expect(mockPrisma.user.update).toHaveBeenCalled();
|
|
expect(mockPermissionCache.invalidate).toHaveBeenCalledWith('uid');
|
|
expect(mockEvents.publish).toHaveBeenCalledWith(expect.objectContaining({ type: 'RolesSynchronized' }));
|
|
expect(res.skipped).toBe(false);
|
|
expect(res.assignedRoleIds).toEqual(['r1']);
|
|
});
|
|
});
|