初始提交:短剧库源码(含转码优化 ultrafast)
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
const assert = require('node:assert/strict');
|
||||
const test = require('node:test');
|
||||
const vm = require('node:vm');
|
||||
const fs = require('node:fs');
|
||||
|
||||
function fixture(request) {
|
||||
let now = 0, number = 0;
|
||||
const timers = new Map(), states = [], expired = [], errors = [];
|
||||
const context = {module: {exports: {}}, AbortController, Promise, Error, setTimeout: (fn, delay) => {const id = ++number; timers.set(id, {fn, at: now + delay}); return id;}, clearTimeout: id => timers.delete(id)};
|
||||
vm.runInNewContext(fs.readFileSync(require.resolve('./player-session.js'), 'utf8'), context);
|
||||
const session = context.module.exports({request, onState: state => states.push(state), onExpired: error => expired.push(error), onError: error => errors.push(error)});
|
||||
const flush = async () => {for (let index = 0; index < 12; index++) await Promise.resolve();};
|
||||
const tick = async amount => {
|
||||
const end = now + amount;
|
||||
await flush();
|
||||
while (true) {
|
||||
const next = Array.from(timers).filter(([, value]) => value.at <= end).sort((a, b) => a[1].at - b[1].at)[0];
|
||||
if (!next) break;
|
||||
now = next[1].at; timers.delete(next[0]); next[1].fn(); await flush();
|
||||
}
|
||||
now = end; await flush();
|
||||
};
|
||||
return {session, states, expired, errors, tick, flush};
|
||||
}
|
||||
|
||||
test('heartbeats renew every 20 seconds and concurrent callers share one request', async () => {
|
||||
const requests = [];
|
||||
let resolve;
|
||||
const f = fixture((id, signal) => {requests.push({id, signal}); return new Promise(done => {resolve = done;});});
|
||||
f.session.start('watch-one');
|
||||
await f.tick(20000);
|
||||
assert.equal(requests.length, 1);
|
||||
const first = f.session.ping(), second = f.session.ping();
|
||||
assert.equal(first, second);
|
||||
resolve({run: 1}); await f.flush();
|
||||
assert.equal(f.states.length, 1);
|
||||
await f.tick(19999); assert.equal(requests.length, 1);
|
||||
await f.tick(1); assert.equal(requests.length, 2);
|
||||
f.session.stop();
|
||||
});
|
||||
|
||||
test('a hung heartbeat times out and retries without blocking future keepalives', async () => {
|
||||
const requests = [];
|
||||
const f = fixture((id, signal) => {requests.push({id, signal}); return requests.length === 1 ? new Promise(() => {}) : Promise.resolve({run: 7});});
|
||||
f.session.start('watch'); f.session.ping();
|
||||
await f.tick(8000);
|
||||
assert.equal(requests[0].signal.aborted, true);
|
||||
await f.tick(5000);
|
||||
assert.equal(requests.length, 2);
|
||||
assert.equal(f.states[0].run, 7);
|
||||
assert.equal(f.expired.length, 0);
|
||||
f.session.stop();
|
||||
});
|
||||
|
||||
test('foreground checks cancel a stuck request and ignore its late expiry response', async () => {
|
||||
let failOld;
|
||||
const requests = [];
|
||||
const f = fixture((id, signal) => {requests.push(signal); return requests.length === 1 ? new Promise((_, reject) => {failOld = reject;}) : Promise.resolve({run: 3});});
|
||||
f.session.start('watch'); f.session.ping(); await f.flush();
|
||||
await f.session.ping(true);
|
||||
assert.equal(requests[0].aborted, true);
|
||||
failOld(Object.assign(new Error('expired'), {status: 410})); await f.flush();
|
||||
assert.equal(f.expired.length, 0);
|
||||
assert.equal(f.states[0].run, 3);
|
||||
f.session.stop();
|
||||
});
|
||||
|
||||
test('expired sessions request one recovery; authentication failures do not trigger recovery loops', async () => {
|
||||
for (const status of [410, 401, 403]) {
|
||||
let requests = 0;
|
||||
const f = fixture(() => {requests++; return Promise.reject(Object.assign(new Error('unavailable'), {status}));});
|
||||
f.session.start('watch'); await f.session.ping(); await f.tick(120000);
|
||||
assert.equal(requests, 1);
|
||||
assert.equal(f.expired.length, status === 410 ? 1 : 0);
|
||||
assert.equal(f.errors.length, status === 410 ? 0 : 1);
|
||||
f.session.stop();
|
||||
}
|
||||
});
|
||||
|
||||
test('closing or changing a drama invalidates late heartbeats from its old session', async () => {
|
||||
let finish;
|
||||
const f = fixture(() => new Promise(resolve => {finish = resolve;}));
|
||||
f.session.start('old'); f.session.ping(); await f.flush();
|
||||
f.session.start('new'); finish({run: 1}); await f.flush();
|
||||
assert.equal(f.states.length, 0);
|
||||
f.session.stop(); await f.tick(120000);
|
||||
assert.equal(f.states.length, 0);
|
||||
});
|
||||
Reference in New Issue
Block a user