simple-test.ts 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. import Piscina from '..';
  2. import { test } from 'tap';
  3. import { version } from '../package.json';
  4. import { pathToFileURL } from 'url';
  5. import { resolve } from 'path';
  6. import { EventEmitter } from 'events';
  7. test('Piscina is exposed on export', async ({ equal }) => {
  8. equal(Piscina.version, version);
  9. });
  10. test('Piscina is exposed on itself', async ({ equal }) => {
  11. equal(Piscina.Piscina, Piscina);
  12. });
  13. test('Piscina.isWorkerThread has the correct value', async ({ equal }) => {
  14. equal(Piscina.isWorkerThread, false);
  15. });
  16. test('Piscina.isWorkerThread has the correct value (worker)', async ({ equal }) => {
  17. const worker = new Piscina({
  18. filename: resolve(__dirname, 'fixtures/simple-isworkerthread.ts')
  19. });
  20. const result = await worker.runTask(null);
  21. equal(result, 'done');
  22. });
  23. test('Piscina.isWorkerThread has the correct value (worker) with named import', async ({ equal }) => {
  24. const worker = new Piscina({
  25. filename: resolve(__dirname, 'fixtures/simple-isworkerthread-named-import.ts')
  26. });
  27. const result = await worker.runTask(null);
  28. equal(result, 'done');
  29. });
  30. test('Piscina instance is an EventEmitter', async ({ ok }) => {
  31. const piscina = new Piscina();
  32. ok(piscina instanceof EventEmitter);
  33. });
  34. test('Piscina constructor options are correctly set', async ({ equal }) => {
  35. const piscina = new Piscina({
  36. minThreads: 10,
  37. maxThreads: 20,
  38. maxQueue: 30
  39. });
  40. equal(piscina.options.minThreads, 10);
  41. equal(piscina.options.maxThreads, 20);
  42. equal(piscina.options.maxQueue, 30);
  43. });
  44. test('trivial eval() handler works', async ({ equal }) => {
  45. const worker = new Piscina({
  46. filename: resolve(__dirname, 'fixtures/eval.js')
  47. });
  48. const result = await worker.runTask('42');
  49. equal(result, 42);
  50. });
  51. test('async eval() handler works', async ({ equal }) => {
  52. const worker = new Piscina({
  53. filename: resolve(__dirname, 'fixtures/eval.js')
  54. });
  55. const result = await worker.runTask('Promise.resolve(42)');
  56. equal(result, 42);
  57. });
  58. test('filename can be provided while posting', async ({ equal }) => {
  59. const worker = new Piscina();
  60. const result = await worker.runTask(
  61. 'Promise.resolve(42)',
  62. resolve(__dirname, 'fixtures/eval.js'));
  63. equal(result, 42);
  64. });
  65. test('filename can be null when initially provided', async ({ equal }) => {
  66. const worker = new Piscina({ filename: null });
  67. const result = await worker.runTask(
  68. 'Promise.resolve(42)',
  69. resolve(__dirname, 'fixtures/eval.js'));
  70. equal(result, 42);
  71. });
  72. test('filename must be provided while posting', async ({ rejects }) => {
  73. const worker = new Piscina();
  74. rejects(worker.runTask('doesn’t matter'),
  75. /filename must be provided to run\(\) or in options object/);
  76. });
  77. test('passing env to workers works', async ({ same }) => {
  78. const pool = new Piscina({
  79. filename: resolve(__dirname, 'fixtures/eval.js'),
  80. env: { A: 'foo' }
  81. });
  82. const env = await pool.runTask('({...process.env})');
  83. same(env, { A: 'foo' });
  84. });
  85. test('passing argv to workers works', async ({ same }) => {
  86. const pool = new Piscina({
  87. filename: resolve(__dirname, 'fixtures/eval.js'),
  88. argv: ['a', 'b', 'c']
  89. });
  90. const env = await pool.runTask('process.argv.slice(2)');
  91. same(env, ['a', 'b', 'c']);
  92. });
  93. test('passing execArgv to workers works', async ({ same }) => {
  94. const pool = new Piscina({
  95. filename: resolve(__dirname, 'fixtures/eval.js'),
  96. execArgv: ['--no-warnings']
  97. });
  98. const env = await pool.runTask('process.execArgv');
  99. same(env, ['--no-warnings']);
  100. });
  101. test('passing valid workerData works', async ({ equal }) => {
  102. const pool = new Piscina({
  103. filename: resolve(__dirname, 'fixtures/simple-workerdata.ts'),
  104. workerData: 'ABC'
  105. });
  106. equal(Piscina.workerData, undefined);
  107. await pool.runTask(null);
  108. });
  109. test('passing valid workerData works with named import', async ({ equal }) => {
  110. const pool = new Piscina({
  111. filename: resolve(__dirname, 'fixtures/simple-workerdata-named-import.ts'),
  112. workerData: 'ABC'
  113. });
  114. equal(Piscina.workerData, undefined);
  115. await pool.runTask(null);
  116. });
  117. test('passing invalid workerData does not work', async ({ throws }) => {
  118. throws(() => new Piscina(({
  119. filename: resolve(__dirname, 'fixtures/simple-workerdata.ts'),
  120. workerData: {
  121. hello () {}
  122. }
  123. }) as any), /could not be cloned./);
  124. });
  125. test('filename can be a file:// URL', async ({ equal }) => {
  126. const worker = new Piscina({
  127. filename: pathToFileURL(resolve(__dirname, 'fixtures/eval.js')).href
  128. });
  129. const result = await worker.runTask('42');
  130. equal(result, 42);
  131. });
  132. test('filename can be a file:// URL to an ESM module', {}, async ({ equal }) => {
  133. const worker = new Piscina({
  134. filename: pathToFileURL(resolve(__dirname, 'fixtures/esm-export.mjs')).href
  135. });
  136. const result = await worker.runTask('42');
  137. equal(result, 42);
  138. });
  139. test('duration and utilization calculations work', async ({ equal, ok }) => {
  140. const worker = new Piscina({
  141. filename: resolve(__dirname, 'fixtures/eval.js')
  142. });
  143. // Initial utilization is always 0
  144. equal(worker.utilization, 0);
  145. await Promise.all([
  146. worker.runTask('42'),
  147. worker.runTask('41'),
  148. worker.runTask('40')
  149. ]);
  150. // utilization is going to be some non-deterministic value
  151. // between 0 and 1. It should not be zero at this point
  152. // because tasks have run, but it should also never be 1
  153. ok(worker.utilization > 0);
  154. ok(worker.utilization < 1);
  155. // Duration must be non-zero.
  156. ok(worker.duration > 0);
  157. });
  158. test('run works also', async () => {
  159. const worker = new Piscina({
  160. filename: resolve(__dirname, 'fixtures/eval.js')
  161. });
  162. await worker.run(42);
  163. });
  164. test('named tasks work', async ({ equal }) => {
  165. const worker = new Piscina({
  166. filename: resolve(__dirname, 'fixtures/multiple.js')
  167. });
  168. equal(await worker.run({}, { name: 'a' }), 'a');
  169. equal(await worker.run({}, { name: 'b' }), 'b');
  170. equal(await worker.run({}), 'a');
  171. });
  172. test('named tasks work', async ({ equal }) => {
  173. const worker = new Piscina({
  174. filename: resolve(__dirname, 'fixtures/multiple.js'),
  175. name: 'b'
  176. });
  177. equal(await worker.run({}, { name: 'a' }), 'a');
  178. equal(await worker.run({}, { name: 'b' }), 'b');
  179. equal(await worker.run({}), 'b');
  180. });