Files
av-tools/tests/unit/ffmpeg-engine-arguments.test.ts

125 lines
3.2 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import {
DEFAULT_JOB_TIMEOUT_MILLISECONDS,
MAX_CONTACT_SHEETS_PER_ENGINE,
MAX_EXECUTIONS_PER_ENGINE,
MULTITHREAD_CODEC_THREAD_LIMIT,
engineJobTimeoutMilliseconds,
prepareEngineArguments,
shouldRecycleExecutionCore,
} from '../../src/ffmpeg/EngineManager';
describe('prepareEngineArguments', () => {
it('leaves single-thread commands unchanged', () => {
const args = ['-i', '/input/source.mp4', '/work/output.mp4'];
expect(
prepareEngineArguments(
args,
'single-thread',
['/input/source.mp4'],
['/work/output.mp4']
)
).toEqual(args);
});
it('bounds multithread input and output codec threads', () => {
expect(
prepareEngineArguments(
['-i', '/input/source.mp4', '-c:v', 'libx264', '/work/output.mp4'],
'multithread',
['/input/source.mp4'],
['/work/output.mp4']
)
).toEqual([
'-threads',
String(MULTITHREAD_CODEC_THREAD_LIMIT),
'-i',
'/input/source.mp4',
'-c:v',
'libx264',
'-threads',
String(MULTITHREAD_CODEC_THREAD_LIMIT),
'/work/output.mp4',
]);
});
it('bounds a generated output pattern in the final output position', () => {
expect(
prepareEngineArguments(
['-i', '/input/source.mp4', '-f', 'segment', '/work/part-%03d.mp4'],
'multithread',
['/input/source.mp4'],
['/work/part-001.mp4', '/work/part-002.mp4']
)
).toEqual([
'-threads',
'2',
'-i',
'/input/source.mp4',
'-f',
'segment',
'-threads',
'2',
'/work/part-%03d.mp4',
]);
});
});
describe('engineJobTimeoutMilliseconds', () => {
it('uses a bounded duration-aware watchdog', () => {
expect(engineJobTimeoutMilliseconds({ expectedDurationSeconds: 2 })).toBe(
120_000
);
expect(
engineJobTimeoutMilliseconds({ expectedDurationSeconds: 10_000 })
).toBe(DEFAULT_JOB_TIMEOUT_MILLISECONDS);
});
it('honors a shorter explicit timeout and caps a longer one', () => {
expect(
engineJobTimeoutMilliseconds({
expectedDurationSeconds: 30,
timeoutMilliseconds: 5_000,
})
).toBe(5_000);
expect(
engineJobTimeoutMilliseconds({
timeoutMilliseconds: DEFAULT_JOB_TIMEOUT_MILLISECONDS * 2,
})
).toBe(DEFAULT_JOB_TIMEOUT_MILLISECONDS);
});
});
describe('execution core recycling policy', () => {
it('refreshes only after the bounded idle-core job budget is exhausted', () => {
expect(shouldRecycleExecutionCore(MAX_EXECUTIONS_PER_ENGINE - 1)).toBe(
false
);
expect(shouldRecycleExecutionCore(MAX_EXECUTIONS_PER_ENGINE)).toBe(true);
});
it('refreshes before a fourth contact sheet hits retained tile-filter state', () => {
expect(
shouldRecycleExecutionCore(
3,
'contact-sheet',
MAX_CONTACT_SHEETS_PER_ENGINE - 1
)
).toBe(false);
expect(
shouldRecycleExecutionCore(
3,
'contact-sheet',
MAX_CONTACT_SHEETS_PER_ENGINE
)
).toBe(true);
expect(
shouldRecycleExecutionCore(
3,
'thumbnail-series',
MAX_CONTACT_SHEETS_PER_ENGINE
)
).toBe(false);
});
});