chore: resolve tests

This commit is contained in:
bwees
2026-03-24 23:39:11 -05:00
parent 80db413d69
commit 4c70afc8f4
3 changed files with 21 additions and 29 deletions
@@ -695,7 +695,9 @@ describe(AssetMediaService.name, () => {
describe('playbackVideo', () => { describe('playbackVideo', () => {
it('should require asset.view permissions', async () => { it('should require asset.view permissions', async () => {
await expect(sut.playbackVideo(authStub.admin, 'id')).rejects.toBeInstanceOf(BadRequestException); await expect(sut.playbackVideo(authStub.admin, 'id', { edited: true })).rejects.toBeInstanceOf(
BadRequestException,
);
expect(mocks.access.asset.checkOwnerAccess).toHaveBeenCalledWith(userStub.admin.id, new Set(['id']), undefined); expect(mocks.access.asset.checkOwnerAccess).toHaveBeenCalledWith(userStub.admin.id, new Set(['id']), undefined);
expect(mocks.access.asset.checkAlbumAccess).toHaveBeenCalledWith(userStub.admin.id, new Set(['id'])); expect(mocks.access.asset.checkAlbumAccess).toHaveBeenCalledWith(userStub.admin.id, new Set(['id']));
@@ -706,7 +708,9 @@ describe(AssetMediaService.name, () => {
const asset = AssetFactory.create(); const asset = AssetFactory.create();
mocks.access.asset.checkOwnerAccess.mockResolvedValue(new Set([asset.id])); mocks.access.asset.checkOwnerAccess.mockResolvedValue(new Set([asset.id]));
await expect(sut.playbackVideo(authStub.admin, asset.id)).rejects.toBeInstanceOf(NotFoundException); await expect(sut.playbackVideo(authStub.admin, asset.id, { edited: true })).rejects.toBeInstanceOf(
NotFoundException,
);
}); });
it('should return the encoded video path if available', async () => { it('should return the encoded video path if available', async () => {
@@ -719,7 +723,7 @@ describe(AssetMediaService.name, () => {
encodedVideoPath: asset.files[0].path, encodedVideoPath: asset.files[0].path,
}); });
await expect(sut.playbackVideo(authStub.admin, asset.id)).resolves.toEqual( await expect(sut.playbackVideo(authStub.admin, asset.id, { edited: true })).resolves.toEqual(
new ImmichFileResponse({ new ImmichFileResponse({
path: '/path/to/encoded/video.mp4', path: '/path/to/encoded/video.mp4',
cacheControl: CacheControl.PrivateWithCache, cacheControl: CacheControl.PrivateWithCache,
@@ -736,7 +740,7 @@ describe(AssetMediaService.name, () => {
encodedVideoPath: null, encodedVideoPath: null,
}); });
await expect(sut.playbackVideo(authStub.admin, asset.id)).resolves.toEqual( await expect(sut.playbackVideo(authStub.admin, asset.id, { edited: true })).resolves.toEqual(
new ImmichFileResponse({ new ImmichFileResponse({
path: asset.originalPath, path: asset.originalPath,
cacheControl: CacheControl.PrivateWithCache, cacheControl: CacheControl.PrivateWithCache,
+13 -21
View File
@@ -221,7 +221,7 @@ describe(MediaService.name, () => {
expect(mocks.assetJob.streamForThumbnailJob).toHaveBeenCalledWith({ force: false, fullsizeEnabled: false }); expect(mocks.assetJob.streamForThumbnailJob).toHaveBeenCalledWith({ force: false, fullsizeEnabled: false });
expect(mocks.job.queueAll).toHaveBeenCalledWith([ expect(mocks.job.queueAll).toHaveBeenCalledWith([
{ {
name: JobName.AssetEditThumbnailGeneration, name: JobName.AssetProcessEdit,
data: { id: asset.id }, data: { id: asset.id },
}, },
]); ]);
@@ -1340,14 +1340,6 @@ describe(MediaService.name, () => {
mocks.media.getImageMetadata.mockResolvedValue({ width: 100, height: 100, isTransparent: false }); mocks.media.getImageMetadata.mockResolvedValue({ width: 100, height: 100, isTransparent: false });
}); });
it('should skip videos', async () => {
const asset = AssetFactory.from({ type: AssetType.Video }).exif().build();
mocks.assetJob.getForGenerateThumbnailJob.mockResolvedValue(getForGenerateThumbnail(asset));
await expect(sut.handleAssetEditProcessing({ id: asset.id })).resolves.toBe(JobStatus.Success);
expect(mocks.media.generateThumbnail).not.toHaveBeenCalled();
});
it('should upsert 3 edited files for edit jobs', async () => { it('should upsert 3 edited files for edit jobs', async () => {
const asset = AssetFactory.from() const asset = AssetFactory.from()
.exif() .exif()
@@ -1359,7 +1351,7 @@ describe(MediaService.name, () => {
]) ])
.build(); .build();
mocks.assetJob.getForGenerateThumbnailJob.mockResolvedValue(getForGenerateThumbnail(asset)); mocks.assetJob.getForAssetEditProcessing.mockResolvedValue(getForGenerateThumbnail(asset));
const thumbhashBuffer = Buffer.from('a thumbhash', 'utf8'); const thumbhashBuffer = Buffer.from('a thumbhash', 'utf8');
mocks.media.generateThumbhash.mockResolvedValue(thumbhashBuffer); mocks.media.generateThumbhash.mockResolvedValue(thumbhashBuffer);
mocks.person.getFaces.mockResolvedValue([]); mocks.person.getFaces.mockResolvedValue([]);
@@ -1381,7 +1373,7 @@ describe(MediaService.name, () => {
.exif() .exif()
.edit({ action: AssetEditAction.Crop, parameters: { height: 1152, width: 1512, x: 216, y: 1512 } }) .edit({ action: AssetEditAction.Crop, parameters: { height: 1152, width: 1512, x: 216, y: 1512 } })
.build(); .build();
mocks.assetJob.getForGenerateThumbnailJob.mockResolvedValue(getForGenerateThumbnail(asset)); mocks.assetJob.getForAssetEditProcessing.mockResolvedValue(getForGenerateThumbnail(asset));
mocks.person.getFaces.mockResolvedValue([]); mocks.person.getFaces.mockResolvedValue([]);
mocks.ocr.getByAssetId.mockResolvedValue([]); mocks.ocr.getByAssetId.mockResolvedValue([]);
@@ -1409,7 +1401,7 @@ describe(MediaService.name, () => {
{ type: AssetFileType.FullSize, path: 'edited3.jpg', isEdited: true }, { type: AssetFileType.FullSize, path: 'edited3.jpg', isEdited: true },
]) ])
.build(); .build();
mocks.assetJob.getForGenerateThumbnailJob.mockResolvedValue(getForGenerateThumbnail(asset)); mocks.assetJob.getForAssetEditProcessing.mockResolvedValue(getForGenerateThumbnail(asset));
const status = await sut.handleAssetEditProcessing({ id: asset.id }); const status = await sut.handleAssetEditProcessing({ id: asset.id });
@@ -1427,7 +1419,7 @@ describe(MediaService.name, () => {
it('should generate all 3 edited files if an asset has edits', async () => { it('should generate all 3 edited files if an asset has edits', async () => {
const asset = AssetFactory.from().exif().edit().build(); const asset = AssetFactory.from().exif().edit().build();
mocks.assetJob.getForGenerateThumbnailJob.mockResolvedValue(getForGenerateThumbnail(asset)); mocks.assetJob.getForAssetEditProcessing.mockResolvedValue(getForGenerateThumbnail(asset));
mocks.person.getFaces.mockResolvedValue([]); mocks.person.getFaces.mockResolvedValue([]);
mocks.ocr.getByAssetId.mockResolvedValue([]); mocks.ocr.getByAssetId.mockResolvedValue([]);
@@ -1453,7 +1445,7 @@ describe(MediaService.name, () => {
it('should generate the original thumbhash if no edits exist', async () => { it('should generate the original thumbhash if no edits exist', async () => {
const asset = AssetFactory.from().exif().build(); const asset = AssetFactory.from().exif().build();
mocks.assetJob.getForGenerateThumbnailJob.mockResolvedValue(getForGenerateThumbnail(asset)); mocks.assetJob.getForAssetEditProcessing.mockResolvedValue(getForGenerateThumbnail(asset));
mocks.media.generateThumbhash.mockResolvedValue(factory.buffer()); mocks.media.generateThumbhash.mockResolvedValue(factory.buffer());
await sut.handleAssetEditProcessing({ id: asset.id, source: 'upload' }); await sut.handleAssetEditProcessing({ id: asset.id, source: 'upload' });
@@ -1463,7 +1455,7 @@ describe(MediaService.name, () => {
it('should apply thumbhash if job source is edit and edits exist', async () => { it('should apply thumbhash if job source is edit and edits exist', async () => {
const asset = AssetFactory.from().exif().edit().build(); const asset = AssetFactory.from().exif().edit().build();
mocks.assetJob.getForGenerateThumbnailJob.mockResolvedValue(getForGenerateThumbnail(asset)); mocks.assetJob.getForAssetEditProcessing.mockResolvedValue(getForGenerateThumbnail(asset));
const thumbhashBuffer = factory.buffer(); const thumbhashBuffer = factory.buffer();
mocks.media.generateThumbhash.mockResolvedValue(thumbhashBuffer); mocks.media.generateThumbhash.mockResolvedValue(thumbhashBuffer);
mocks.person.getFaces.mockResolvedValue([]); mocks.person.getFaces.mockResolvedValue([]);
@@ -1974,7 +1966,7 @@ describe(MediaService.name, () => {
mocks.media.probe.mockResolvedValue(probeStub.noAudioStreams); mocks.media.probe.mockResolvedValue(probeStub.noAudioStreams);
mocks.systemMetadata.get.mockResolvedValue({ ffmpeg: { transcode: 'foo' } } as never as SystemConfig); mocks.systemMetadata.get.mockResolvedValue({ ffmpeg: { transcode: 'foo' } } as never as SystemConfig);
await expect(sut.handleVideoConversion({ id: 'video-id' })).rejects.toThrowError(); await expect(sut.handleVideoConversion({ id: 'video-id' })).resolves.toBe(JobStatus.Failed);
expect(mocks.media.transcode).not.toHaveBeenCalled(); expect(mocks.media.transcode).not.toHaveBeenCalled();
}); });
@@ -2228,7 +2220,7 @@ describe(MediaService.name, () => {
mocks.media.probe.mockResolvedValue(probeStub.videoStream2160p); mocks.media.probe.mockResolvedValue(probeStub.videoStream2160p);
mocks.systemMetadata.get.mockResolvedValue({ ffmpeg: { transcode: 'invalid' as any } }); mocks.systemMetadata.get.mockResolvedValue({ ffmpeg: { transcode: 'invalid' as any } });
await expect(sut.handleVideoConversion({ id: 'video-id' })).rejects.toThrowError(); await expect(sut.handleVideoConversion({ id: 'video-id' })).resolves.toBe(JobStatus.Failed);
expect(mocks.media.transcode).not.toHaveBeenCalled(); expect(mocks.media.transcode).not.toHaveBeenCalled();
}); });
@@ -2626,14 +2618,14 @@ describe(MediaService.name, () => {
mocks.systemMetadata.get.mockResolvedValue({ mocks.systemMetadata.get.mockResolvedValue({
ffmpeg: { accel: TranscodeHardwareAcceleration.Nvenc, targetVideoCodec: VideoCodec.Vp9 }, ffmpeg: { accel: TranscodeHardwareAcceleration.Nvenc, targetVideoCodec: VideoCodec.Vp9 },
}); });
await expect(sut.handleVideoConversion({ id: 'video-id' })).rejects.toThrowError(); await expect(sut.handleVideoConversion({ id: 'video-id' })).resolves.toBe(JobStatus.Failed);
expect(mocks.media.transcode).not.toHaveBeenCalled(); expect(mocks.media.transcode).not.toHaveBeenCalled();
}); });
it('should fail if hwaccel option is invalid', async () => { it('should fail if hwaccel option is invalid', async () => {
mocks.media.probe.mockResolvedValue(probeStub.matroskaContainer); mocks.media.probe.mockResolvedValue(probeStub.matroskaContainer);
mocks.systemMetadata.get.mockResolvedValue({ ffmpeg: { accel: 'invalid' as any } }); mocks.systemMetadata.get.mockResolvedValue({ ffmpeg: { accel: 'invalid' as any } });
await expect(sut.handleVideoConversion({ id: 'video-id' })).rejects.toThrowError(); await expect(sut.handleVideoConversion({ id: 'video-id' })).resolves.toBe(JobStatus.Failed);
expect(mocks.media.transcode).not.toHaveBeenCalled(); expect(mocks.media.transcode).not.toHaveBeenCalled();
}); });
@@ -2920,7 +2912,7 @@ describe(MediaService.name, () => {
mocks.media.probe.mockResolvedValue(probeStub.matroskaContainer); mocks.media.probe.mockResolvedValue(probeStub.matroskaContainer);
mocks.systemMetadata.get.mockResolvedValue({ ffmpeg: { accel: TranscodeHardwareAcceleration.Qsv } }); mocks.systemMetadata.get.mockResolvedValue({ ffmpeg: { accel: TranscodeHardwareAcceleration.Qsv } });
await expect(sut.handleVideoConversion({ id: 'video-id' })).rejects.toThrowError(); await expect(sut.handleVideoConversion({ id: 'video-id' })).resolves.toBe(JobStatus.Failed);
expect(mocks.media.transcode).not.toHaveBeenCalled(); expect(mocks.media.transcode).not.toHaveBeenCalled();
}); });
@@ -3330,7 +3322,7 @@ describe(MediaService.name, () => {
sut.videoInterfaces = { dri: [], mali: true }; sut.videoInterfaces = { dri: [], mali: true };
mocks.media.probe.mockResolvedValue(probeStub.matroskaContainer); mocks.media.probe.mockResolvedValue(probeStub.matroskaContainer);
mocks.systemMetadata.get.mockResolvedValue({ ffmpeg: { accel: TranscodeHardwareAcceleration.Vaapi } }); mocks.systemMetadata.get.mockResolvedValue({ ffmpeg: { accel: TranscodeHardwareAcceleration.Vaapi } });
await expect(sut.handleVideoConversion({ id: 'video-id' })).rejects.toThrowError(); await expect(sut.handleVideoConversion({ id: 'video-id' })).resolves.toBe(JobStatus.Failed);
expect(mocks.media.transcode).not.toHaveBeenCalled(); expect(mocks.media.transcode).not.toHaveBeenCalled();
}); });
-4
View File
@@ -803,12 +803,8 @@ export class MediaService extends BaseService {
const { ffmpeg } = await this.getConfig({ withCache: true }); const { ffmpeg } = await this.getConfig({ withCache: true });
const files: UpsertFileOptions[] = []; const files: UpsertFileOptions[] = [];
try { try {
const generated = await this.transcodeVideo(asset, ffmpeg); const generated = await this.transcodeVideo(asset, ffmpeg);
if (!generated) {
return JobStatus.Skipped;
}
if (generated?.file) { if (generated?.file) {
files.push(generated.file); files.push(generated.file);
} }