d
This commit is contained in:
parent
c3a6f5ff37
commit
4c4e767ec6
73 changed files with 3502 additions and 741 deletions
|
|
@ -11,11 +11,11 @@ const outboxContext={
|
|||
vm.createContext(outboxContext);
|
||||
vm.runInContext(`${functionSource('currentCloudPending')}\n${functionSource('noteCloudRow')}\nthis.logic={currentCloudPending,noteCloudRow};`,outboxContext);
|
||||
outboxContext.logic.noteCloudRow('state','B0');
|
||||
assert.equal(outboxContext.cloudJournalStateIds.has('B0'),false,'Unsolved personal path entered the shared journal');
|
||||
assert.equal(outboxContext.cloudOutboxDeleteKeys.has('state:B0'),true,'Stale unsolved shared outbox row was not scheduled for deletion');
|
||||
assert.equal(outboxContext.cloudJournalStateIds.has('B0'),true,'Unfinished shared path was not added to the shared journal');
|
||||
assert.equal(outboxContext.cloudOutboxDeleteKeys.has('state:B0'),false,'Unfinished shared path was incorrectly deleted from the outbox');
|
||||
outboxContext.logic.noteCloudRow('state','B1');
|
||||
assert.equal(outboxContext.cloudJournalStateIds.has('B1'),true,'Solved state was not added to the shared journal');
|
||||
assert.deepEqual([...outboxContext.logic.currentCloudPending().stateIds],['B1']);
|
||||
assert.deepEqual([...outboxContext.logic.currentCloudPending().stateIds],['B0','B1']);
|
||||
|
||||
const AppLogic=loadAppLogic(),now=1_800_000_000_000;
|
||||
const leaseContext={
|
||||
|
|
@ -26,10 +26,8 @@ vm.createContext(leaseContext);
|
|||
vm.runInContext(`${functionSource('sharedExpansionRepairDelay')}\nthis.sharedExpansionRepairDelay=sharedExpansionRepairDelay;`,leaseContext);
|
||||
assert.equal(leaseContext.sharedExpansionRepairDelay({solved:true,solvedById:'bbbbbbbbbbbbbbbb',solvedAt:now}),0,'The solving client cannot expand its own clear');
|
||||
const wait=leaseContext.sharedExpansionRepairDelay({solved:true,solvedById:'aaaaaaaaaaaaaaaa',solvedAt:now});
|
||||
assert(wait>=60_000&&wait<90_000,'A non-solving client can race the solver before the recovery grace period');
|
||||
assert.equal(leaseContext.sharedExpansionRepairDelay({solved:true,solvedById:'aaaaaaaaaaaaaaaa',solvedAt:now-100_000}),0,'A disconnected solver can leave expansion permanently blocked');
|
||||
leaseContext.cloudAvailable=false;
|
||||
assert.equal(leaseContext.sharedExpansionRepairDelay({solved:true,solvedById:'aaaaaaaaaaaaaaaa',solvedAt:now}),0,'Offline expansion was incorrectly lease-gated');
|
||||
assert.equal(wait,Infinity,'A non-solving client can generate transient boards that the server will reject');
|
||||
assert.equal(leaseContext.sharedExpansionRepairDelay({solved:true,solvedById:'aaaaaaaaaaaaaaaa',solvedAt:now-100_000}),Infinity,'Expansion authority silently transfers away from the solver');
|
||||
|
||||
const localMeta={id:'B0',x:99,y:99,seed:1,chunks:[[0,0]],sealedSides:[],rev:9_999};
|
||||
const remoteMeta={id:'B0',x:0,y:0,seed:2,chunks:[[0,0]],sealedSides:[],rev:2_000};
|
||||
|
|
@ -51,7 +49,7 @@ const authoritativeContext={
|
|||
if(current&&!current.solved&&!incoming.solved)return{...JSON.parse(JSON.stringify(incoming)),paths:JSON.parse(JSON.stringify(current.paths||[]))};
|
||||
return JSON.parse(JSON.stringify(incoming));
|
||||
},
|
||||
markStateDirty:id=>authoritativeContext.dirtyStateIds.add(id),dirtyStateIds:new Set(),sanitizeStateForPuzzle:()=>{},
|
||||
markStateDirty:id=>authoritativeContext.dirtyStateIds.add(id),dirtyStateIds:new Set(),sanitizeStateForPuzzle:()=>{},boardClaimOwnedByMe:()=>false,
|
||||
mergeGlobalFields:()=>{throw new Error('Authoritative shared global unexpectedly used generic merge')},resolveMergedOverlaps:()=>[],statsDirty:false
|
||||
};
|
||||
vm.createContext(authoritativeContext);
|
||||
|
|
@ -76,9 +74,15 @@ assert.equal(authoritativeContext.data.states.B0.solved,true,'A durable clear wa
|
|||
assert.deepEqual([...authoritativeContext.cloudJournalStateIds],['B0'],'The retained clear was not queued for shared upload');
|
||||
assert.equal(authoritativeContext.cloudOutboxDeleteKeys.has('state:B0'),false,'The retained clear was incorrectly scheduled for deletion');
|
||||
|
||||
// Matching unsolved boards keep the player's unfinished line locally while the board definition stays shared.
|
||||
// Matching unsolved boards adopt the authoritative shared progress when this player has no pending claim.
|
||||
authoritativeContext.data.metas.B0=remoteMeta;
|
||||
authoritativeContext.data.states.B0={solved:false,paths:[{startGate:0,cells:[[0,0],[0,1]]}],rev:3_000};
|
||||
authoritativeContext.cloudJournalStateIds.clear();
|
||||
authoritativeContext.mergeSnapshotIntoData({metas:{B0:{...remoteMeta,rev:4_000}},states:{B0:{solved:false,paths:[],rev:4_000}},nextId:2},{finalize:false,authoritativeWorld:true});
|
||||
assert.equal(authoritativeContext.data.states.B0.paths.length,1,'Authoritative shared refresh erased a matching board\'s personal unfinished path');
|
||||
assert.equal(authoritativeContext.data.states.B0.paths.length,0,'Authoritative shared progress did not replace stale local unfinished progress');
|
||||
// The active claimant keeps an unsent local update during a revision-conflict pull, then retries it.
|
||||
authoritativeContext.data.states.B0={solved:false,paths:[{startGate:0,cells:[[0,0],[0,1]]}],rev:5_000};
|
||||
authoritativeContext.cloudJournalStateIds.add('B0');authoritativeContext.boardClaimOwnedByMe=()=>true;
|
||||
authoritativeContext.mergeSnapshotIntoData({metas:{B0:{...remoteMeta,rev:6_000}},states:{B0:{solved:false,paths:[],rev:6_000}},nextId:2},{finalize:false,authoritativeWorld:true});
|
||||
assert.equal(authoritativeContext.data.states.B0.paths.length,1,'The active claimant lost an unsent path during conflict recovery');
|
||||
console.log('Shared-world phase 1 client synchronization smoke test passed');
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue