| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152 |
- // @vitest-environment node
- import {afterEach,expect,it,vi} from 'vitest'
- import {execFile} from 'node:child_process'
- import {randomUUID} from 'node:crypto'
- import {mkdtemp,rm,access,writeFile,mkdir} from 'node:fs/promises'
- import {join} from 'node:path'
- import {promisify} from 'node:util'
- import {GUEST_COMMAND} from '../../src/runner/computers/commandProcess'
- const homes:string[]=[]
- afterEach(async()=>{await Promise.all(homes.splice(0).map(path=>rm(path,{recursive:true,force:true})))})
- const python=promisify(execFile)
- const launch=(root:string,key:string,script:string,timeout=3)=>python('python3',['-c',GUEST_COMMAND,'run',root,key,'root',String(timeout),'python3','-c',script],{timeout:10000})
- const cancel=(root:string,key:string)=>python('python3',['-c',GUEST_COMMAND,'cancel',root,key],{timeout:10000})
- const exists=(path:string)=>access(path).then(()=>true,()=>false)
- async function fixture(){const root=await mkdtemp('/tmp/yaoyao-cmd-');homes.push(root);return root}
- it.skipIf(process.platform==='win32')('cancels a guest process group while a peer command finishes and preserves command IO',async()=>{
- const root=await fixture(),key=randomUUID(),ready=join(root,'ready'),late=join(root,'late')
- const child=`import pathlib,time;time.sleep(.6);pathlib.Path(${JSON.stringify(late)}).touch()`
- const execution=launch(root,key,`import subprocess,pathlib,time;subprocess.Popen(['python3','-c',${JSON.stringify(child)}]);pathlib.Path(${JSON.stringify(ready)}).touch();time.sleep(30)`).catch(error=>error)
- const peer=launch(root,randomUUID(),"import time,sys;time.sleep(.3);print('peer');print('stderr',file=sys.stderr)")
- try{
- await vi.waitFor(async()=>expect(await exists(ready)).toBe(true))
- await expect(launch(root,key,"print('duplicate')")).rejects.toMatchObject({code:130})
- expect(JSON.parse((await cancel(root,key)).stdout)).toEqual({stopped:true})
- expect(await execution).toMatchObject({code:130})
- expect(await peer).toMatchObject({stdout:'peer\n',stderr:'stderr\n'})
- await new Promise(resolve=>setTimeout(resolve,600))
- expect(await exists(late)).toBe(false)
- }finally{await cancel(root,key).catch(()=>{});await Promise.allSettled([execution,peer])}
- },10000)
- it.skipIf(process.platform==='win32')('prevents launch when cancellation arrives first and acknowledges completed commands',async()=>{
- const root=await fixture(),key=randomUUID(),marker=join(root,'never')
- expect(JSON.parse((await cancel(root,key)).stdout)).toEqual({stopped:true})
- await expect(launch(root,key,`import pathlib;pathlib.Path(${JSON.stringify(marker)}).touch()`)).rejects.toMatchObject({code:130})
- expect(await exists(marker)).toBe(false)
- const completed=randomUUID()
- expect((await launch(root,completed,"print('done')")).stdout).toBe('done\n')
- expect(JSON.parse((await cancel(root,completed)).stdout)).toEqual({stopped:true})
- })
- it.skipIf(process.platform==='win32')('times out a process group and refuses to confirm a crashed supervisor',async()=>{
- const root=await fixture(),key=randomUUID(),late=join(root,'late')
- const child=`import pathlib,time;time.sleep(.6);pathlib.Path(${JSON.stringify(late)}).touch()`
- await expect(launch(root,key,`import subprocess,time;subprocess.Popen(['python3','-c',${JSON.stringify(child)}]);time.sleep(30)`,.15)).rejects.toMatchObject({code:124})
- await new Promise(resolve=>setTimeout(resolve,600))
- expect(await exists(late)).toBe(false)
- const crashed=randomUUID();await mkdir(join(root,crashed));await writeFile(join(root,crashed,'started'),'')
- await expect(cancel(root,crashed)).rejects.toMatchObject({code:1})
- expect(await exists(join(root,crashed,'done'))).toBe(false)
- })
|