rwadurian/backend/services/backup-service/test/integration/backup-share-repository.int...

253 lines
7.8 KiB
TypeScript

import { Test, TestingModule } from '@nestjs/testing';
import { BackupShareRepositoryImpl } from '../../src/infrastructure/persistence/repositories/backup-share.repository.impl';
import { PrismaService } from '../../src/infrastructure/persistence/prisma/prisma.service';
import { MockPrismaService } from '../utils/mock-prisma.service';
import { BackupShare, BackupShareStatus } from '../../src/domain';
describe('BackupShareRepository Integration', () => {
let repository: BackupShareRepositoryImpl;
let mockPrisma: MockPrismaService;
beforeEach(async () => {
mockPrisma = new MockPrismaService();
const module: TestingModule = await Test.createTestingModule({
providers: [
BackupShareRepositoryImpl,
{ provide: PrismaService, useValue: mockPrisma },
],
}).compile();
repository = module.get<BackupShareRepositoryImpl>(BackupShareRepositoryImpl);
});
afterEach(() => {
mockPrisma.reset();
});
describe('save', () => {
it('should create a new backup share', async () => {
const share = BackupShare.create({
userId: BigInt(12345),
accountSequence: BigInt(1001),
publicKey: '02' + 'a'.repeat(64),
encryptedShareData: 'encrypted-data',
encryptionKeyId: 'key-v1',
});
const saved = await repository.save(share);
expect(saved.shareId).toBeDefined();
expect(saved.userId).toBe(BigInt(12345));
expect(saved.publicKey).toBe('02' + 'a'.repeat(64));
expect(mockPrisma.backupShare.create).toHaveBeenCalled();
});
it('should update an existing backup share', async () => {
// First create
const share = BackupShare.create({
userId: BigInt(12345),
accountSequence: BigInt(1001),
publicKey: '02' + 'a'.repeat(64),
encryptedShareData: 'encrypted-data',
encryptionKeyId: 'key-v1',
});
const saved = await repository.save(share);
// Modify and update
saved.recordAccess();
const updated = await repository.save(saved);
expect(updated.accessCount).toBe(1);
expect(mockPrisma.backupShare.update).toHaveBeenCalled();
});
it('should preserve all fields when saving', async () => {
const share = BackupShare.create({
userId: BigInt(99999),
accountSequence: BigInt(9999),
publicKey: '02' + 'b'.repeat(64),
encryptedShareData: 'test-encrypted-data',
encryptionKeyId: 'key-v2',
threshold: 3,
totalParties: 5,
});
const saved = await repository.save(share);
expect(saved.threshold).toBe(3);
expect(saved.totalParties).toBe(5);
expect(saved.partyIndex).toBe(2);
expect(saved.status).toBe(BackupShareStatus.ACTIVE);
});
});
describe('findByUserId', () => {
it('should find share by user ID', async () => {
const share = BackupShare.create({
userId: BigInt(55555),
accountSequence: BigInt(5555),
publicKey: '02' + 'c'.repeat(64),
encryptedShareData: 'data',
encryptionKeyId: 'key-v1',
});
await repository.save(share);
const found = await repository.findByUserId(BigInt(55555));
expect(found).toBeDefined();
expect(found?.userId).toBe(BigInt(55555));
});
it('should return null for non-existent user', async () => {
const found = await repository.findByUserId(BigInt(99999999));
expect(found).toBeNull();
});
});
describe('findByPublicKey', () => {
it('should find share by public key', async () => {
const publicKey = '02' + 'd'.repeat(64);
const share = BackupShare.create({
userId: BigInt(66666),
accountSequence: BigInt(6666),
publicKey,
encryptedShareData: 'data',
encryptionKeyId: 'key-v1',
});
await repository.save(share);
const found = await repository.findByPublicKey(publicKey);
expect(found).toBeDefined();
expect(found?.publicKey).toBe(publicKey);
});
});
describe('findByUserIdAndPublicKey', () => {
it('should find share by user ID and public key combination', async () => {
const userId = BigInt(77777);
const publicKey = '02' + 'e'.repeat(64);
const share = BackupShare.create({
userId,
accountSequence: BigInt(7777),
publicKey,
encryptedShareData: 'data',
encryptionKeyId: 'key-v1',
});
await repository.save(share);
const found = await repository.findByUserIdAndPublicKey(userId, publicKey);
expect(found).toBeDefined();
expect(found?.userId).toBe(userId);
expect(found?.publicKey).toBe(publicKey);
});
it('should return null when user ID matches but public key does not', async () => {
const share = BackupShare.create({
userId: BigInt(88888),
accountSequence: BigInt(8888),
publicKey: '02' + 'f'.repeat(64),
encryptedShareData: 'data',
encryptionKeyId: 'key-v1',
});
await repository.save(share);
const found = await repository.findByUserIdAndPublicKey(
BigInt(88888),
'02' + 'g'.repeat(64), // Different public key
);
expect(found).toBeNull();
});
});
describe('findByAccountSequence', () => {
it('should find share by account sequence', async () => {
const accountSequence = BigInt(123456);
const share = BackupShare.create({
userId: BigInt(11111),
accountSequence,
publicKey: '02' + 'h'.repeat(64),
encryptedShareData: 'data',
encryptionKeyId: 'key-v1',
});
await repository.save(share);
const found = await repository.findByAccountSequence(accountSequence);
expect(found).toBeDefined();
expect(found?.accountSequence).toBe(accountSequence);
});
});
describe('delete', () => {
it('should delete a backup share', async () => {
const share = BackupShare.create({
userId: BigInt(22222),
accountSequence: BigInt(2222),
publicKey: '02' + 'i'.repeat(64),
encryptedShareData: 'data',
encryptionKeyId: 'key-v1',
});
const saved = await repository.save(share);
await repository.delete(saved.shareId!);
expect(mockPrisma.backupShare.delete).toHaveBeenCalledWith({
where: { shareId: saved.shareId },
});
});
});
describe('entity state transitions', () => {
it('should persist revoked status', async () => {
const share = BackupShare.create({
userId: BigInt(33333),
accountSequence: BigInt(3333),
publicKey: '02' + 'j'.repeat(64),
encryptedShareData: 'data',
encryptionKeyId: 'key-v1',
});
const saved = await repository.save(share);
saved.revoke('SECURITY_BREACH');
await repository.save(saved);
expect(mockPrisma.backupShare.update).toHaveBeenCalledWith(
expect.objectContaining({
data: expect.objectContaining({
status: 'REVOKED',
}),
}),
);
});
it('should persist access count updates', async () => {
const share = BackupShare.create({
userId: BigInt(44444),
accountSequence: BigInt(4444),
publicKey: '02' + 'k'.repeat(64),
encryptedShareData: 'data',
encryptionKeyId: 'key-v1',
});
const saved = await repository.save(share);
saved.recordAccess();
saved.recordAccess();
await repository.save(saved);
expect(mockPrisma.backupShare.update).toHaveBeenCalledWith(
expect.objectContaining({
data: expect.objectContaining({
accessCount: 2,
}),
}),
);
});
});
});