test(canvas): retain copy checkpoints without duplicating managed image bytes

This commit is contained in:
2026-11-11 16:09:25 +08:00
parent db6594f473
commit 580a14f508
+3 -3
View File
@@ -81,13 +81,13 @@ try{
await engine.close();
const targetCreated=await transport({method:'POST',path:`workspaces/${workspaceId}/materials`,body:JSON.stringify({kind:'board',title:'Cross-project depot target',content:{}})});assert.equal(targetCreated.status,201);const targetRoot=targetCreated.body.id;
const targetMigration=await loadFoundryModel(transport,workspaceId,targetRoot,registry);assert.equal(targetMigration.status,'migration-required');const targetMigrationId=randomUUID();assert.equal((await transport({method:'POST',path:`workspaces/${workspaceId}/materials/${targetRoot}/canvas/model/migrate`,requestId:targetMigrationId,body:JSON.stringify({protocol_version:2,request_id:targetMigrationId,expected_versions:Object.fromEntries(targetMigration.sourceVersions)})})).status,200);
const targetInitial=await loadFoundryModel(transport,workspaceId,targetRoot,registry);assert.equal(targetInitial.status,'ready');let targetImage=null,targetOwner;
const targetStorage={...storage,async claim(targetScope){assert.equal(targetOwner,undefined);const held={scope:targetScope,fence:1,active:true,async release(){held.active=false;targetOwner=undefined;}};targetOwner=held;return held;},async recover(){return structuredClone(targetImage);},async commit(held,batch){assert.strictEqual(held,targetOwner);targetImage=structuredClone(batch.image);share(batch);assert.equal((batch.files??[]).length,0,'adoption duplicated project-local bytes');return{durableRootRevision:targetImage.rootRevision};},async readFile(){return;}};
const targetInitial=await loadFoundryModel(transport,workspaceId,targetRoot,registry);assert.equal(targetInitial.status,'ready');let targetImage=null,targetOwner,adoptionOnly=true;const targetFiles=new Map();
const targetStorage={...storage,async claim(targetScope){assert.equal(targetOwner,undefined);const held={scope:targetScope,fence:1,active:true,async release(){held.active=false;targetOwner=undefined;}};targetOwner=held;return held;},async recover(){return structuredClone(targetImage);},async commit(held,batch){assert.strictEqual(held,targetOwner);if(adoptionOnly)assert.equal((batch.files??[]).length,0,'adoption duplicated project-local bytes');for(const file of batch.files??[]){assert.equal(file.bytes.type.startsWith('image/'),false,'managed image copy duplicated bitmap bytes');targetFiles.set(file.id,file.bytes);}for(const id of batch.deleteFiles??[])targetFiles.delete(id);targetImage=structuredClone(batch.image);share(batch);return{durableRootRevision:targetImage.rootRevision};},async readFile(_held,id){return targetFiles.get(id);}};
const targetOptions={scope:{accountId,workspaceId,projectId:targetRoot},registry,storage:targetStorage,assets,persistence:createFoundryPersistence({registry,workspaceId,rootId:targetRoot,transport}),document:targetInitial.document,versions:targetInitial.versions,clock,createId:randomUUID,onError:error=>errors.push(error)};
engine=await openProjectEngine(targetOptions);const adoptedId=randomUUID();assert.equal((await engine.adoptResource(imageResource.id,(handle,tx)=>tx.dispatch({type:'element.create',element:{...node(adoptedId,targetRoot),componentId:'image',data:{title:'Adopted existing image',text:'',assetId:handle.id,src:handle.src}}}))).status,'applied');await engine.settle();assert.equal(targetImage.formatVersion,13);assert.equal((await loadFoundryModel(transport,workspaceId,targetRoot,registry)).document.elements.get(adoptedId).data.assetId,imageResource.id);assert.equal(calls.filter(call=>call.method==='POST'&&call.path.endsWith('/assets')).length,uploadCount);
await engine.close();engine=await openProjectEngine(targetOptions);const display=await engine.displayResource(imageResource.id);assert.ok(display.url.startsWith('blob:'));assert.deepEqual(Buffer.from(await(await fetch(display.url)).arrayBuffer()),Buffer.from(await originalBytes.arrayBuffer()));display.release();assert.equal(engine.editor.history.undo().status,'applied');await engine.settle();assert.equal(engine.editor.history.redo().status,'applied');await engine.settle();assert.equal((await loadFoundryModel(transport,workspaceId,targetRoot,registry)).document.elements.get(adoptedId).incarnation,2);assert.equal(calls.filter(call=>call.method==='POST'&&call.path.endsWith('/assets')).length,uploadCount);
let aiReport={};if(process.env.FOUNDRY_TEST_AI_WORKER==='1'){
await engine.close();aiReport=await verifyFoundryAI({open:()=>openProjectEngine({...targetOptions,runs:createFoundryRuns({workspaceId,rootId:targetRoot,registry,transport})}),transport,rootId:targetRoot,imageId:adoptedId,assets,calls,tick,readDisplay:async url=>{const response=await authenticatedFetch(url);assert.equal(response.status,200);return Buffer.from(await response.arrayBuffer());},advance:()=>{now+=10_000;},loseAdmission:()=>{loseNextAIAdmission=true;},loseAction:()=>{loseNextAIAction=true;}});
await engine.close();adoptionOnly=false;aiReport=await verifyFoundryAI({open:()=>openProjectEngine({...targetOptions,runs:createFoundryRuns({workspaceId,rootId:targetRoot,registry,transport})}),transport,rootId:targetRoot,imageId:adoptedId,assets,calls,tick,readDisplay:async url=>{const response=await authenticatedFetch(url);assert.equal(response.status,200);return Buffer.from(await response.arrayBuffer());},advance:()=>{now+=10_000;},loseAdmission:()=>{loseNextAIAdmission=true;},loseAction:()=>{loseNextAIAction=true;}});
}
assert.ok(errors.every(error=>String(error).includes('injected response loss')),'unexpected engine error: '+errors.map(String).join(','));
console.log(JSON.stringify({status:'ok',...aiReport,migrationRetry:true,realHttp:true,lostAckRecovered:true,atomicPartition:true,deepCopyUpperEdge:true,nativePartialReport:true,loadingImportOldCapture:true,unloadedTailDuringCopy:true,scopedImageLostAck:true,copiedPendingImageSharesUpload:true,authorizedAssetMetadata:true,originalAssetBytes:true,crossProjectAdoption:true,adoptionReopenedBytes:true,requests:calls.length}));