immich/server/src/services/audit.service.spec.ts

214 lines
7.1 KiB
TypeScript
Raw Normal View History

import { BadRequestException } from '@nestjs/common';
import { FileReportItemDto } from 'src/dtos/audit.dto';
2025-02-11 17:15:56 -05:00
import {
AssetFileType,
AssetPathType,
DatabaseAction,
EntityType,
JobStatus,
PersonPathType,
UserPathType,
} from 'src/enum';
import { AuditService } from 'src/services/audit.service';
import { auditStub } from 'test/fixtures/audit.stub';
import { authStub } from 'test/fixtures/auth.stub';
2025-02-10 18:47:42 -05:00
import { newTestService, ServiceMocks } from 'test/utils';
describe(AuditService.name, () => {
let sut: AuditService;
2025-02-10 18:47:42 -05:00
let mocks: ServiceMocks;
beforeEach(() => {
2025-02-10 18:47:42 -05:00
({ sut, mocks } = newTestService(AuditService));
});
it('should work', () => {
expect(sut).toBeDefined();
});
describe('handleCleanup', () => {
it('should delete old audit entries', async () => {
await expect(sut.handleCleanup()).resolves.toBe(JobStatus.SUCCESS);
2025-02-10 18:47:42 -05:00
expect(mocks.audit.removeBefore).toHaveBeenCalledWith(expect.any(Date));
});
});
describe('getDeletes', () => {
it('should require full sync if the request is older than 100 days', async () => {
2025-02-10 18:47:42 -05:00
mocks.audit.getAfter.mockResolvedValue([]);
const date = new Date(2022, 0, 1);
await expect(sut.getDeletes(authStub.admin, { after: date, entityType: EntityType.ASSET })).resolves.toEqual({
needsFullSync: true,
ids: [],
});
2025-02-10 18:47:42 -05:00
expect(mocks.audit.getAfter).toHaveBeenCalledWith(date, {
action: DatabaseAction.DELETE,
userIds: [authStub.admin.user.id],
entityType: EntityType.ASSET,
});
});
it('should get any new or updated assets and deleted ids', async () => {
2025-02-10 18:47:42 -05:00
mocks.audit.getAfter.mockResolvedValue([auditStub.delete.entityId]);
const date = new Date();
await expect(sut.getDeletes(authStub.admin, { after: date, entityType: EntityType.ASSET })).resolves.toEqual({
needsFullSync: false,
ids: ['asset-deleted'],
});
2025-02-10 18:47:42 -05:00
expect(mocks.audit.getAfter).toHaveBeenCalledWith(date, {
action: DatabaseAction.DELETE,
userIds: [authStub.admin.user.id],
entityType: EntityType.ASSET,
});
});
});
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);
2025-02-10 18:47:42 -05:00
expect(mocks.crypto.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) },
]);
2025-02-10 18:47:42 -05:00
expect(mocks.crypto.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);
2025-02-10 18:47:42 -05:00
expect(mocks.asset.update).not.toHaveBeenCalled();
expect(mocks.asset.upsertFile).not.toHaveBeenCalled();
expect(mocks.person.update).not.toHaveBeenCalled();
expect(mocks.user.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,
]);
2025-02-10 18:47:42 -05:00
expect(mocks.asset.update).toHaveBeenCalledWith({ id: 'my-id', encodedVideoPath: './upload/my-video.mp4' });
expect(mocks.asset.upsertFile).not.toHaveBeenCalled();
expect(mocks.person.update).not.toHaveBeenCalled();
expect(mocks.user.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,
]);
2025-02-10 18:47:42 -05:00
expect(mocks.asset.upsertFile).toHaveBeenCalledWith({
assetId: 'my-id',
type: AssetFileType.PREVIEW,
path: './upload/my-preview.png',
});
2025-02-10 18:47:42 -05:00
expect(mocks.asset.update).not.toHaveBeenCalled();
expect(mocks.person.update).not.toHaveBeenCalled();
expect(mocks.user.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,
]);
2025-02-10 18:47:42 -05:00
expect(mocks.asset.upsertFile).toHaveBeenCalledWith({
assetId: 'my-id',
type: AssetFileType.THUMBNAIL,
path: './upload/my-thumbnail.webp',
});
2025-02-10 18:47:42 -05:00
expect(mocks.asset.update).not.toHaveBeenCalled();
expect(mocks.person.update).not.toHaveBeenCalled();
expect(mocks.user.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,
]);
2025-02-10 18:47:42 -05:00
expect(mocks.asset.update).toHaveBeenCalledWith({ id: 'my-id', originalPath: './upload/my-original.png' });
expect(mocks.asset.upsertFile).not.toHaveBeenCalled();
expect(mocks.person.update).not.toHaveBeenCalled();
expect(mocks.user.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,
]);
2025-02-10 18:47:42 -05:00
expect(mocks.asset.update).toHaveBeenCalledWith({ id: 'my-id', sidecarPath: './upload/my-sidecar.xmp' });
expect(mocks.asset.upsertFile).not.toHaveBeenCalled();
expect(mocks.person.update).not.toHaveBeenCalled();
expect(mocks.user.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,
]);
2025-02-10 18:47:42 -05:00
expect(mocks.person.update).toHaveBeenCalledWith({ id: 'my-id', thumbnailPath: './upload/my-face.jpg' });
expect(mocks.asset.update).not.toHaveBeenCalled();
expect(mocks.asset.upsertFile).not.toHaveBeenCalled();
expect(mocks.user.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,
]);
2025-02-10 18:47:42 -05:00
expect(mocks.user.update).toHaveBeenCalledWith('my-id', { profileImagePath: './upload/my-profile-pic.jpg' });
expect(mocks.asset.update).not.toHaveBeenCalled();
expect(mocks.asset.upsertFile).not.toHaveBeenCalled();
expect(mocks.person.update).not.toHaveBeenCalled();
});
});
});