Files
release-cleanup/app/test/delete-utils.test.js
T
JefferyandClaude Opus 4.8 a0ef76d9d2 test(delete-utils): 新增重試、狀態分流與併發上限測試
涵蓋 isRetryableStatus、deleteWithRetry(成功/暫時性重試/永久性即止/網路例外用盡)
與 runWithConcurrency(順序、併發上限、空陣列)。測試共 75 項全數通過。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 15:28:40 +08:00

98 lines
2.6 KiB
JavaScript

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, [])
})