88 lines
2.3 KiB
TypeScript
88 lines
2.3 KiB
TypeScript
import { describe, it } from 'node:test'
|
|
import assert from 'node:assert'
|
|
import { Semaphore } from './semaphore.js'
|
|
|
|
describe('Semaphore', () => {
|
|
it('allows up to maxConcurrency parallel executions', async () => {
|
|
const semaphore = new Semaphore(2)
|
|
let concurrent = 0
|
|
let maxConcurrent = 0
|
|
|
|
const tasks = Array.from({ length: 4 }, () =>
|
|
semaphore.run(async () => {
|
|
concurrent++
|
|
if (concurrent > maxConcurrent) {
|
|
maxConcurrent = concurrent
|
|
}
|
|
await new Promise(resolve => setTimeout(resolve, 10))
|
|
concurrent--
|
|
})
|
|
)
|
|
|
|
await Promise.all(tasks)
|
|
assert.strictEqual(maxConcurrent, 2)
|
|
})
|
|
|
|
it('queues when at maxConcurrency', async () => {
|
|
const semaphore = new Semaphore(1)
|
|
const order: number[] = []
|
|
|
|
const tasks = Array.from({ length: 3 }, (_, i) =>
|
|
semaphore.run(async () => {
|
|
order.push(i)
|
|
await new Promise(resolve => setTimeout(resolve, 10))
|
|
})
|
|
)
|
|
|
|
await Promise.all(tasks)
|
|
assert.deepStrictEqual(order, [0, 1, 2])
|
|
})
|
|
|
|
it('executes queued tasks FIFO', async () => {
|
|
const semaphore = new Semaphore(1)
|
|
const completionOrder: number[] = []
|
|
|
|
const tasks = Array.from({ length: 5 }, (_, i) =>
|
|
semaphore.run(async () => {
|
|
await new Promise(resolve => setTimeout(resolve, 5))
|
|
completionOrder.push(i)
|
|
})
|
|
)
|
|
|
|
await Promise.all(tasks)
|
|
assert.deepStrictEqual(completionOrder, [0, 1, 2, 3, 4])
|
|
})
|
|
|
|
it('propagates errors without leaking slots', async () => {
|
|
const semaphore = new Semaphore(1)
|
|
let subsequentRan = false
|
|
|
|
const errorTask = semaphore.run(async () => {
|
|
throw new Error('intentional error')
|
|
})
|
|
|
|
const normalTask = semaphore.run(async () => {
|
|
subsequentRan = true
|
|
})
|
|
|
|
await assert.rejects(errorTask, /intentional error/)
|
|
await normalTask
|
|
assert.strictEqual(subsequentRan, true)
|
|
})
|
|
|
|
it('handles many tasks', async () => {
|
|
const semaphore = new Semaphore(4)
|
|
const results: number[] = []
|
|
|
|
const tasks = Array.from({ length: 100 }, (_, i) =>
|
|
semaphore.run(async () => {
|
|
results.push(i)
|
|
await new Promise(resolve => setTimeout(resolve, 1))
|
|
})
|
|
)
|
|
|
|
await Promise.all(tasks)
|
|
assert.strictEqual(results.length, 100)
|
|
})
|
|
})
|