mirror of
https://github.com/iflytek/skillhub.git
synced 2026-10-15 04:18:20 +00:00
test(cli): synchronize target lock contenders
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
This commit is contained in:
parent
181e0ba076
commit
021cefb311
2 changed files with 31 additions and 5 deletions
|
|
@ -1,13 +1,22 @@
|
|||
import { access, writeFile } from 'node:fs/promises'
|
||||
import { acquireSkillTargetLock } from '../../src/services/skill-target-lock'
|
||||
import { CliError } from '../../src/shared/errors'
|
||||
|
||||
const [rootDir, slug, holdMilliseconds] = process.argv.slice(2)
|
||||
if (!rootDir || !slug || !holdMilliseconds) process.exit(5)
|
||||
const [rootDir, slug, acquiredPath, releasePath] = process.argv.slice(2)
|
||||
if (!rootDir || !slug || !acquiredPath || !releasePath) process.exit(5)
|
||||
|
||||
try {
|
||||
const release = await acquireSkillTargetLock(rootDir, slug)
|
||||
await writeFile(acquiredPath, 'acquired')
|
||||
process.stdout.write('acquired\n')
|
||||
await new Promise(resolve => setTimeout(resolve, Number(holdMilliseconds)))
|
||||
while (true) {
|
||||
try {
|
||||
await access(releasePath)
|
||||
break
|
||||
} catch {
|
||||
await new Promise(resolve => setTimeout(resolve, 10))
|
||||
}
|
||||
}
|
||||
await release()
|
||||
process.exit(0)
|
||||
} catch (error) {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { access, mkdir, mkdtemp, utimes } from 'node:fs/promises'
|
||||
import { access, mkdir, mkdtemp, utimes, writeFile } from 'node:fs/promises'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { join } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
|
@ -14,6 +14,14 @@ async function exists(path: string): Promise<boolean> {
|
|||
}
|
||||
}
|
||||
|
||||
async function waitForFile(path: string): Promise<void> {
|
||||
for (let attempt = 0; attempt < 500; attempt++) {
|
||||
if (await exists(path)) return
|
||||
await Bun.sleep(10)
|
||||
}
|
||||
throw new Error(`timed out waiting for ${path}`)
|
||||
}
|
||||
|
||||
describe('skill target lifecycle lock', () => {
|
||||
test('simultaneous stale recovery admits exactly one owner across processes', async () => {
|
||||
const rootDir = await mkdtemp(join(tmpdir(), 'skillhub-target-lock-root-'))
|
||||
|
|
@ -23,12 +31,21 @@ describe('skill target lifecycle lock', () => {
|
|||
await utimes(lockPath, staleTime, staleTime)
|
||||
const worker = fileURLToPath(new URL('../../helpers/target-lock-worker.ts', import.meta.url))
|
||||
const bunPath = (await Bun.which('bun')) ?? process.execPath
|
||||
const acquiredPath = join(rootDir, 'acquired')
|
||||
const releasePath = join(rootDir, 'release')
|
||||
|
||||
const processes = [0, 1].map(() => Bun.spawn({
|
||||
cmd: [bunPath, worker, rootDir, 'demo', '1000'],
|
||||
cmd: [bunPath, worker, rootDir, 'demo', acquiredPath, releasePath],
|
||||
stdout: 'pipe',
|
||||
stderr: 'pipe'
|
||||
}))
|
||||
await waitForFile(acquiredPath)
|
||||
const loserExitCode = await Promise.race([
|
||||
...processes.map(process => process.exited),
|
||||
Bun.sleep(5_000).then(() => { throw new Error('timed out waiting for the lock loser') })
|
||||
])
|
||||
expect(loserExitCode).toBe(4)
|
||||
await writeFile(releasePath, 'release')
|
||||
const results = await Promise.all(processes.map(async process => ({
|
||||
exitCode: await process.exited,
|
||||
stdout: (await new Response(process.stdout).text()).trim(),
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue