feat: ship skill and MCP workflows with signed updater for v0.0.7
This commit is contained in:
1 parent
1b52df0603
commit
a01085c656
136 files changed
+18646
-217
No files matched your search
@@ -0,0 +1,95 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import { assertRuntimeAvailable, pauseRuntimeStarts, resumeRuntimeStarts, withRuntimeStart } from '../src/main/update-maintenance'
|
||||
import { createUpdateLifecycle } from '../src/main/update-lifecycle'
|
||||
|
||||
let release!: () => void
|
||||
const running = withRuntimeStart(() => new Promise<void>(resolve => { release = resolve }))
|
||||
await Promise.resolve()
|
||||
let paused = false
|
||||
const pendingPause = pauseRuntimeStarts().then(() => { paused = true })
|
||||
assert.throws(assertRuntimeAvailable, /准备重启/)
|
||||
assert.throws(() => withRuntimeStart(async () => undefined), /准备重启/)
|
||||
await Promise.resolve()
|
||||
assert.equal(paused, false)
|
||||
release()
|
||||
await running
|
||||
await pendingPause
|
||||
assert.equal(paused, true)
|
||||
resumeRuntimeStarts()
|
||||
assert.doesNotThrow(assertRuntimeAvailable)
|
||||
await assert.rejects(withRuntimeStart(async () => { throw new Error('failed start') }), /failed start/)
|
||||
await pauseRuntimeStarts()
|
||||
resumeRuntimeStarts()
|
||||
assert.equal(await withRuntimeStart(async () => 42), 42)
|
||||
console.log('PASS update maintenance: in-flight start drain, new work rejection, resume, rejected-start cleanup')
|
||||
|
||||
let resumed = 0
|
||||
let finishDirectQuiesce!: () => void
|
||||
let directQuiesceStarted!: () => void
|
||||
const directQuiesceStart = new Promise<void>(resolve => { directQuiesceStarted = resolve })
|
||||
let directQuiesceCalls = 0
|
||||
const directLifecycle = createUpdateLifecycle({
|
||||
quiesce: () => {
|
||||
directQuiesceCalls += 1
|
||||
directQuiesceStarted()
|
||||
return new Promise<void>(resolve => { finishDirectQuiesce = resolve })
|
||||
},
|
||||
restore: () => { throw new Error('successful quiesce must not restore') },
|
||||
shutdown: async () => undefined,
|
||||
exit: () => undefined,
|
||||
log: () => undefined
|
||||
})
|
||||
const directInstall = directLifecycle.beforeInstall()
|
||||
await directQuiesceStart
|
||||
assert.equal(directQuiesceCalls, 1, 'install starts quiesce without a confirmation port')
|
||||
let directResolved = false
|
||||
void directInstall.then(() => { directResolved = true })
|
||||
await Promise.resolve()
|
||||
assert.equal(directResolved, false, 'beforeInstall waits for quiesce completion')
|
||||
await assert.rejects(directLifecycle.beforeInstall(), /上次更新准备仍在结束中/)
|
||||
assert.equal(directQuiesceCalls, 1, 'concurrent beforeInstall must not start quiesce twice')
|
||||
finishDirectQuiesce()
|
||||
assert.equal(await directInstall, true)
|
||||
|
||||
let finishQuiesce!: () => void
|
||||
const deferredLifecycle = createUpdateLifecycle({
|
||||
quiesce: () => new Promise<void>(resolve => { finishQuiesce = resolve }),
|
||||
restore: () => { resumed += 1 },
|
||||
shutdown: async () => undefined,
|
||||
exit: () => undefined,
|
||||
log: () => undefined,
|
||||
prepareTimeoutMs: 2
|
||||
})
|
||||
await assert.rejects(deferredLifecycle.beforeInstall(), /清理尚未结束/)
|
||||
deferredLifecycle.installFailed()
|
||||
assert.equal(resumed, 0, 'timeout must not resume while old quiesce is still running')
|
||||
finishQuiesce()
|
||||
await new Promise(resolve => setTimeout(resolve, 0))
|
||||
assert.equal(resumed, 1, 'runtime resumes only after timed-out quiesce settles')
|
||||
|
||||
let exited = 0
|
||||
let restarts = 0
|
||||
let shutdowns = 0
|
||||
const committedLifecycle = createUpdateLifecycle({
|
||||
quiesce: async () => undefined,
|
||||
restore: () => { restarts += 1 },
|
||||
shutdown: async () => { shutdowns += 1 },
|
||||
exit: () => { exited += 1 },
|
||||
log: () => undefined
|
||||
})
|
||||
assert.equal(await committedLifecycle.beforeInstall(), true)
|
||||
await committedLifecycle.quitForUpdate()
|
||||
committedLifecycle.installFailed()
|
||||
assert.deepEqual([shutdowns, exited, restarts], [1, 1, 0], 'committed installer exit must never restore work')
|
||||
await assert.rejects(committedLifecycle.beforeInstall(), /安装器已启动/)
|
||||
const hungShutdown = createUpdateLifecycle({
|
||||
quiesce: async () => undefined,
|
||||
restore: () => { throw new Error('must not restore committed installer') },
|
||||
shutdown: () => new Promise<void>(() => undefined),
|
||||
exit: () => { exited += 1 },
|
||||
log: () => undefined,
|
||||
quitTimeoutMs: 2
|
||||
})
|
||||
await hungShutdown.quitForUpdate()
|
||||
assert.equal(exited, 2, 'hung shutdown is bounded and still releases the installer PID')
|
||||
console.log('PASS update lifecycle: direct quiesce, concurrent barrier, timeout recovery, post-launch no-resume commit')
|
||||
Reference in new issue
Block a user