Skip to content

Commit

Permalink
Prevent remote-change events in RealtimeSyncOff (#824)
Browse files Browse the repository at this point in the history
  • Loading branch information
chacha912 authored May 27, 2024
1 parent 67b3328 commit 240831a
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 1 deletion.
3 changes: 2 additions & 1 deletion src/client/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -695,7 +695,8 @@ export class Client {
// PushPull, ignore the response when the syncMode is PushOnly.
if (
respPack.hasChanges() &&
attachment.syncMode === SyncMode.RealtimePushOnly
(attachment.syncMode === SyncMode.RealtimePushOnly ||
attachment.syncMode === SyncMode.RealtimeSyncOff)
) {
return doc;
}
Expand Down
83 changes: 83 additions & 0 deletions test/integration/client_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,89 @@ describe.sequential('Client', function () {
await c2.deactivate();
});

it('Should prevent remote changes in sync-off mode', async function ({
task,
}) {
const c1 = new yorkie.Client(testRPCAddr);
const c2 = new yorkie.Client(testRPCAddr);
await c1.activate();
await c2.activate();

const docKey = toDocKey(`${task.name}-${new Date().getTime()}`);
const d1 = new yorkie.Document<{ tree: Tree }>(docKey);
const d2 = new yorkie.Document<{ tree: Tree }>(docKey);
await c1.attach(d1);
await c2.attach(d2);

const eventCollectorD1 = new EventCollector();
const eventCollectorD2 = new EventCollector();
const unsub1 = d1.subscribe((event) => {
eventCollectorD1.add(event.type);
});
const unsub2 = d2.subscribe((event) => {
eventCollectorD2.add(event.type);
});

d1.update((root) => {
root.tree = new Tree({
type: 'doc',
children: [
{
type: 'p',
children: [{ type: 'text', value: '12' }],
},
{
type: 'p',
children: [{ type: 'text', value: '34' }],
},
],
});
});
await eventCollectorD2.waitAndVerifyNthEvent(1, DocEventType.RemoteChange);

assert.equal(d1.getRoot().tree.toXML(), '<doc><p>12</p><p>34</p></doc>');
assert.equal(d2.getRoot().tree.toXML(), '<doc><p>12</p><p>34</p></doc>');

d1.update((root) => {
root.tree.edit(2, 2, { type: 'text', value: 'a' });
});
await c1.sync();

// Simulate the situation in the runSyncLoop where a pushpull request has been sent
// but a response has not yet been received.
c2.sync();

// In sync-off mode, remote-change events should not occur.
c2.changeSyncMode(d2, SyncMode.RealtimeSyncOff);
let remoteChangeOccured = false;
const unsub3 = d2.subscribe((event) => {
if (event.type === DocEventType.RemoteChange) {
remoteChangeOccured = true;
}
});
await new Promise((res) => {
// TODO(chacha912): We need to clean up this later because it is non-deterministic.
setTimeout(res, 0); // Keep the sync-off state.
});
unsub3();
assert.isFalse(remoteChangeOccured);

c2.changeSyncMode(d2, SyncMode.Realtime);

d2.update((root) => {
root.tree.edit(2, 2, { type: 'text', value: 'b' });
});
await eventCollectorD1.waitAndVerifyNthEvent(3, DocEventType.RemoteChange);

assert.equal(d1.getRoot().tree.toXML(), '<doc><p>1ba2</p><p>34</p></doc>');
assert.equal(d2.getRoot().tree.toXML(), '<doc><p>1ba2</p><p>34</p></doc>');

unsub1();
unsub2();
await c1.deactivate();
await c2.deactivate();
});

it('Should avoid unnecessary syncs in push-only mode', async function ({
task,
}) {
Expand Down

0 comments on commit 240831a

Please sign in to comment.