You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

promise.js 5.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. 'use strict'
  2. const test = require('tape')
  3. const buildQueue = require('../').promise
  4. const { promisify } = require('util')
  5. const sleep = promisify(setTimeout)
  6. const immediate = promisify(setImmediate)
  7. test('concurrency', function (t) {
  8. t.plan(2)
  9. t.throws(buildQueue.bind(null, worker, 0))
  10. t.doesNotThrow(buildQueue.bind(null, worker, 1))
  11. async function worker (arg) {
  12. return true
  13. }
  14. })
  15. test('worker execution', async function (t) {
  16. const queue = buildQueue(worker, 1)
  17. const result = await queue.push(42)
  18. t.equal(result, true, 'result matches')
  19. async function worker (arg) {
  20. t.equal(arg, 42)
  21. return true
  22. }
  23. })
  24. test('limit', async function (t) {
  25. const queue = buildQueue(worker, 1)
  26. const [res1, res2] = await Promise.all([queue.push(10), queue.push(0)])
  27. t.equal(res1, 10, 'the result matches')
  28. t.equal(res2, 0, 'the result matches')
  29. async function worker (arg) {
  30. await sleep(arg)
  31. return arg
  32. }
  33. })
  34. test('multiple executions', async function (t) {
  35. const queue = buildQueue(worker, 1)
  36. const toExec = [1, 2, 3, 4, 5]
  37. const expected = ['a', 'b', 'c', 'd', 'e']
  38. let count = 0
  39. await Promise.all(toExec.map(async function (task, i) {
  40. const result = await queue.push(task)
  41. t.equal(result, expected[i], 'the result matches')
  42. }))
  43. async function worker (arg) {
  44. t.equal(arg, toExec[count], 'arg matches')
  45. return expected[count++]
  46. }
  47. })
  48. test('drained', async function (t) {
  49. const queue = buildQueue(worker, 2)
  50. const toExec = new Array(10).fill(10)
  51. let count = 0
  52. async function worker (arg) {
  53. await sleep(arg)
  54. count++
  55. }
  56. toExec.forEach(function (i) {
  57. queue.push(i)
  58. })
  59. await queue.drained()
  60. t.equal(count, toExec.length)
  61. toExec.forEach(function (i) {
  62. queue.push(i)
  63. })
  64. await queue.drained()
  65. t.equal(count, toExec.length * 2)
  66. })
  67. test('drained with exception should not throw', async function (t) {
  68. const queue = buildQueue(worker, 2)
  69. const toExec = new Array(10).fill(10)
  70. async function worker () {
  71. throw new Error('foo')
  72. }
  73. toExec.forEach(function (i) {
  74. queue.push(i)
  75. })
  76. await queue.drained()
  77. })
  78. test('drained with drain function', async function (t) {
  79. let drainCalled = false
  80. const queue = buildQueue(worker, 2)
  81. queue.drain = function () {
  82. drainCalled = true
  83. }
  84. const toExec = new Array(10).fill(10)
  85. let count = 0
  86. async function worker (arg) {
  87. await sleep(arg)
  88. count++
  89. }
  90. toExec.forEach(function () {
  91. queue.push()
  92. })
  93. await queue.drained()
  94. t.equal(count, toExec.length)
  95. t.equal(drainCalled, true)
  96. })
  97. test('drained while idle should resolve', async function (t) {
  98. const queue = buildQueue(worker, 2)
  99. async function worker (arg) {
  100. await sleep(arg)
  101. }
  102. await queue.drained()
  103. })
  104. test('drained while idle should not call the drain function', async function (t) {
  105. let drainCalled = false
  106. const queue = buildQueue(worker, 2)
  107. queue.drain = function () {
  108. drainCalled = true
  109. }
  110. async function worker (arg) {
  111. await sleep(arg)
  112. }
  113. await queue.drained()
  114. t.equal(drainCalled, false)
  115. })
  116. test('set this', async function (t) {
  117. t.plan(1)
  118. const that = {}
  119. const queue = buildQueue(that, worker, 1)
  120. await queue.push(42)
  121. async function worker (arg) {
  122. t.equal(this, that, 'this matches')
  123. }
  124. })
  125. test('unshift', async function (t) {
  126. const queue = buildQueue(worker, 1)
  127. const expected = [1, 2, 3, 4]
  128. await Promise.all([
  129. queue.push(1),
  130. queue.push(4),
  131. queue.unshift(3),
  132. queue.unshift(2)
  133. ])
  134. t.is(expected.length, 0)
  135. async function worker (arg) {
  136. t.equal(expected.shift(), arg, 'tasks come in order')
  137. }
  138. })
  139. test('push with worker throwing error', async function (t) {
  140. t.plan(5)
  141. const q = buildQueue(async function (task, cb) {
  142. throw new Error('test error')
  143. }, 1)
  144. q.error(function (err, task) {
  145. t.ok(err instanceof Error, 'global error handler should catch the error')
  146. t.match(err.message, /test error/, 'error message should be "test error"')
  147. t.equal(task, 42, 'The task executed should be passed')
  148. })
  149. try {
  150. await q.push(42)
  151. } catch (err) {
  152. t.ok(err instanceof Error, 'push callback should catch the error')
  153. t.match(err.message, /test error/, 'error message should be "test error"')
  154. }
  155. })
  156. test('unshift with worker throwing error', async function (t) {
  157. t.plan(2)
  158. const q = buildQueue(async function (task, cb) {
  159. throw new Error('test error')
  160. }, 1)
  161. try {
  162. await q.unshift(42)
  163. } catch (err) {
  164. t.ok(err instanceof Error, 'push callback should catch the error')
  165. t.match(err.message, /test error/, 'error message should be "test error"')
  166. }
  167. })
  168. test('no unhandledRejection (push)', async function (t) {
  169. function handleRejection () {
  170. t.fail('unhandledRejection')
  171. }
  172. process.once('unhandledRejection', handleRejection)
  173. const q = buildQueue(async function (task, cb) {
  174. throw new Error('test error')
  175. }, 1)
  176. q.push(42)
  177. await immediate()
  178. process.removeListener('unhandledRejection', handleRejection)
  179. })
  180. test('no unhandledRejection (unshift)', async function (t) {
  181. function handleRejection () {
  182. t.fail('unhandledRejection')
  183. }
  184. process.once('unhandledRejection', handleRejection)
  185. const q = buildQueue(async function (task, cb) {
  186. throw new Error('test error')
  187. }, 1)
  188. q.unshift(42)
  189. await immediate()
  190. process.removeListener('unhandledRejection', handleRejection)
  191. })