文档库:目录改为编号制(01-规范/02-架构设计/03-数据库/04-调整方案/
05-交接单/06-ops/07-scripts/08-skills/09-archive),顶层散文件归入 01-规范/;
INDEX.md 与 docs-manifest.json 重刷(档案 146 篇);旧目录名引用全量对齐。
IM 线:src/im/**(SDK / hub / store / presence / ws / gateway-token)、
src/web/routes/im.ts、src/db/plugin-data/**、src/supervisor/plugin-assembly.ts
及对应 test/**。
插件线:poc/{im-agent-bridge,im-connection-gateway,im-conversation-tabs,
business-plugins-im,carbon-mcp-probe}、src/web/routes/{sessions,overlay-device}.ts、
src/net/relay/{device-grant,instance-credential}.ts。
仓库卫生:清出 40 个历史误入库 / 已改名文件(34 个交接单归档 + 6 个旧结构,
本地均有副本);dsh-server-docs/.gitignore 补 tmp/;交接单不入库(政策)。
This commit is contained in:
1 parent
3d8f50e366
commit
e6207aa691
239 files changed
+34477
-14633
No files matched your search
@@ -302,6 +302,106 @@ function register(backend, makeAdapter) {
|
||||
await db.close()
|
||||
}
|
||||
})
|
||||
|
||||
// ── v12 · 设备台账(序㊻ 步骤 6 / S3)────────────────────────────────────────
|
||||
test(`${backend}: upsertOverlayDevice —— 首签 = 1、续签 = +1(同一行)、租约被刷新`, async () => {
|
||||
const db = await makeAdapter()
|
||||
try {
|
||||
await db.createUser(user('u1', 'u1'))
|
||||
const t0 = 1_700_000_000_000
|
||||
const base = { network: 'u:u1', hostId: 'd-u1-abcdef12', userId: 'u1', nodeKey: 'ab'.repeat(32) }
|
||||
|
||||
const first = await db.upsertOverlayDevice({ ...base, leaseExpiresAt: t0 + 1000, at: t0 })
|
||||
assert.equal(first.grantRenewals, 1, '首次插入 = 1')
|
||||
assert.equal(first.status, 'active', '首次插入 = active')
|
||||
assert.equal(first.createdAt, t0)
|
||||
assert.equal(first.grantIssuedAt, t0)
|
||||
|
||||
const second = await db.upsertOverlayDevice({ ...base, leaseExpiresAt: t0 + 2000, at: t0 + 500 })
|
||||
assert.equal(second.grantRenewals, 2, '续签 = 旧值 + 1(⛔ 不是恒为 1,也不是 2 卡住)')
|
||||
assert.equal(second.leaseExpiresAt, t0 + 2000, '租约必须被刷新')
|
||||
assert.equal(second.createdAt, t0, 'created_at 不被续签改动')
|
||||
const third = await db.upsertOverlayDevice({ ...base, leaseExpiresAt: t0 + 3000, at: t0 + 900 })
|
||||
assert.equal(third.grantRenewals, 3, '第三次 = 3(计数真的在累加)')
|
||||
assert.equal((await db.listOverlayDevices('u:u1')).length, 1, '续签 = 同一行,⛔ 不是插新行')
|
||||
|
||||
// 按网过滤 / 按 userId 归属
|
||||
await db.createUser(user('u2', 'u2'))
|
||||
await db.upsertOverlayDevice({
|
||||
network: 'u:u2',
|
||||
hostId: 'd-u2-11111111',
|
||||
userId: 'u2',
|
||||
nodeKey: 'cd'.repeat(32),
|
||||
leaseExpiresAt: t0 + 1000,
|
||||
at: t0,
|
||||
})
|
||||
assert.equal((await db.listOverlayDevices()).length, 2, '不带过滤 = 全部')
|
||||
assert.equal((await db.listOverlayDevices('u:u2')).length, 1, '按网过滤')
|
||||
assert.equal((await db.findOverlayDevice('u:u2', 'd-u2-11111111')).userId, 'u2')
|
||||
assert.equal(await db.findOverlayDevice('u:u2', 'd-u2-22222222'), undefined, '不存在 ⇒ undefined(⛔ 不抛)')
|
||||
} finally {
|
||||
await db.close()
|
||||
}
|
||||
})
|
||||
|
||||
test(`${backend}: setOverlayDeviceStatus —— 停发是**黏性**的(续签不复活)+ 不存在的行 = false`, async () => {
|
||||
const db = await makeAdapter()
|
||||
try {
|
||||
await db.createUser(user('u3', 'u3'))
|
||||
const row = {
|
||||
network: 'u:u3',
|
||||
hostId: 'd-u3-abcdef12',
|
||||
userId: 'u3',
|
||||
nodeKey: 'ef'.repeat(32),
|
||||
leaseExpiresAt: Date.now() + 1000,
|
||||
}
|
||||
await db.upsertOverlayDevice(row)
|
||||
assert.equal(await db.setOverlayDeviceStatus('u:u3', 'd-u3-abcdef12', 'revoked'), true)
|
||||
assert.equal((await db.findOverlayDevice('u:u3', 'd-u3-abcdef12')).status, 'revoked')
|
||||
// 🔴 关键:续签**不许**把它复活(SQL 层的 DO UPDATE SET 里没有 status 这一列)
|
||||
const renewed = await db.upsertOverlayDevice({ ...row, leaseExpiresAt: Date.now() + 9999 })
|
||||
assert.equal(renewed.status, 'revoked', '⚠️ 续签不得让被停发的设备自动复活')
|
||||
assert.equal(renewed.grantRenewals, 2, '但它确实是一次续签(计数照常累加)')
|
||||
// 恢复只能显式来
|
||||
assert.equal(await db.setOverlayDeviceStatus('u:u3', 'd-u3-abcdef12', 'active'), true)
|
||||
assert.equal((await db.findOverlayDevice('u:u3', 'd-u3-abcdef12')).status, 'active')
|
||||
// 不存在的行 ⇒ false(路由据此回 404)
|
||||
assert.equal(await db.setOverlayDeviceStatus('u:u3', 'd-u3-00000000', 'revoked'), false)
|
||||
} finally {
|
||||
await db.close()
|
||||
}
|
||||
})
|
||||
|
||||
test(`${backend}: overlay_devices 归属 user(删除用户即级联清理台账)`, async () => {
|
||||
const db = await makeAdapter()
|
||||
try {
|
||||
await db.createUser(user('u4', 'u4'))
|
||||
await db.upsertOverlayDevice({
|
||||
network: 'u:u4',
|
||||
hostId: 'd-u4-abcdef12',
|
||||
userId: 'u4',
|
||||
nodeKey: 'aa'.repeat(32),
|
||||
leaseExpiresAt: Date.now() + 1000,
|
||||
})
|
||||
assert.equal((await db.listOverlayDevices()).length, 1)
|
||||
await db.deleteUser('u4')
|
||||
assert.equal((await db.listOverlayDevices()).length, 0, '删用户应当把台账一起带走(ON DELETE CASCADE)')
|
||||
// 未知用户 ⇒ 外键违例(与其它表同一口径)
|
||||
await assert.rejects(
|
||||
() =>
|
||||
db.upsertOverlayDevice({
|
||||
network: 'u:ghost',
|
||||
hostId: 'd-ghost-abcdef12',
|
||||
userId: 'missing',
|
||||
nodeKey: 'bb'.repeat(32),
|
||||
leaseExpiresAt: Date.now(),
|
||||
}),
|
||||
ForeignKeyViolationError,
|
||||
)
|
||||
} finally {
|
||||
await db.close()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
register('sqlite', () => new SqliteAdapter(':memory:', 100000))
|
||||
|
||||
Reference in new issue
Block a user