Tighten needsFit to exact canvas size, guard against empty renders
needsFit only compared aspect ratio, so a same-aspect-but-larger still (e.g. a 4032x2268 phone photo against a 1344x768 canvas) would skip fitting and hand MiniMaxH3AddGuide a still that does not match the job's own latent size. Require an exact width+height match instead; anything else (including unreadable dimensions) still fits. Also guard the video save path: an empty Comfy download, an empty stitched assembly, or a stitched result with no readable duration now fails the job with a clear error instead of silently saving/attaching a broken zero-length clip. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -21,8 +21,8 @@ function fixture(mode='video') {
|
||||
prepareGraph:async r=>{queued.push({hero:r.request.identityStillId,start:r.request.startClipId,action:r.request.promptSections.action});return {}},queuePrompt:async()=>({prompt_id:`p${++id}`}),
|
||||
fetchHistory:async p=>({[p]:{status:{status_str:'success'},outputs:{}}}),comfyFetch:()=>{throw new Error('Unexpected network call')},
|
||||
extractVideo:()=>({filename:'video.mp4',subfolder:'preview/studio2/r',type:'output'}),extractEditedImage:()=>({filename:'image.png',subfolder:'preview/studio2/r',type:'output'}),
|
||||
downloadComfyVideo:async()=>Buffer.from('video'),downloadComfyImage:async()=>Buffer.from('image'),imageDimensions:()=>({width:960,height:960}),
|
||||
videoSourcePaths:()=>['source'],clipVideoPath:()=>'/fake/source',studio2Root:()=>'/fake',join,mkdirSync(){},stitchExtension:async()=>Buffer.from('stitched'),
|
||||
downloadComfyVideo:async()=>Buffer.alloc(128,'v'),downloadComfyImage:async()=>Buffer.from('image'),imageDimensions:()=>({width:960,height:960}),
|
||||
videoSourcePaths:()=>['source'],clipVideoPath:()=>'/fake/source',studio2Root:()=>'/fake',join,mkdirSync(){},writeFileSync(){},unlinkSync(){},probeDuration:async()=>5,stitchExtension:async()=>Buffer.alloc(128,'s'),
|
||||
saveClip:async p=>{const a={id:`asset${saved.length}`,...p};saved.push(a);return a},saveStill:async p=>{const a={id:`asset${saved.length}`,...p};saved.push(a);return a},
|
||||
attachStudio2Metadata:async(owner,id,data)=>{assert.ok(saved.some(a=>a.id===id));assert.equal(data.identityStillId,'hero')},
|
||||
purge:async r=>{assert.ok(saved.length>purged.length);purged.push(r.index);r.purgeResult='Cleared input + output'},
|
||||
@@ -40,6 +40,16 @@ for(const mode of ['video','iterate']) test(`${mode} runner saves each output be
|
||||
test('failed library save never purges host media',async()=>{
|
||||
const f=fixture();f.scope.saveClip=async()=>{throw new Error('Disk full')};await runner(f.scope)(f.record,f.job);assert.equal(f.record.state,'failed');assert.equal(f.purged.length,0)
|
||||
})
|
||||
test('an empty Comfy video output fails the job with a real error and never saves or attaches a clip',async()=>{
|
||||
const f=fixture();f.scope.downloadComfyVideo=async()=>Buffer.alloc(0)
|
||||
await runner(f.scope)(f.record,f.job)
|
||||
assert.equal(f.record.state,'failed');assert.match(f.record.error,/empty video file/);assert.equal(f.saved.length,0);assert.equal(f.record.outputs.length,0)
|
||||
})
|
||||
test('a stitched extension with no readable duration fails the job and never saves or attaches a clip',async()=>{
|
||||
const f=fixture('video');f.scope.probeDuration=async()=>NaN
|
||||
await runner(f.scope)(f.record,f.job)
|
||||
assert.equal(f.record.state,'failed');assert.match(f.record.error,/no readable duration/);assert.equal(f.saved.length,0);assert.equal(f.record.outputs.length,0)
|
||||
})
|
||||
test('resume uses persisted Comfy prompt and never submits it again',async()=>{
|
||||
const f=fixture();f.record.request.batch=[];f.record.promptId='existing';f.record.files=[];f.record.index=0
|
||||
f.scope.queuePrompt=async()=>{throw new Error('Duplicate submit')};await runner(f.scope)(f.record,f.job)
|
||||
|
||||
Reference in New Issue
Block a user