UNPKG

5.49 kBJavaScriptView Raw
1/* vim: set ts=8 sts=8 sw=8 noet: */
2
3var mod_tap = require('tap');
4var mod_vasync = require('..');
5
6function
7immediate_worker(task, next)
8{
9 setImmediate(function () {
10 next();
11 });
12}
13
14function
15sametick_worker(task, next)
16{
17 next();
18}
19
20function
21random_delay_worker(task, next)
22{
23 setTimeout(function () {
24 next();
25 }, Math.floor(Math.random() * 250));
26}
27
28mod_tap.test('must not push after close', function (test) {
29 test.plan(3);
30
31 var q = mod_vasync.queuev({
32 worker: immediate_worker,
33 concurrency: 10
34 });
35 test.ok(q);
36
37 test.doesNotThrow(function () {
38 q.push({});
39 }, 'push should not throw _before_ close()');
40
41 q.close();
42
43 /*
44 * If we attempt to add tasks to the queue _after_ calling close(),
45 * we should get an exception:
46 */
47 test.throws(function () {
48 q.push({});
49 }, 'push should throw _after_ close()');
50
51 test.end();
52});
53
54mod_tap.test('get \'end\' event with close()', function (test) {
55 var task_count = 45;
56 var tasks_finished = 0;
57 var seen_end = false;
58 var seen_drain = false;
59
60 test.plan(14 + task_count);
61
62 var q = mod_vasync.queuev({
63 worker: random_delay_worker,
64 concurrency: 5
65 });
66 test.ok(q);
67
68 /*
69 * Enqueue a bunch of tasks; more than our concurrency:
70 */
71 for (var i = 0; i < 45; i++) {
72 q.push({}, function () {
73 tasks_finished++;
74 test.ok(true);
75 });
76 }
77
78 /*
79 * Close the queue to signify that we're done now.
80 */
81 test.equal(q.ended, false);
82 test.equal(q.closed, false);
83 q.close();
84 test.equal(q.closed, true);
85 test.equal(q.ended, false);
86
87 q.on('drain', function () {
88 /*
89 * 'drain' should fire before 'end':
90 */
91 test.notOk(seen_drain);
92 test.notOk(seen_end);
93 seen_drain = true;
94 });
95 q.on('end', function () {
96 /*
97 * 'end' should fire after 'drain':
98 */
99 test.ok(seen_drain);
100 test.notOk(seen_end);
101 seen_end = true;
102
103 /*
104 * Check the public state:
105 */
106 test.equal(q.closed, true);
107 test.equal(q.ended, true);
108
109 /*
110 * We should have fired the callbacks for _all_ enqueued
111 * tasks by now:
112 */
113 test.equal(task_count, tasks_finished);
114 test.end();
115 });
116
117 /*
118 * Check that we see neither the 'drain', nor the 'end' event before
119 * the end of this tick:
120 */
121 test.notOk(seen_drain);
122 test.notOk(seen_end);
123});
124
125mod_tap.test('get \'end\' event with close() and no tasks', function (test) {
126 var seen_drain = false;
127 var seen_end = false;
128
129 test.plan(10);
130
131 var q = mod_vasync.queuev({
132 worker: immediate_worker,
133 concurrency: 10
134 });
135
136 setImmediate(function () {
137 test.notOk(seen_end);
138 });
139
140 test.equal(q.ended, false);
141 test.equal(q.closed, false);
142 q.close();
143 test.equal(q.closed, true);
144 test.equal(q.ended, false);
145 test.notOk(seen_end);
146
147 q.on('drain', function () {
148 seen_drain = true;
149 });
150 q.on('end', function () {
151 /*
152 * We do not expect to see a 'drain' event, as there were no
153 * tasks pushed onto the queue before we closed it.
154 */
155 test.notOk(seen_drain);
156 test.notOk(seen_end);
157 test.equal(q.closed, true);
158 test.equal(q.ended, true);
159 seen_end = true;
160 test.end();
161 });
162});
163
164/*
165 * We want to ensure that both the 'drain' event and the q.drain() hook are
166 * called the same number of times:
167 */
168mod_tap.test('equivalence of on(\'drain\') and q.drain()', function (test) {
169 var enqcount = 4;
170 var drains = 4;
171 var ee_count = 0;
172 var fn_count = 0;
173
174 test.plan(enqcount + drains + 3);
175
176 var q = mod_vasync.queuev({
177 worker: immediate_worker,
178 concurrency: 10
179 });
180
181 var enq = function () {
182 if (--enqcount < 0)
183 return;
184
185 q.push({}, function () {
186 test.ok(true, 'task completion');
187 });
188 };
189
190 var draino = function () {
191 test.ok(true, 'drain called');
192 if (--drains === 0) {
193 test.equal(q.closed, false, 'not closed');
194 test.equal(q.ended, false, 'not ended');
195 test.equal(fn_count, ee_count, 'same number of calls');
196 test.end();
197 }
198 };
199
200 enq();
201 enq();
202
203 q.on('drain', function () {
204 ee_count++;
205 enq();
206 draino();
207 });
208 q.drain = function () {
209 fn_count++;
210 enq();
211 draino();
212 };
213});
214
215/*
216 * In the past, we've only handed on the _first_ argument to the task completion
217 * callback. Make sure we hand on _all_ of the arguments now:
218 */
219mod_tap.test('ensure all arguments passed to push() callback', function (test) {
220 test.plan(13);
221
222 var q = mod_vasync.queuev({
223 worker: function (task, callback) {
224 if (task.fail) {
225 callback(new Error('guru meditation'));
226 return;
227 }
228 callback(null, 1, 2, 3, 5, 8);
229 },
230 concurrency: 1
231 });
232
233 q.push({ fail: true }, function (err, a, b, c, d, e) {
234 test.ok(err, 'got the error');
235 test.equal(err.message, 'guru meditation');
236 test.type(a, 'undefined');
237 test.type(b, 'undefined');
238 test.type(c, 'undefined');
239 test.type(d, 'undefined');
240 test.type(e, 'undefined');
241 });
242
243 q.push({ fail: false }, function (err, a, b, c, d, e) {
244 test.notOk(err, 'got no error');
245 test.equal(a, 1);
246 test.equal(b, 2);
247 test.equal(c, 3);
248 test.equal(d, 5);
249 test.equal(e, 8);
250 });
251
252 q.drain = function () {
253 test.end();
254 };
255});
256
257mod_tap.test('queue kill', function (test) {
258 // Derived from async queue.kill test
259 var count = 0;
260 var q = mod_vasync.queuev({
261 worker: function (task, callback) {
262 setImmediate(function () {
263 test.ok(++count < 2,
264 'Function should be called once');
265 callback();
266 });
267 },
268 concurrency: 1
269 });
270 q.drain = function () {
271 test.ok(false, 'Function should never be called');
272 };
273
274 // Queue twice, the first will exec immediately
275 q.push(0);
276 q.push(0);
277
278 q.kill();
279
280 q.on('end', function () {
281 test.ok(q.killed);
282 test.end();
283 });
284});