feat(downloads): apply bandwidth and schedule policy
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { decideDownloadStart, normalizeDownloadPolicy } from './download-policy';
|
||||
|
||||
describe('download policy integration contract', () => {
|
||||
it('keeps a normalized persisted policy after a config-shaped restart payload', () => {
|
||||
const persisted = JSON.parse(JSON.stringify({
|
||||
download_policy: {
|
||||
throttle: { maxBytesPerSecond: 1_572_864 },
|
||||
windows: [{ start: '22:00', end: '06:00' }, { start: '22:00', end: '06:00' }, { start: 'bad', end: '12:00' }]
|
||||
}
|
||||
}));
|
||||
|
||||
expect(normalizeDownloadPolicy(persisted.download_policy)).toEqual({
|
||||
throttle: { maxBytesPerSecond: 1_572_864 },
|
||||
windows: [{ start: '22:00', end: '06:00' }]
|
||||
});
|
||||
|
||||
const mainSource = readFileSync(join(process.cwd(), 'src', 'main.ts'), 'utf8');
|
||||
expect(mainSource).toContain('download_policy: { throttle: null, windows: [] }');
|
||||
expect(mainSource).toContain('download_policy: normalizeDownloadPolicy(input.download_policy)');
|
||||
});
|
||||
|
||||
it('blocks automatic queue starts outside the local window but allows a manual override', () => {
|
||||
const policy = normalizeDownloadPolicy({
|
||||
throttle: { maxBytesPerSecond: 1_048_576 },
|
||||
windows: [{ start: '22:00', end: '06:00' }]
|
||||
});
|
||||
const now = new Date(2026, 0, 13, 13, 0);
|
||||
|
||||
expect(decideDownloadStart(policy, now)).toMatchObject({
|
||||
allowed: false,
|
||||
reason: 'outside-window',
|
||||
nextStart: new Date(2026, 0, 13, 22, 0)
|
||||
});
|
||||
expect(decideDownloadStart(policy, now, true)).toMatchObject({
|
||||
allowed: true,
|
||||
reason: 'manual-override',
|
||||
maxBytesPerSecond: 1_048_576
|
||||
});
|
||||
|
||||
const mainSource = readFileSync(join(process.cwd(), 'src', 'main.ts'), 'utf8');
|
||||
expect(mainSource).toContain('function scheduleQueueProcessing(manualOverride = false)');
|
||||
expect(mainSource).toContain('scheduleQueueProcessing(manualOverride === true)');
|
||||
expect(mainSource).toContain('scheduleDownloadPolicyWake(decision.nextStart)');
|
||||
});
|
||||
|
||||
it('uses the app-side stdout transform and retains the existing Streamlink argument pipeline', () => {
|
||||
const source = readFileSync(join(process.cwd(), 'src', 'main.ts'), 'utf8');
|
||||
const start = source.indexOf('function downloadVODPart(');
|
||||
const end = source.indexOf('const outputFinished = output.finished', start);
|
||||
const section = source.slice(start, end);
|
||||
|
||||
expect(section).toContain('createTokenBucketTransform');
|
||||
expect(section).toContain("const args = [...streamlinkCmd.prefixArgs, url, getStreamlinkStreamArg(), '--stdout'];");
|
||||
expect(section).not.toMatch(/args\.push\([^\n]*(?:bandwidth|rate-limit|max-rate|throttle)/i);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user