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.
		
		
		
		
		
			
		
			
				
					222 lines
				
				4.8 KiB
			
		
		
			
		
	
	
					222 lines
				
				4.8 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								'use strict'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const test = require('tape')
							 | 
						||
| 
								 | 
							
								const buildQueue = require('../').promise
							 | 
						||
| 
								 | 
							
								const { promisify } = require('util')
							 | 
						||
| 
								 | 
							
								const sleep = promisify(setTimeout)
							 | 
						||
| 
								 | 
							
								const immediate = promisify(setImmediate)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								test('concurrency', function (t) {
							 | 
						||
| 
								 | 
							
								  t.plan(2)
							 | 
						||
| 
								 | 
							
								  t.throws(buildQueue.bind(null, worker, 0))
							 | 
						||
| 
								 | 
							
								  t.doesNotThrow(buildQueue.bind(null, worker, 1))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  async function worker (arg) {
							 | 
						||
| 
								 | 
							
								    return true
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								test('worker execution', async function (t) {
							 | 
						||
| 
								 | 
							
								  const queue = buildQueue(worker, 1)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const result = await queue.push(42)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  t.equal(result, true, 'result matches')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  async function worker (arg) {
							 | 
						||
| 
								 | 
							
								    t.equal(arg, 42)
							 | 
						||
| 
								 | 
							
								    return true
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								test('limit', async function (t) {
							 | 
						||
| 
								 | 
							
								  const queue = buildQueue(worker, 1)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const [res1, res2] = await Promise.all([queue.push(10), queue.push(0)])
							 | 
						||
| 
								 | 
							
								  t.equal(res1, 10, 'the result matches')
							 | 
						||
| 
								 | 
							
								  t.equal(res2, 0, 'the result matches')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  async function worker (arg) {
							 | 
						||
| 
								 | 
							
								    await sleep(arg)
							 | 
						||
| 
								 | 
							
								    return arg
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								test('multiple executions', async function (t) {
							 | 
						||
| 
								 | 
							
								  const queue = buildQueue(worker, 1)
							 | 
						||
| 
								 | 
							
								  const toExec = [1, 2, 3, 4, 5]
							 | 
						||
| 
								 | 
							
								  const expected = ['a', 'b', 'c', 'd', 'e']
							 | 
						||
| 
								 | 
							
								  let count = 0
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  await Promise.all(toExec.map(async function (task, i) {
							 | 
						||
| 
								 | 
							
								    const result = await queue.push(task)
							 | 
						||
| 
								 | 
							
								    t.equal(result, expected[i], 'the result matches')
							 | 
						||
| 
								 | 
							
								  }))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  async function worker (arg) {
							 | 
						||
| 
								 | 
							
								    t.equal(arg, toExec[count], 'arg matches')
							 | 
						||
| 
								 | 
							
								    return expected[count++]
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								test('drained', async function (t) {
							 | 
						||
| 
								 | 
							
								  const queue = buildQueue(worker, 2)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const toExec = new Array(10).fill(10)
							 | 
						||
| 
								 | 
							
								  let count = 0
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  async function worker (arg) {
							 | 
						||
| 
								 | 
							
								    await sleep(arg)
							 | 
						||
| 
								 | 
							
								    count++
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  toExec.forEach(function (i) {
							 | 
						||
| 
								 | 
							
								    queue.push(i)
							 | 
						||
| 
								 | 
							
								  })
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  await queue.drained()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  t.equal(count, toExec.length)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  toExec.forEach(function (i) {
							 | 
						||
| 
								 | 
							
								    queue.push(i)
							 | 
						||
| 
								 | 
							
								  })
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  await queue.drained()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  t.equal(count, toExec.length * 2)
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								test('drained with exception should not throw', async function (t) {
							 | 
						||
| 
								 | 
							
								  const queue = buildQueue(worker, 2)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const toExec = new Array(10).fill(10)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  async function worker () {
							 | 
						||
| 
								 | 
							
								    throw new Error('foo')
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  toExec.forEach(function (i) {
							 | 
						||
| 
								 | 
							
								    queue.push(i)
							 | 
						||
| 
								 | 
							
								  })
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  await queue.drained()
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								test('drained with drain function', async function (t) {
							 | 
						||
| 
								 | 
							
								  let drainCalled = false
							 | 
						||
| 
								 | 
							
								  const queue = buildQueue(worker, 2)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  queue.drain = function () {
							 | 
						||
| 
								 | 
							
								    drainCalled = true
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const toExec = new Array(10).fill(10)
							 | 
						||
| 
								 | 
							
								  let count = 0
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  async function worker (arg) {
							 | 
						||
| 
								 | 
							
								    await sleep(arg)
							 | 
						||
| 
								 | 
							
								    count++
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  toExec.forEach(function () {
							 | 
						||
| 
								 | 
							
								    queue.push()
							 | 
						||
| 
								 | 
							
								  })
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  await queue.drained()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  t.equal(count, toExec.length)
							 | 
						||
| 
								 | 
							
								  t.equal(drainCalled, true)
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								test('set this', async function (t) {
							 | 
						||
| 
								 | 
							
								  t.plan(1)
							 | 
						||
| 
								 | 
							
								  const that = {}
							 | 
						||
| 
								 | 
							
								  const queue = buildQueue(that, worker, 1)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  await queue.push(42)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  async function worker (arg) {
							 | 
						||
| 
								 | 
							
								    t.equal(this, that, 'this matches')
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								test('unshift', async function (t) {
							 | 
						||
| 
								 | 
							
								  const queue = buildQueue(worker, 1)
							 | 
						||
| 
								 | 
							
								  const expected = [1, 2, 3, 4]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  await Promise.all([
							 | 
						||
| 
								 | 
							
								    queue.push(1),
							 | 
						||
| 
								 | 
							
								    queue.push(4),
							 | 
						||
| 
								 | 
							
								    queue.unshift(3),
							 | 
						||
| 
								 | 
							
								    queue.unshift(2)
							 | 
						||
| 
								 | 
							
								  ])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  t.is(expected.length, 0)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  async function worker (arg) {
							 | 
						||
| 
								 | 
							
								    t.equal(expected.shift(), arg, 'tasks come in order')
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								test('push with worker throwing error', async function (t) {
							 | 
						||
| 
								 | 
							
								  t.plan(5)
							 | 
						||
| 
								 | 
							
								  const q = buildQueue(async function (task, cb) {
							 | 
						||
| 
								 | 
							
								    throw new Error('test error')
							 | 
						||
| 
								 | 
							
								  }, 1)
							 | 
						||
| 
								 | 
							
								  q.error(function (err, task) {
							 | 
						||
| 
								 | 
							
								    t.ok(err instanceof Error, 'global error handler should catch the error')
							 | 
						||
| 
								 | 
							
								    t.match(err.message, /test error/, 'error message should be "test error"')
							 | 
						||
| 
								 | 
							
								    t.equal(task, 42, 'The task executed should be passed')
							 | 
						||
| 
								 | 
							
								  })
							 | 
						||
| 
								 | 
							
								  try {
							 | 
						||
| 
								 | 
							
								    await q.push(42)
							 | 
						||
| 
								 | 
							
								  } catch (err) {
							 | 
						||
| 
								 | 
							
								    t.ok(err instanceof Error, 'push callback should catch the error')
							 | 
						||
| 
								 | 
							
								    t.match(err.message, /test error/, 'error message should be "test error"')
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								test('unshift with worker throwing error', async function (t) {
							 | 
						||
| 
								 | 
							
								  t.plan(2)
							 | 
						||
| 
								 | 
							
								  const q = buildQueue(async function (task, cb) {
							 | 
						||
| 
								 | 
							
								    throw new Error('test error')
							 | 
						||
| 
								 | 
							
								  }, 1)
							 | 
						||
| 
								 | 
							
								  try {
							 | 
						||
| 
								 | 
							
								    await q.unshift(42)
							 | 
						||
| 
								 | 
							
								  } catch (err) {
							 | 
						||
| 
								 | 
							
								    t.ok(err instanceof Error, 'push callback should catch the error')
							 | 
						||
| 
								 | 
							
								    t.match(err.message, /test error/, 'error message should be "test error"')
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								test('no unhandledRejection (push)', async function (t) {
							 | 
						||
| 
								 | 
							
								  function handleRejection () {
							 | 
						||
| 
								 | 
							
								    t.fail('unhandledRejection')
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  process.once('unhandledRejection', handleRejection)
							 | 
						||
| 
								 | 
							
								  const q = buildQueue(async function (task, cb) {
							 | 
						||
| 
								 | 
							
								    throw new Error('test error')
							 | 
						||
| 
								 | 
							
								  }, 1)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  q.push(42)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  await immediate()
							 | 
						||
| 
								 | 
							
								  process.removeListener('unhandledRejection', handleRejection)
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								test('no unhandledRejection (unshift)', async function (t) {
							 | 
						||
| 
								 | 
							
								  function handleRejection () {
							 | 
						||
| 
								 | 
							
								    t.fail('unhandledRejection')
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  process.once('unhandledRejection', handleRejection)
							 | 
						||
| 
								 | 
							
								  const q = buildQueue(async function (task, cb) {
							 | 
						||
| 
								 | 
							
								    throw new Error('test error')
							 | 
						||
| 
								 | 
							
								  }, 1)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  q.unshift(42)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  await immediate()
							 | 
						||
| 
								 | 
							
								  process.removeListener('unhandledRejection', handleRejection)
							 | 
						||
| 
								 | 
							
								})
							 |