import Piscina from '..'; import { test } from 'tap'; import { version } from '../package.json'; import { pathToFileURL } from 'url'; import { resolve } from 'path'; import { EventEmitter } from 'events'; test('Piscina is exposed on export', async ({ equal }) => { equal(Piscina.version, version); }); test('Piscina is exposed on itself', async ({ equal }) => { equal(Piscina.Piscina, Piscina); }); test('Piscina.isWorkerThread has the correct value', async ({ equal }) => { equal(Piscina.isWorkerThread, false); }); test('Piscina.isWorkerThread has the correct value (worker)', async ({ equal }) => { const worker = new Piscina({ filename: resolve(__dirname, 'fixtures/simple-isworkerthread.ts') }); const result = await worker.runTask(null); equal(result, 'done'); }); test('Piscina instance is an EventEmitter', async ({ ok }) => { const piscina = new Piscina(); ok(piscina instanceof EventEmitter); }); test('Piscina constructor options are correctly set', async ({ equal }) => { const piscina = new Piscina({ minThreads: 10, maxThreads: 20, maxQueue: 30 }); equal(piscina.options.minThreads, 10); equal(piscina.options.maxThreads, 20); equal(piscina.options.maxQueue, 30); }); test('trivial eval() handler works', async ({ equal }) => { const worker = new Piscina({ filename: resolve(__dirname, 'fixtures/eval.js') }); const result = await worker.runTask('42'); equal(result, 42); }); test('async eval() handler works', async ({ equal }) => { const worker = new Piscina({ filename: resolve(__dirname, 'fixtures/eval.js') }); const result = await worker.runTask('Promise.resolve(42)'); equal(result, 42); }); test('filename can be provided while posting', async ({ equal }) => { const worker = new Piscina(); const result = await worker.runTask( 'Promise.resolve(42)', resolve(__dirname, 'fixtures/eval.js')); equal(result, 42); }); test('filename can be null when initially provided', async ({ equal }) => { const worker = new Piscina({ filename: null }); const result = await worker.runTask( 'Promise.resolve(42)', resolve(__dirname, 'fixtures/eval.js')); equal(result, 42); }); test('filename must be provided while posting', async ({ rejects }) => { const worker = new Piscina(); rejects(worker.runTask('doesn’t matter'), /filename must be provided to run\(\) or in options object/); }); test('passing env to workers works', async ({ same }) => { const pool = new Piscina({ filename: resolve(__dirname, 'fixtures/eval.js'), env: { A: 'foo' } }); const env = await pool.runTask('({...process.env})'); same(env, { A: 'foo' }); }); test('passing argv to workers works', async ({ same }) => { const pool = new Piscina({ filename: resolve(__dirname, 'fixtures/eval.js'), argv: ['a', 'b', 'c'] }); const env = await pool.runTask('process.argv.slice(2)'); same(env, ['a', 'b', 'c']); }); test('passing execArgv to workers works', async ({ same }) => { const pool = new Piscina({ filename: resolve(__dirname, 'fixtures/eval.js'), execArgv: ['--no-warnings'] }); const env = await pool.runTask('process.execArgv'); same(env, ['--no-warnings']); }); test('passing valid workerData works', async ({ equal }) => { const pool = new Piscina({ filename: resolve(__dirname, 'fixtures/simple-workerdata.ts'), workerData: 'ABC' }); equal(Piscina.workerData, undefined); await pool.runTask(null); }); test('passing invalid workerData does not work', async ({ throws }) => { throws(() => new Piscina(({ filename: resolve(__dirname, 'fixtures/simple-workerdata.ts'), workerData: process.env }) as any), /Cannot transfer object of unsupported type./); }); test('filename can be a file:// URL', async ({ equal }) => { const worker = new Piscina({ filename: pathToFileURL(resolve(__dirname, 'fixtures/eval.js')).href }); const result = await worker.runTask('42'); equal(result, 42); }); test('filename can be a file:// URL to an ESM module', {}, async ({ equal }) => { const worker = new Piscina({ filename: pathToFileURL(resolve(__dirname, 'fixtures/esm-export.mjs')).href }); const result = await worker.runTask('42'); equal(result, 42); }); test('duration and utilization calculations work', async ({ equal, ok }) => { const worker = new Piscina({ filename: resolve(__dirname, 'fixtures/eval.js') }); // Initial utilization is always 0 equal(worker.utilization, 0); await Promise.all([ worker.runTask('42'), worker.runTask('41'), worker.runTask('40') ]); // utilization is going to be some non-deterministic value // between 0 and 1. It should not be zero at this point // because tasks have run, but it should also never be 1 ok(worker.utilization > 0); ok(worker.utilization < 1); // Duration must be non-zero. ok(worker.duration > 0); }); test('run works also', async () => { const worker = new Piscina({ filename: resolve(__dirname, 'fixtures/eval.js') }); await worker.run(42); }); test('named tasks work', async ({ equal }) => { const worker = new Piscina({ filename: resolve(__dirname, 'fixtures/multiple.js') }); equal(await worker.run({}, { name: 'a' }), 'a'); equal(await worker.run({}, { name: 'b' }), 'b'); equal(await worker.run({}), 'a'); }); test('named tasks work', async ({ equal }) => { const worker = new Piscina({ filename: resolve(__dirname, 'fixtures/multiple.js'), name: 'b' }); equal(await worker.run({}, { name: 'a' }), 'a'); equal(await worker.run({}, { name: 'b' }), 'b'); equal(await worker.run({}), 'b'); });