diff --git a/packages/core/api/sync/__tests__/sync.test.js b/packages/core/api/sync/__tests__/sync.test.js index 642e2b338..fab27cda9 100644 --- a/packages/core/api/sync/__tests__/sync.test.js +++ b/packages/core/api/sync/__tests__/sync.test.js @@ -259,6 +259,46 @@ test.skip( 60 * 1000 ); +test.skip( + "issue: new topics on 2 devices are not properly synced", + async () => { + const deviceA = await initializeDevice("deviceA"); + const deviceB = await initializeDevice("deviceB"); + + const id = await deviceA.notebooks.add({ title: "Notebook 1" }); + + await syncAndWait(deviceA, deviceB, false); + + expect(deviceB.notebooks.notebook(id)).toBeDefined(); + + await deviceA.notebooks.notebook(id).topics.add("Topic 1"); + + // to create a conflict + await delay(1500); + + await deviceB.notebooks.notebook(id).topics.add("Topic 2"); + + expect(deviceA.notebooks.notebook(id).topics.has("Topic 1")).toBeTruthy(); + + expect(deviceB.notebooks.notebook(id).topics.has("Topic 2")).toBeTruthy(); + + await syncAndWait(deviceA, deviceB, false); + + await delay(1000); + + await syncAndWait(deviceB, deviceB, false); + + expect(deviceA.notebooks.notebook(id).topics.has("Topic 1")).toBeTruthy(); + expect(deviceB.notebooks.notebook(id).topics.has("Topic 1")).toBeTruthy(); + + expect(deviceA.notebooks.notebook(id).topics.has("Topic 2")).toBeTruthy(); + expect(deviceB.notebooks.notebook(id).topics.has("Topic 2")).toBeTruthy(); + + await cleanup(deviceA, deviceB); + }, + 60 * 1000 +); + /** * * @param {string} id @@ -274,11 +314,11 @@ async function initializeDevice(id, capabilities = []) { const device = new Database(new NodeStorageInterface(), EventSource, FS); device.host({ - API_HOST: "http://192.168.43.221:5264", - AUTH_HOST: "http://192.168.43.221:8264", - SSE_HOST: "http://192.168.43.221:7264", - ISSUES_HOST: "http://192.168.43.221:2624", - SUBSCRIPTIONS_HOST: "http://192.168.43.221:9264", + API_HOST: "http://192.168.10.29:5264", + AUTH_HOST: "http://192.168.10.29:8264", + SSE_HOST: "http://192.168.10.29:7264", + ISSUES_HOST: "http://192.168.10.29:2624", + SUBSCRIPTIONS_HOST: "http://192.168.10.29:9264", }); await device.init(id); diff --git a/packages/core/api/sync/merger.js b/packages/core/api/sync/merger.js index bda75b465..7af204db1 100644 --- a/packages/core/api/sync/merger.js +++ b/packages/core/api/sync/merger.js @@ -20,10 +20,13 @@ class Merger { set: (item) => this._db.notes.merge(item), }, notebook: { + threshold: 1000, get: (id) => this._db.notebooks.notebook(id), set: (item) => this._db.notebooks.merge(item), + conflict: (_local, remote) => this._db.notebooks.merge(remote), }, content: { + threshold: process.env.NODE_ENV === "test" ? 6 * 1000 : 60 * 1000, get: (id) => this._db.content.raw(id), set: (item) => this._db.content.add(item), conflict: async (local, remote) => { @@ -138,7 +141,13 @@ class Merger { } } - async _mergeItemWithConflicts(remoteItem, get, add, markAsConflicted) { + async _mergeItemWithConflicts( + remoteItem, + get, + add, + markAsConflicted, + threshold + ) { remoteItem = await this._deserialize(remoteItem); let localItem = await get(remoteItem.id); @@ -149,15 +158,13 @@ class Merger { const isModified = localItem.dateModified > this._lastSynced; if (isModified && !isResolved) { // If time difference between local item's edits & remote item's edits - // is less than 1 minute, we shouldn't trigger a merge conflict; instead + // is less than threshold, we shouldn't trigger a merge conflict; instead // we will keep the most recently changed item. const timeDiff = Math.max(remoteItem.dateModified, localItem.dateModified) - Math.min(remoteItem.dateModified, localItem.dateModified); - const ONE_MINUTE = - process.env.NODE_ENV === "test" ? 6 * 1000 : 60 * 1000; - if (timeDiff < ONE_MINUTE) { + if (timeDiff < threshold) { if (remoteItem.dateModified > localItem.dateModified) { await add(remoteItem); } @@ -188,7 +195,8 @@ class Merger { item, definition.get, definition.set, - definition.conflict + definition.conflict, + definition.threshold ); } else if (definition.get && definition.set) { await this._mergeItem(item, definition.get, definition.set); diff --git a/packages/core/collections/notebooks.js b/packages/core/collections/notebooks.js index 086908330..8a701eb44 100644 --- a/packages/core/collections/notebooks.js +++ b/packages/core/collections/notebooks.js @@ -47,7 +47,7 @@ export default class Notebooks extends Collection { isChanged = true; } } - if (isChanged) remoteNotebook.dateModified = Date.now(); // we update the dateEdited so it can be synced back + remoteNotebook.remote = !isChanged; } return await this._collection.addItem(remoteNotebook); }