67 lines
4.2 KiB
JavaScript
67 lines
4.2 KiB
JavaScript
const { test } = require('node:test')
|
|||
|
|
const assert = require('node:assert/strict')
|
||
|
|
const fs = require('node:fs')
|
||
|
|
const os = require('node:os')
|
||
|
|
const path = require('node:path')
|
||
|
|
const { loadClosures, parseClosures, closureFor, annotateClosed, closureKey, closureFile } = require('./wiki_recovery_closures.cjs')
|
||
|
|
|
||
|
|
const tenant = 10059
|
||
|
|
const valid = { dead_letter_id: 10, attempt_number: 7, terminal_status: 'stopped_budget', error_code: 'EXTRACT_FAILED',
|
||
|
|
closed_at: '2026-09-21T12:00:00Z', reason: 'Reviewed terminal extraction failure with no further bounded attempt' }
|
||
|
|
const ledger = closures => ({ tenant_id: tenant, closures })
|
||
|
|
const row = overrides => ({ tenant_id: tenant, dead_letter_id: 10, attempt_number: 7, recovery_status: 'stopped_budget',
|
||
|
|
error_code: 'EXTRACT_FAILED', pending: false, pending_finalize: 0, ...overrides })
|
||
|
|
|
||
|
|
test('a missing ledger file or directory means nothing is closed', () => {
|
||
|
|
assert.equal(loadClosures(null, tenant).size, 0)
|
||
|
|
assert.equal(loadClosures(fs.mkdtempSync(path.join(os.tmpdir(), 'closures-')), tenant).size, 0)
|
||
|
|
assert.equal(annotateClosed([row()], loadClosures(null, tenant), tenant)[0].closed, false)
|
||
|
|
})
|
||
|
|
|
||
|
|
test('the ledger file is read from the recovery directory and parsed strictly', () => {
|
||
|
|
const directory = fs.mkdtempSync(path.join(os.tmpdir(), 'closures-'))
|
||
|
|
fs.writeFileSync(path.join(directory, closureFile), JSON.stringify(ledger([valid])))
|
||
|
|
assert.equal(loadClosures(directory, tenant).size, 1)
|
||
|
|
fs.writeFileSync(path.join(directory, closureFile), JSON.stringify(ledger([{ ...valid, reason: 'short' }])))
|
||
|
|
assert.throws(() => loadClosures(directory, tenant), /written reason/)
|
||
|
|
})
|
||
|
|
|
||
|
|
test('only an exact terminal closure is accepted; every mismatch fails closed', () => {
|
||
|
|
assert.equal(parseClosures(ledger([valid]), tenant).size, 1)
|
||
|
|
for (const [change, pattern] of [
|
||
|
|
[{ tenant_id: 10060 }, /another tenant/],
|
||
|
|
[{ closures: [{ ...valid, terminal_status: 'wiki_recovered' }] }, /Only terminal/],
|
||
|
|
[{ closures: [{ ...valid, terminal_status: 'failed' }] }, /Only terminal/],
|
||
|
|
[{ closures: [{ ...valid, error_code: 'lower_case' }] }, /terminal error code/],
|
||
|
|
[{ closures: [{ ...valid, reason: 'too short' }] }, /written reason/],
|
||
|
|
[{ closures: [{ ...valid, closed_at: 'later' }] }, /timestamp/],
|
||
|
|
[{ closures: [{ ...valid, dead_letter_id: 34 }] }, /1\.\.33/],
|
||
|
|
[{ closures: [{ ...valid, attempt_number: 0 }] }, /attempt number/],
|
||
|
|
[{ closures: [valid, valid] }, /same attempt twice/],
|
||
|
|
[{ closures: 'nope' }, /list closures/],
|
||
|
|
]) assert.throws(() => parseClosures({ ...ledger(change.closures), ...change }, tenant), pattern)
|
||
|
|
})
|
||
|
|
|
||
|
|
test('closure matching rechecks the live row and never excuses pending work', () => {
|
||
|
|
const closures = parseClosures(ledger([valid]), tenant)
|
||
|
|
assert.equal(closureFor(row(), closures, tenant).dead_letter_id, 10)
|
||
|
|
assert.equal(closureFor(row({ attempt_number: 6 }), closures, tenant), null)
|
||
|
|
assert.equal(closureFor(row({ dead_letter_id: 4 }), closures, tenant), null)
|
||
|
|
assert.equal(closureFor(row({ recovery_status: 'failed' }), closures, tenant), null)
|
||
|
|
assert.equal(closureFor(row({ recovery_status: 'running', pending: true }), closures, tenant), null)
|
||
|
|
assert.throws(() => closureFor(row({ recovery_status: 'stopped_invalid' }), closures, tenant), /does not match the recorded terminal status/)
|
||
|
|
assert.throws(() => closureFor(row({ error_code: 'OTHER' }), closures, tenant), /does not match the recorded terminal error/)
|
||
|
|
assert.throws(() => closureFor(row({ pending: true }), closures, tenant), /pending attempt cannot be closed/)
|
||
|
|
assert.throws(() => closureFor(row({ pending_finalize: 1 }), closures, tenant), /pending attempt cannot be closed/)
|
||
|
|
assert.equal(closureKey(tenant, 10, 7), '10059:10:7')
|
||
|
|
})
|
||
|
|
|
||
|
|
test('annotated rows carry the closure decision without changing the recorded status', () => {
|
||
|
|
const closures = parseClosures(ledger([valid]), tenant)
|
||
|
|
const rows = annotateClosed([row(), row({ dead_letter_id: 4, attempt_number: 1, recovery_status: 'failed', error_code: 'EXTRACT_FAILED' })], closures, tenant)
|
||
|
|
assert.equal(rows[0].closed, true)
|
||
|
|
assert.equal(rows[0].recovery_status, 'stopped_budget')
|
||
|
|
assert.equal(rows[1].closed, false)
|
||
|
|
assert.equal(rows[1].recovery_status, 'failed')
|
||
|
|
})
|