This commit is contained in:
33333-33333 2026-08-01 16:06:14 +09:00
commit 4c4e767ec6
73 changed files with 3502 additions and 741 deletions

View file

@ -10,7 +10,7 @@ const {connectRealtime}=require('./helpers/realtime-client');
const port=20000+Math.floor(Math.random()*10000);
const dataDir=fs.mkdtempSync(path.join(os.tmpdir(),'bend-field-realtime-phase2-'));
const child=spawn(process.execPath,[path.join(root,'server.js')],{
env:{...process.env,PORT:String(port),HOST:'127.0.0.1',BEND_FIELD_DATA_DIR:dataDir},stdio:['ignore','pipe','pipe']
env:{...process.env,PORT:String(port),HOST:'127.0.0.1',LINK_FIELD_TEST_DATA_ROOT:dataDir},stdio:['ignore','pipe','pipe']
});
let stderr='',aliceRealtime=null,bobRealtime=null;child.stderr.on('data',chunk=>stderr+=chunk);
const base=`http://127.0.0.1:${port}`;
@ -26,9 +26,12 @@ function solvedState(puzzle){return{paths:puzzle.solution.map(route=>({startGate
const alice=(await request('/api/cloud/session',{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify({name:'Alice'})})).body;
const bob=(await request('/api/cloud/session',{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify({name:'Bob'})})).body;
const puzzle=starterPuzzle(),b0=boardMeta('B0',0,111,puzzle),b1=boardMeta('B1',2,222,puzzle);
const bootstrap=await request('/api/cloud/push',{method:'POST',headers:auth(alice),body:JSON.stringify({baseRevision:0,global:{schema:31,appVersion:'47.70',generatorVersion:5,worldGeneration:'v47-field-reset-20260728-interaction-fix',nextId:2},metas:[b0,b1],states:[{id:'B0',value:{paths:[],solved:false,rev:1,revAuthor:'alice'}},{id:'B1',value:{paths:[],solved:false,rev:1,revAuthor:'alice'}}],deleted:[]})});
const bootstrap=await request('/api/cloud/push',{method:'POST',headers:auth(alice),body:JSON.stringify({baseRevision:0,global:{schema:31,appVersion:'47.70',generatorVersion:5,worldGeneration:'linkfield-single-world-20260801',nextId:2},metas:[b0,b1],states:[{id:'B0',value:{paths:[],solved:false,rev:1,revAuthor:'alice'}},{id:'B1',value:{paths:[],solved:false,rev:1,revAuthor:'alice'}}],deleted:[]})});
assert.equal(bootstrap.response.status,200);assert.equal(bootstrap.body.revision,1);
const directClaim=await request('/api/realtime/claim',{method:'POST',headers:auth(alice),body:JSON.stringify({boardId:'B0'})});assert.equal(directClaim.response.status,200);assert.equal(directClaim.body.ok,true);assert.equal(directClaim.body.claim.playerName,'Alice');
const directDenied=await request('/api/realtime/claim',{method:'POST',headers:auth(bob),body:JSON.stringify({boardId:'B0'})});assert.equal(directDenied.response.status,200);assert.equal(directDenied.body.ok,false);assert.equal(directDenied.body.reason,'occupied');
aliceRealtime=await connectRealtime(base,alice);bobRealtime=await connectRealtime(base,bob);
aliceRealtime.send({type:'viewport',minX:-8,minY:-8,maxX:8,maxY:8});bobRealtime.send({type:'viewport',minX:-8,minY:-8,maxX:8,maxY:8});
await aliceRealtime.waitFor('snapshot');await bobRealtime.waitFor('snapshot');
@ -63,8 +66,9 @@ function solvedState(puzzle){return{paths:puzzle.solution.map(route=>({startGate
await bobRealtime.waitFor(message=>message.type==='claim'&&message.claim?.boardId==='B1');
aliceRealtime.close();aliceRealtime=null;
await bobRealtime.waitFor(message=>message.type==='player-left'&&message.playerId===alice.playerId);
await bobRealtime.waitFor(message=>message.type==='claim-release'&&message.boardId==='B1'&&message.reason==='disconnected');
bobRealtime.send({type:'claim',requestId:'bob-b1-after-disconnect',boardId:'B1'});
const retained=await bobRealtime.waitFor(message=>message.type==='claim-result'&&message.requestId==='bob-b1-after-disconnect');assert.equal(retained.ok,false);assert.equal(retained.reason,'occupied');
const transferred=await bobRealtime.waitFor(message=>message.type==='claim-result'&&message.requestId==='bob-b1-after-disconnect');assert.equal(transferred.ok,true);assert.equal(transferred.claim.playerName,'Bob');
console.log('BEND FIELD realtime phase 2 smoke test passed');
})().catch(error=>{console.error(error);if(stderr)console.error(stderr);process.exitCode=1}).finally(()=>{aliceRealtime?.close();bobRealtime?.close();child.kill('SIGTERM');fs.rmSync(dataDir,{recursive:true,force:true})});