test(delete-utils): 新增重試、狀態分流與併發上限測試
涵蓋 isRetryableStatus、deleteWithRetry(成功/暫時性重試/永久性即止/網路例外用盡) 與 runWithConcurrency(順序、併發上限、空陣列)。測試共 75 項全數通過。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
9e88f5a9d5
commit
a0ef76d9d2
@@ -0,0 +1,97 @@
|
||||
import { test } from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
import {
|
||||
isRetryableStatus,
|
||||
deleteWithRetry,
|
||||
runWithConcurrency,
|
||||
} from '../delete-utils.js'
|
||||
|
||||
const noSleep = () => Promise.resolve()
|
||||
|
||||
test('isRetryableStatus 僅對暫時性狀態碼回傳 true', () => {
|
||||
for (const s of [429, 502, 503, 504]) assert.equal(isRetryableStatus(s), true)
|
||||
for (const s of [200, 204, 400, 401, 403, 404, 500]) {
|
||||
assert.equal(isRetryableStatus(s), false)
|
||||
}
|
||||
})
|
||||
|
||||
test('deleteWithRetry 成功(204)時不重試', async () => {
|
||||
let calls = 0
|
||||
const client = {
|
||||
async deleteResource() {
|
||||
calls += 1
|
||||
return 204
|
||||
},
|
||||
}
|
||||
const result = await deleteWithRetry(client, 'u', { sleep: noSleep })
|
||||
assert.equal(result.status, 204)
|
||||
assert.equal(calls, 1)
|
||||
})
|
||||
|
||||
test('deleteWithRetry 對暫時性錯誤重試後成功', async () => {
|
||||
const statuses = [503, 503, 204]
|
||||
let i = 0
|
||||
const client = {
|
||||
async deleteResource() {
|
||||
return statuses[i++]
|
||||
},
|
||||
}
|
||||
const result = await deleteWithRetry(client, 'u', { sleep: noSleep })
|
||||
assert.equal(result.status, 204)
|
||||
assert.equal(result.attempts, 3)
|
||||
})
|
||||
|
||||
test('deleteWithRetry 對永久性錯誤(403)立即停止重試', async () => {
|
||||
let calls = 0
|
||||
const client = {
|
||||
async deleteResource() {
|
||||
calls += 1
|
||||
return 403
|
||||
},
|
||||
}
|
||||
const result = await deleteWithRetry(client, 'u', { sleep: noSleep })
|
||||
assert.equal(result.status, 403)
|
||||
assert.equal(calls, 1)
|
||||
})
|
||||
|
||||
test('deleteWithRetry 對網路例外重試至次數用盡並回傳 error', async () => {
|
||||
let calls = 0
|
||||
const client = {
|
||||
async deleteResource() {
|
||||
calls += 1
|
||||
throw new Error('network down')
|
||||
},
|
||||
}
|
||||
const result = await deleteWithRetry(client, 'u', { attempts: 3, sleep: noSleep })
|
||||
assert.equal(result.status, 0)
|
||||
assert.match(result.error.message, /network down/)
|
||||
assert.equal(calls, 3)
|
||||
})
|
||||
|
||||
test('runWithConcurrency 回傳對應輸入順序的結果', async () => {
|
||||
const items = [1, 2, 3, 4, 5]
|
||||
const out = await runWithConcurrency(items, async (n) => n * 2, 2)
|
||||
assert.deepEqual(out, [2, 4, 6, 8, 10])
|
||||
})
|
||||
|
||||
test('runWithConcurrency 不超過併發上限', async () => {
|
||||
let active = 0
|
||||
let maxActive = 0
|
||||
const items = Array.from({ length: 10 }, (_, i) => i)
|
||||
await runWithConcurrency(
|
||||
items,
|
||||
async () => {
|
||||
active += 1
|
||||
maxActive = Math.max(maxActive, active)
|
||||
await Promise.resolve()
|
||||
active -= 1
|
||||
},
|
||||
3,
|
||||
)
|
||||
assert.ok(maxActive <= 3, `maxActive=${maxActive} 應 <= 3`)
|
||||
})
|
||||
|
||||
test('runWithConcurrency 對空陣列回傳空陣列', async () => {
|
||||
const out = await runWithConcurrency([], async () => 1, 4)
|
||||
assert.deepEqual(out, [])
|
||||
})
|
||||
Reference in New Issue
Block a user