Files
av-tools/tests/unit/ffmpeg-virtual-fs.test.ts

110 lines
3.3 KiB
TypeScript

import { describe, expect, it, vi } from 'vitest';
import type { FFmpegAdapter } from '../../src/ffmpeg/ffmpeg.types';
import {
describeMountedInputAccess,
mountJobFiles,
} from '../../src/ffmpeg/virtual-fs';
function createFilesystemAdapter(
options: { keepWorkDirectory?: boolean; rejectWorkerFs?: boolean } = {}
) {
const directories = new Set(['/input', '/work']);
const files = new Set<string>();
const adapter = {
createDir: vi.fn(async (path: string) => {
directories.add(path);
}),
mount: vi.fn(async () => {
if (options.rejectWorkerFs) {
throw new Error('WORKERFS unavailable');
}
}),
unmount: vi.fn(async () => undefined),
writeFile: vi.fn(async (path: string) => {
files.add(path);
}),
deleteFile: vi.fn(async (path: string) => {
files.delete(path);
}),
deleteDir: vi.fn(async (path: string) => {
if (options.keepWorkDirectory && path.startsWith('/work/job-')) return;
directories.delete(path);
}),
listDir: vi.fn(async (path: string) =>
[...directories]
.filter(
(entry) =>
entry !== path && entry.slice(0, entry.lastIndexOf('/')) === path
)
.map((entry) => ({
name: entry.split('/').at(-1) ?? '',
isDir: true,
isLink: false,
}))
),
};
return adapter as unknown as FFmpegAdapter;
}
describe('per-job FFmpeg filesystem', () => {
it('uses generated paths and verifies complete cleanup', async () => {
const adapter = createFilesystemAdapter();
const mounted = await mountJobFiles(
adapter,
'../../job with separators',
[new File(['source'], '../../private name.MP4')],
['../unsafe result.mp4']
);
expect(mounted.inputPaths).toEqual([
'/input/job-job-with-separators/source-0.mp4',
]);
expect(mounted.outputPaths).toEqual([
'/work/job-job-with-separators/output-0.mp4',
]);
expect(mounted).toMatchObject({
inputMode: 'workerfs',
inputBytes: 6,
copiedInputBytes: 0,
});
expect(describeMountedInputAccess(mounted)).toContain(
'0 bytes copied into engine memory'
);
expect(mounted.inputPaths[0]).not.toContain('private');
expect(await mounted.cleanup()).toBe(true);
});
it('accounts for and explains the actual memory-copy fallback', async () => {
const adapter = createFilesystemAdapter({ rejectWorkerFs: true });
const mounted = await mountJobFiles(
adapter,
'copy-fallback',
[new File(['1234'], 'one.mp4'), new File(['567'], 'two.mp4')],
['result.mp4']
);
expect(mounted).toMatchObject({
inputMode: 'memory-copy',
inputBytes: 7,
copiedInputBytes: 7,
});
expect(adapter.writeFile).toHaveBeenCalledTimes(2);
expect(describeMountedInputAccess(mounted)).toBe(
'Input compatibility fallback: WORKERFS mounting was unavailable, so 7 bytes were copied into engine memory.'
);
expect(await mounted.cleanup()).toBe(true);
});
it('reports a directory that survives cleanup', async () => {
const adapter = createFilesystemAdapter({ keepWorkDirectory: true });
const mounted = await mountJobFiles(
adapter,
'job',
[new File(['source'], 'source.wav')],
['result.wav']
);
expect(await mounted.cleanup()).toBe(false);
});
});