import { test } from 'node:test' import assert from 'node:assert/strict' import { createHealthCheckRunner, type HealthProbe } from '../src/shared/health-check-runner.ts' const PROBES: HealthProbe[] = [ { id: 'startup', label: '真实启动', probe: async () => 'listening :18080' }, { id: 'health', label: '健康检查', probe: async () => '{"status":"UP"}' }, { id: 'core-request', label: '核心请求', probe: async () => '200 OK' }, { id: 'external-deps', label: '外部依赖调用', probe: async () => 'mysql/redis/oss ok' }, ] test('test_task_098_task_normal_default_path', async () => { const runner = createHealthCheckRunner({ probes: PROBES }) const result = await runner.runAll() assert.equal(result.ok, true) assert.equal(result.passed.length, 4) assert.deepEqual(result.failed, []) assert.deepEqual( result.passed.map((p) => p.id), ['startup', 'health', 'core-request', 'external-deps'], '按序执行全部探针', ) assert.equal(result.passed[0].output, 'listening :18080') assert.ok(result.passed[0].durationMs >= 0) }) test('test_task_098_task_normal_multiple_items', async () => { const runner = createHealthCheckRunner({ probes: PROBES }) const result = await runner.runAll() // 批量场景:结果不丢失且顺序稳定 assert.equal(result.passed.length, 4) assert.equal(result.passed[3].id, 'external-deps') assert.equal(result.passed[3].output, 'mysql/redis/oss ok') assert.equal(result.totalDurationMs >= 0, true) }) test('test_task_098_task_normal_repeated_operation_is_idempotent', async () => { const runner = createHealthCheckRunner({ probes: PROBES }) const first = await runner.runAll() const second = await runner.runAll() assert.equal(first.ok, second.ok) assert.deepEqual(first.passed.map((p) => p.id), second.passed.map((p) => p.id)) assert.deepEqual(first.failed, second.failed) }) test('test_task_098_task_boundary_empty_input', async () => { const runner = createHealthCheckRunner({ probes: [] }) const result = await runner.runAll() assert.equal(result.ok, true, '无探针视为通过') assert.deepEqual(result.passed, []) assert.deepEqual(result.failed, []) assert.equal(result.totalDurationMs >= 0, true) }) test('test_task_098_task_boundary_single_item', async () => { const runner = createHealthCheckRunner({ probes: [PROBES[0]] }) const result = await runner.runAll() assert.equal(result.ok, true) assert.equal(result.passed.length, 1) assert.equal(result.passed[0].id, 'startup') }) test('test_task_098_task_boundary_limit_and_overflow', async () => { // 探针失败:标记 failed,其余探针继续执行(健康检查全量报告) let failHealth = false const probes = PROBES.map((p) => p.id === 'health' ? { ...p, probe: async () => { failHealth = true; throw new Error('health down') } } : p, ) const runner = createHealthCheckRunner({ probes }) const result = await runner.runAll() assert.equal(result.ok, false) assert.equal(result.failed.length, 1) assert.equal(result.failed[0].id, 'health') assert.ok(result.failed[0].output.includes('health down')) assert.equal(result.passed.length, 3, '失败不中断其余探针') assert.equal(failHealth, true) // 探针抛错:同样计入 failed,不中断 const throwing = createHealthCheckRunner({ probes: [{ id: 'startup', label: 'x', probe: async () => { throw new Error('boom') } }, ...PROBES.slice(1)], }) const thrown = await throwing.runAll() assert.equal(thrown.ok, false) assert.equal(thrown.failed[0].id, 'startup') assert.ok(thrown.failed[0].output.includes('boom')) assert.equal(thrown.passed.length, 3) }) test('test_task_098_task_invalid_input_rejected', async () => { assert.throws(() => createHealthCheckRunner({} as never), /probes 必须是数组/) assert.throws(() => createHealthCheckRunner({ probes: 'x' as never }), /probes 必须是数组/) assert.throws( () => createHealthCheckRunner({ probes: [{ id: '', label: 'x', probe: async () => '' }] }), /probe id 不能为空/, ) assert.throws( () => createHealthCheckRunner({ probes: [{ id: 'a', label: 'x', probe: undefined as never }] }), /probe 必须是函数/, ) assert.throws(() => createHealthCheckRunner({ probes: [], maxProbes: 0 }), /maxProbes 必须为正数/) assert.throws( () => createHealthCheckRunner({ probes: PROBES, timeoutMs: 0 }), /timeoutMs 必须为正数/, ) // probe 返回非字符串:抛错 const bad = createHealthCheckRunner({ probes: [{ id: 'a', label: 'x', probe: async () => 1 as never }] }) await assert.rejects(() => bad.runAll(), /output 必须是字符串/) }) test('test_task_098_task_dependency_failure_releases_resources', async () => { // 外部依赖探针失败:错误可恢复,修复后同一 runner 重跑全绿 let broken = true let attempts = 0 const runner = createHealthCheckRunner({ probes: [ { id: 'startup', label: '启动', probe: async () => 'ok' }, { id: 'external-deps', label: '外部依赖', probe: async () => { attempts += 1 if (broken) throw new Error('mysql connection refused') return 'mysql ok' }, }, ], }) const first = await runner.runAll() assert.equal(first.ok, false) assert.equal(first.failed[0].id, 'external-deps') assert.equal(first.passed.length, 1) assert.ok(first.failed[0].output.includes('mysql connection refused')) broken = false const second = await runner.runAll() assert.equal(second.ok, true) assert.equal(second.passed.length, 2) assert.equal(attempts, 2) })