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