diff --git a/server/src/services/audit.service.spec.ts b/server/src/services/audit.service.spec.ts index 20bbf5c739..c7a51565af 100644 --- a/server/src/services/audit.service.spec.ts +++ b/server/src/services/audit.service.spec.ts @@ -1,6 +1,12 @@ -import { DatabaseAction, EntityType } from 'src/enum'; +import { BadRequestException } from '@nestjs/common'; +import { FileReportItemDto } from 'src/dtos/audit.dto'; +import { AssetFileType, AssetPathType, DatabaseAction, EntityType, PersonPathType, UserPathType } from 'src/enum'; +import { IAssetRepository } from 'src/interfaces/asset.interface'; import { IAuditRepository } from 'src/interfaces/audit.interface'; +import { ICryptoRepository } from 'src/interfaces/crypto.interface'; import { JobStatus } from 'src/interfaces/job.interface'; +import { IPersonRepository } from 'src/interfaces/person.interface'; +import { IUserRepository } from 'src/interfaces/user.interface'; import { AuditService } from 'src/services/audit.service'; import { auditStub } from 'test/fixtures/audit.stub'; import { authStub } from 'test/fixtures/auth.stub'; @@ -10,9 +16,13 @@ import { Mocked } from 'vitest'; describe(AuditService.name, () => { let sut: AuditService; let auditMock: Mocked; + let assetMock: Mocked; + let cryptoMock: Mocked; + let personMock: Mocked; + let userMock: Mocked; beforeEach(() => { - ({ sut, auditMock } = newTestService(AuditService)); + ({ sut, auditMock, assetMock, cryptoMock, personMock, userMock } = newTestService(AuditService)); }); it('should work', () => { @@ -59,4 +69,148 @@ describe(AuditService.name, () => { }); }); }); + + describe('getChecksums', () => { + it('should fail if the file is not in the immich path', async () => { + await expect(sut.getChecksums({ filenames: ['foo/bar'] })).rejects.toBeInstanceOf(BadRequestException); + + expect(cryptoMock.hashFile).not.toHaveBeenCalled(); + }); + + it('should get checksum for valid file', async () => { + await expect(sut.getChecksums({ filenames: ['./upload/my-file.jpg'] })).resolves.toEqual([ + { filename: './upload/my-file.jpg', checksum: expect.any(String) }, + ]); + + expect(cryptoMock.hashFile).toHaveBeenCalledWith('./upload/my-file.jpg'); + }); + }); + + describe('fixItems', () => { + it('should fail if the file is not in the immich path', async () => { + await expect( + sut.fixItems([ + { entityId: 'my-id', pathType: AssetPathType.ORIGINAL, pathValue: 'foo/bar' } as FileReportItemDto, + ]), + ).rejects.toBeInstanceOf(BadRequestException); + + expect(assetMock.update).not.toHaveBeenCalled(); + expect(assetMock.upsertFile).not.toHaveBeenCalled(); + expect(personMock.update).not.toHaveBeenCalled(); + expect(userMock.update).not.toHaveBeenCalled(); + }); + + it('should update encoded video path', async () => { + await sut.fixItems([ + { + entityId: 'my-id', + pathType: AssetPathType.ENCODED_VIDEO, + pathValue: './upload/my-video.mp4', + } as FileReportItemDto, + ]); + + expect(assetMock.update).toHaveBeenCalledWith({ id: 'my-id', encodedVideoPath: './upload/my-video.mp4' }); + expect(assetMock.upsertFile).not.toHaveBeenCalled(); + expect(personMock.update).not.toHaveBeenCalled(); + expect(userMock.update).not.toHaveBeenCalled(); + }); + + it('should update preview path', async () => { + await sut.fixItems([ + { + entityId: 'my-id', + pathType: AssetPathType.PREVIEW, + pathValue: './upload/my-preview.png', + } as FileReportItemDto, + ]); + + expect(assetMock.upsertFile).toHaveBeenCalledWith({ + assetId: 'my-id', + type: AssetFileType.PREVIEW, + path: './upload/my-preview.png', + }); + expect(assetMock.update).not.toHaveBeenCalled(); + expect(personMock.update).not.toHaveBeenCalled(); + expect(userMock.update).not.toHaveBeenCalled(); + }); + + it('should update thumbnail path', async () => { + await sut.fixItems([ + { + entityId: 'my-id', + pathType: AssetPathType.THUMBNAIL, + pathValue: './upload/my-thumbnail.webp', + } as FileReportItemDto, + ]); + + expect(assetMock.upsertFile).toHaveBeenCalledWith({ + assetId: 'my-id', + type: AssetFileType.THUMBNAIL, + path: './upload/my-thumbnail.webp', + }); + expect(assetMock.update).not.toHaveBeenCalled(); + expect(personMock.update).not.toHaveBeenCalled(); + expect(userMock.update).not.toHaveBeenCalled(); + }); + + it('should update original path', async () => { + await sut.fixItems([ + { + entityId: 'my-id', + pathType: AssetPathType.ORIGINAL, + pathValue: './upload/my-original.png', + } as FileReportItemDto, + ]); + + expect(assetMock.update).toHaveBeenCalledWith({ id: 'my-id', originalPath: './upload/my-original.png' }); + expect(assetMock.upsertFile).not.toHaveBeenCalled(); + expect(personMock.update).not.toHaveBeenCalled(); + expect(userMock.update).not.toHaveBeenCalled(); + }); + + it('should update sidecar path', async () => { + await sut.fixItems([ + { + entityId: 'my-id', + pathType: AssetPathType.SIDECAR, + pathValue: './upload/my-sidecar.xmp', + } as FileReportItemDto, + ]); + + expect(assetMock.update).toHaveBeenCalledWith({ id: 'my-id', sidecarPath: './upload/my-sidecar.xmp' }); + expect(assetMock.upsertFile).not.toHaveBeenCalled(); + expect(personMock.update).not.toHaveBeenCalled(); + expect(userMock.update).not.toHaveBeenCalled(); + }); + + it('should update face path', async () => { + await sut.fixItems([ + { + entityId: 'my-id', + pathType: PersonPathType.FACE, + pathValue: './upload/my-face.jpg', + } as FileReportItemDto, + ]); + + expect(personMock.update).toHaveBeenCalledWith({ id: 'my-id', thumbnailPath: './upload/my-face.jpg' }); + expect(assetMock.update).not.toHaveBeenCalled(); + expect(assetMock.upsertFile).not.toHaveBeenCalled(); + expect(userMock.update).not.toHaveBeenCalled(); + }); + + it('should update profile path', async () => { + await sut.fixItems([ + { + entityId: 'my-id', + pathType: UserPathType.PROFILE, + pathValue: './upload/my-profile-pic.jpg', + } as FileReportItemDto, + ]); + + expect(userMock.update).toHaveBeenCalledWith('my-id', { profileImagePath: './upload/my-profile-pic.jpg' }); + expect(assetMock.update).not.toHaveBeenCalled(); + expect(assetMock.upsertFile).not.toHaveBeenCalled(); + expect(personMock.update).not.toHaveBeenCalled(); + }); + }); });