'use strict'; const test = require('node:test'); const assert = require('node:assert'); const { TargetLeaseTable, DEFAULT_TTL_MS } = require('../src/core/targetLease'); test('tryAcquire:先抢到的机器人独占,其他机器人拿不到', () => { const table = new TargetLeaseTable(); const chunk = { x: 10, z: 20 }; assert.strictEqual(table.tryAcquire(chunk, 'A'), true); assert.strictEqual(table.tryAcquire(chunk, 'B'), false, '被别人占用时应失败'); assert.strictEqual(table.isLeasedByOther(chunk, 'B'), true); assert.strictEqual(table.isLeasedByOther(chunk, 'A'), false, '自己占用不算「被别人占用」'); }); test('tryAcquire:同一机器人可重复占用(视为续租)', () => { const table = new TargetLeaseTable({ ttlMs: 1000 }); const chunk = { x: 1, z: 1 }; assert.strictEqual(table.tryAcquire(chunk, 'A'), true); assert.strictEqual(table.tryAcquire(chunk, 'A'), true, '自己再抢一次不应失败'); assert.strictEqual(table.size, 1, '不应产生第二条记录'); }); test('租约到期后自动失效,其他机器人可接手(不会永久锁死区块)', async () => { const table = new TargetLeaseTable({ ttlMs: 30 }); const chunk = { x: 5, z: 5 }; assert.strictEqual(table.tryAcquire(chunk, 'A'), true); assert.strictEqual(table.tryAcquire(chunk, 'B'), false); await new Promise((resolve) => setTimeout(resolve, 45)); assert.strictEqual(table.isLeasedByOther(chunk, 'B'), false, '过期后应视为空闲'); assert.strictEqual(table.tryAcquire(chunk, 'B'), true, '过期后其他机器人可接手'); }); test('release:只有持有者能释放,释放后别人立刻可用', () => { const table = new TargetLeaseTable(); const chunk = { x: 2, z: 3 }; table.tryAcquire(chunk, 'A'); assert.strictEqual(table.release(chunk, 'B'), false, '非持有者不能释放'); assert.strictEqual(table.tryAcquire(chunk, 'B'), false); assert.strictEqual(table.release(chunk, 'A'), true); assert.strictEqual(table.tryAcquire(chunk, 'B'), true); }); test('releaseAll 释放某机器人的全部占用(停止任务 / 断线时用)', () => { const table = new TargetLeaseTable(); table.tryAcquire({ x: 0, z: 0 }, 'A'); table.tryAcquire({ x: 1, z: 0 }, 'A'); table.tryAcquire({ x: 0, z: 1 }, 'B'); assert.strictEqual(table.releaseAll('A'), 2); assert.strictEqual(table.size, 1, '只应剩下 B 的占用'); assert.strictEqual(table.isLeasedByOther({ x: 0, z: 0 }, 'B'), false); }); test('renew 延长租约,防止长距离寻路中途被抢', async () => { const table = new TargetLeaseTable({ ttlMs: 40 }); const chunk = { x: 7, z: 7 }; table.tryAcquire(chunk, 'A'); await new Promise((resolve) => setTimeout(resolve, 25)); assert.strictEqual(table.renew(chunk, 'A'), true); await new Promise((resolve) => setTimeout(resolve, 25)); // 已超过原始 TTL,但续租过 → 仍是 A 的 assert.strictEqual(table.tryAcquire(chunk, 'B'), false, '续租后不应被抢走'); }); test('renew 对非持有者无效', () => { const table = new TargetLeaseTable(); table.tryAcquire({ x: 9, z: 9 }, 'A'); assert.strictEqual(table.renew({ x: 9, z: 9 }, 'B'), false); }); test('sweep 清理过期租约,snapshot 只列出有效占用', async () => { const table = new TargetLeaseTable({ ttlMs: 20 }); table.tryAcquire({ x: 1, z: 1 }, 'A'); await new Promise((resolve) => setTimeout(resolve, 30)); assert.strictEqual(table.sweep(), 1); assert.deepStrictEqual(table.snapshot(), []); }); test('默认租约时长与配置常量一致', () => { assert.strictEqual(new TargetLeaseTable().ttlMs, DEFAULT_TTL_MS); assert.ok(DEFAULT_TTL_MS >= 60000, '默认不应太短,否则长距离寻路会被抢'); });