From a0c20972aca00260e6f8a8dd3327dfee70a12ba6 Mon Sep 17 00:00:00 2001 From: Codex Bot Date: Fri, 30 Oct 2026 20:30:25 +0800 Subject: [PATCH] Verify successful image generation and upscale task delivery --- .../tests/canvas-integration.ts | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/apps/waterfall-wiki/tests/canvas-integration.ts b/apps/waterfall-wiki/tests/canvas-integration.ts index 55e1ddf..352a937 100644 --- a/apps/waterfall-wiki/tests/canvas-integration.ts +++ b/apps/waterfall-wiki/tests/canvas-integration.ts @@ -2,6 +2,7 @@ import assert from 'node:assert/strict'; import {randomUUID} from 'node:crypto'; import {db} from '../src/lib/db'; import {newToken,tokenDigest,ACCOUNT_COOKIE} from '../src/lib/account-crypto'; +import type {CanvasDocument} from '../src/lib/canvas-document'; export async function verifyCanvasWorkspace(base:string){ const identities=await Promise.all([0,1].map(async()=>{const id=randomUUID(),token=newToken();await db().query("INSERT INTO account_users(id,email,password_hash,verified_at) VALUES($1,$2,'test',now())",[id,id+'@example.com']);await db().query("INSERT INTO account_tokens(digest,user_id,kind,expires_at) VALUES($1,$2,'session',now()+interval '1 hour')",[tokenDigest(token),id]);return {[`cookie`]:ACCOUNT_COOKIE+'='+token}})); const origin=process.env.ACCOUNT_PUBLIC_ORIGIN||base; @@ -39,6 +40,39 @@ export async function verifyCanvasWorkspace(base:string){ assert.equal((await call(root+'/tasks/'+second,'PATCH',result,agent)).status,200,'Identical completion is idempotent'); assert.equal((await call(root+'/tasks/'+second,'PATCH',{status:'succeeded',result:{text:'覆盖'}},agent)).status,409); const final=await (await call(root,'GET',undefined,identities[0])).json();assert.equal(final.revision,4);assert.equal(final.document.cards.find((n:{id:string})=>n.id==='script').text,'第一镜:城市醒来。');assert.deepEqual(final.document.links,doc.links); + const png='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+ip1sAAAAASUVORK5CYII='; + const imageDocument:CanvasDocument={version:1,cards:[ + {id:'source',kind:'image',title:'参考图',text:'保留原图',image:png,x:0,y:0}, + {id:'generated',kind:'image',title:'图生图',text:'',instruction:'保留构图,改为雪夜',operation:'generate',x:500,y:0}, + {id:'upscaled',kind:'image',title:'图片高清',text:'',operation:'upscale',x:1000,y:0}, + ],links:[['source','generated'],['generated','upscaled']]}; + const imageCreate=await call('','POST',{document:imageDocument},identities[0]);assert.equal(imageCreate.status,201); + const imageCanvas=await imageCreate.json(),imageRoot='/'+imageCanvas.id; + const imageLink=await call(imageRoot+'/link','POST',{},identities[0]);assert.equal(imageLink.status,201); + const imageAgent={authorization:'Bearer '+(await imageLink.json()).token}; + for(const [index,targetId] of ['generated','upscaled'].entries()){ + const queued=await call(imageRoot+'/tasks','POST',{revision:index+1,targetId},identities[0]);assert.equal(queued.status,201,await queued.clone().text()); + const taskId=(await queued.json()).id,taskPath=imageRoot+'/tasks/'+taskId; + const snapshotResponse=await call(taskPath,'GET',undefined,imageAgent);assert.equal(snapshotResponse.status,200); + const snapshot=await snapshotResponse.json();assert.equal(snapshot.request.operation,index===0?'generate':'upscale'); + assert.equal(snapshot.request.references[0].id,index===0?'source':'generated'); + assert.equal(snapshot.request.references[0].image,png,'Image tasks carry the referenced image bytes'); + assert.deepEqual(snapshot.request.result.allowedFields,['image','text']); + assert.equal((await call(taskPath,'PATCH',{status:'running'},imageAgent)).status,200); + const completion={status:'succeeded',result:{image:png,text:index===0?'雪夜图片结果':'高清图片结果'}}; + const completed=await call(taskPath,'PATCH',completion,imageAgent);assert.equal(completed.status,200,await completed.clone().text()); + assert.equal((await call(taskPath,'PATCH',completion,imageAgent)).status,200,'Image completion retries are idempotent'); + const stateResponse=await call(imageRoot,'GET',undefined,identities[0]);assert.equal(stateResponse.status,200); + const state=await stateResponse.json();assert.equal(state.revision,index+2); + const cards=(state.document as CanvasDocument).cards; + assert.equal(cards.find(n=>n.id===targetId)?.image,png);assert.equal(cards.find(n=>n.id===targetId)?.text,completion.result.text); + assert.deepEqual(cards.find(n=>n.id==='source'),imageDocument.cards[0],'Generation preserves the reference node'); + assert.deepEqual(state.document.links,imageDocument.links,'Image results preserve the reference graph'); + if(index===0)assert.deepEqual(cards.find(n=>n.id==='upscaled'),imageDocument.cards[2],'Generation only updates its target'); + else assert.equal(cards.find(n=>n.id==='generated')?.text,'雪夜图片结果','Upscaling preserves the previous generated image'); + } + assert.equal((await call(imageRoot+'/link','DELETE',{},identities[0])).status,200); + assert.equal((await call(imageRoot,'GET',undefined,imageAgent)).status,404); assert.equal((await call(root+'/link','POST',{},agent)).status,403,'A delegated agent cannot mint links'); assert.equal((await call(root+'/link','DELETE',{},identities[0])).status,200); assert.equal((await call(root,'GET',undefined,agent)).status,404,'Revocation takes effect on the next request');