45 lines
2.6 KiB
JavaScript
45 lines
2.6 KiB
JavaScript
'use strict';
|
|
const assert = require('assert/strict');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const os = require('os');
|
|
const crypto = require('crypto');
|
|
const { execFile } = require('child_process');
|
|
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'spine-worker-lifecycle-'));
|
|
const library = path.join(root, 'test.library');
|
|
const source = path.join(library, 'images', 'test.info', 'hero.atlas.txt');
|
|
const marker = path.join(root, 'completed');
|
|
const worker = path.resolve(__dirname, '../js/spine-reconcile-worker.js');
|
|
const thumbnail = path.resolve(__dirname, '../thumbnail/spine.js');
|
|
const key = crypto.createHash('sha256').update(path.dirname(worker) + library).digest('hex');
|
|
const queue = path.join(os.tmpdir(), 'spineviewer-reconcile', key);
|
|
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
|
|
(async () => {
|
|
try {
|
|
fs.mkdirSync(path.dirname(source), { recursive: true }); fs.writeFileSync(source, 'atlas');
|
|
fs.writeFileSync(path.join(library, 'metadata.json'), '{"folders":[]}');
|
|
// Isolate lifecycle behavior from rendering and the user's running Eagle API.
|
|
const preload = path.join(root, 'preload.cjs');
|
|
fs.writeFileSync(preload, `require.cache[${JSON.stringify(thumbnail)}] = { exports: {
|
|
reconcileOnce: async (src, previous) => {
|
|
if (previous !== 'stable') return { signature: 'stable', complete: false };
|
|
require('fs').appendFileSync(${JSON.stringify(marker)}, String(process.pid) + '\\n');
|
|
return { complete: true };
|
|
}
|
|
}};`);
|
|
await new Promise((resolve, reject) => execFile(process.execPath, ['-e', `require(${JSON.stringify(worker)}).enqueue(${JSON.stringify(source)})`],
|
|
{ env: { ...process.env, NODE_OPTIONS: '--require=' + preload } }, error => error ? reject(error) : resolve()));
|
|
assert(!fs.existsSync(marker), 'launcher returns before reconciliation');
|
|
const deadline = Date.now() + 15000;
|
|
while ((!fs.existsSync(marker) || fs.existsSync(path.join(queue, 'worker.lock'))) && Date.now() < deadline) await sleep(100);
|
|
assert(fs.existsSync(marker), 'worker completes after launching process has exited');
|
|
assert(!fs.existsSync(path.join(queue, 'worker.lock')), 'worker releases lock and exits when idle');
|
|
assert.equal(fs.readdirSync(queue).filter(name => name.endsWith('.json')).length, 0);
|
|
console.log('PASS: detached worker survives callback process exit, completes queued work and releases lock');
|
|
} finally {
|
|
if (!fs.existsSync(path.join(queue, 'worker.lock'))) {
|
|
fs.rmSync(root, { recursive: true, force: true }); fs.rmSync(queue, { recursive: true, force: true });
|
|
}
|
|
}
|
|
})().catch(error => { console.error(error); process.exitCode = 1; });
|