From bca694afeb5af61efcf2b1a8da03242f24f4cd99 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Sat, 1 Jul 2017 11:30:50 +0100 Subject: [PATCH] Fixed deletion of synced folders --- CliClient/tests/synchronizer.js | 425 ++++++++++++++++---------------- lib/models/base-item.js | 7 + lib/models/folder.js | 10 - lib/synchronizer.js | 14 +- 4 files changed, 228 insertions(+), 228 deletions(-) diff --git a/CliClient/tests/synchronizer.js b/CliClient/tests/synchronizer.js index 3ddccaa458..2d50763002 100644 --- a/CliClient/tests/synchronizer.js +++ b/CliClient/tests/synchronizer.js @@ -54,244 +54,245 @@ describe('Synchronizer', function() { done(); }); - // it('should create remote items', async (done) => { - // let folder = await Folder.save({ title: "folder1" }); - // await Note.save({ title: "un", parent_id: folder.id }); + it('should create remote items', async (done) => { + let folder = await Folder.save({ title: "folder1" }); + await Note.save({ title: "un", parent_id: folder.id }); - // let all = await allItems(); + let all = await allItems(); - // await synchronizer().start(); + await synchronizer().start(); - // await localItemsSameAsRemote(all, expect); + await localItemsSameAsRemote(all, expect); - // done(); - // }); + done(); + }); - // it('should update remote item', async (done) => { - // let folder = await Folder.save({ title: "folder1" }); - // let note = await Note.save({ title: "un", parent_id: folder.id }); - // await synchronizer().start(); + it('should update remote item', async (done) => { + let folder = await Folder.save({ title: "folder1" }); + let note = await Note.save({ title: "un", parent_id: folder.id }); + await synchronizer().start(); - // await sleep(0.1); + await sleep(0.1); - // await Note.save({ title: "un UPDATE", id: note.id }); + await Note.save({ title: "un UPDATE", id: note.id }); - // let all = await allItems(); - // await synchronizer().start(); + let all = await allItems(); + await synchronizer().start(); - // await localItemsSameAsRemote(all, expect); + await localItemsSameAsRemote(all, expect); - // done(); - // }); + done(); + }); - // it('should create local items', async (done) => { - // let folder = await Folder.save({ title: "folder1" }); - // await Note.save({ title: "un", parent_id: folder.id }); - // await synchronizer().start(); + it('should create local items', async (done) => { + let folder = await Folder.save({ title: "folder1" }); + await Note.save({ title: "un", parent_id: folder.id }); + await synchronizer().start(); - // await switchClient(2); + await switchClient(2); - // await synchronizer().start(); + await synchronizer().start(); - // let all = await allItems(); - // await localItemsSameAsRemote(all, expect); + let all = await allItems(); + await localItemsSameAsRemote(all, expect); - // done(); - // }); + done(); + }); - // it('should update local items', async (done) => { - // let folder1 = await Folder.save({ title: "folder1" }); - // let note1 = await Note.save({ title: "un", parent_id: folder1.id }); - // await synchronizer().start(); + it('should update local items', async (done) => { + let folder1 = await Folder.save({ title: "folder1" }); + let note1 = await Note.save({ title: "un", parent_id: folder1.id }); + await synchronizer().start(); - // await switchClient(2); + await switchClient(2); - // await synchronizer().start(); + await synchronizer().start(); - // await sleep(0.1); + await sleep(0.1); - // let note2 = await Note.load(note1.id); - // note2.title = "Updated on client 2"; - // await Note.save(note2); - // note2 = await Note.load(note2.id); + let note2 = await Note.load(note1.id); + note2.title = "Updated on client 2"; + await Note.save(note2); + note2 = await Note.load(note2.id); - // await synchronizer().start(); + await synchronizer().start(); - // await switchClient(1); + await switchClient(1); - // await synchronizer().start(); + await synchronizer().start(); - // let all = await allItems(); + let all = await allItems(); - // await localItemsSameAsRemote(all, expect); + await localItemsSameAsRemote(all, expect); - // done(); - // }); + done(); + }); - // it('should resolve note conflicts', async (done) => { - // let folder1 = await Folder.save({ title: "folder1" }); - // let note1 = await Note.save({ title: "un", parent_id: folder1.id }); - // await synchronizer().start(); + it('should resolve note conflicts', async (done) => { + let folder1 = await Folder.save({ title: "folder1" }); + let note1 = await Note.save({ title: "un", parent_id: folder1.id }); + await synchronizer().start(); - // await switchClient(2); + await switchClient(2); - // await synchronizer().start(); + await synchronizer().start(); - // await sleep(0.1); + await sleep(0.1); - // let note2 = await Note.load(note1.id); - // note2.title = "Updated on client 2"; - // await Note.save(note2); - // note2 = await Note.load(note2.id); + let note2 = await Note.load(note1.id); + note2.title = "Updated on client 2"; + await Note.save(note2); + note2 = await Note.load(note2.id); - // await synchronizer().start(); + await synchronizer().start(); - // await switchClient(1); + await switchClient(1); - // await sleep(0.1); + await sleep(0.1); - // let note2conf = await Note.load(note1.id); - // note2conf.title = "Updated on client 1"; - // await Note.save(note2conf); - // note2conf = await Note.load(note1.id); + let note2conf = await Note.load(note1.id); + note2conf.title = "Updated on client 1"; + await Note.save(note2conf); + note2conf = await Note.load(note1.id); - // await synchronizer().start(); + await synchronizer().start(); - // let conflictedNotes = await Note.conflictedNotes(); + let conflictedNotes = await Note.conflictedNotes(); - // expect(conflictedNotes.length).toBe(1); + expect(conflictedNotes.length).toBe(1); - // // Other than the id (since the conflicted note is a duplicate), and the is_conflict property - // // the conflicted and original note must be the same in every way, to make sure no data has been lost. - // let conflictedNote = conflictedNotes[0]; - // expect(conflictedNote.id == note2conf.id).toBe(false); - // for (let n in conflictedNote) { - // if (!conflictedNote.hasOwnProperty(n)) continue; - // if (n == 'id' || n == 'is_conflict') continue; - // expect(conflictedNote[n]).toBe(note2conf[n], 'Property: ' + n); - // } + // Other than the id (since the conflicted note is a duplicate), and the is_conflict property + // the conflicted and original note must be the same in every way, to make sure no data has been lost. + let conflictedNote = conflictedNotes[0]; + expect(conflictedNote.id == note2conf.id).toBe(false); + for (let n in conflictedNote) { + if (!conflictedNote.hasOwnProperty(n)) continue; + if (n == 'id' || n == 'is_conflict') continue; + expect(conflictedNote[n]).toBe(note2conf[n], 'Property: ' + n); + } - // let noteUpdatedFromRemote = await Note.load(note1.id); - // for (let n in noteUpdatedFromRemote) { - // if (!noteUpdatedFromRemote.hasOwnProperty(n)) continue; - // if (n == 'sync_time') continue; - // expect(noteUpdatedFromRemote[n]).toBe(note2[n], 'Property: ' + n); - // } + let noteUpdatedFromRemote = await Note.load(note1.id); + for (let n in noteUpdatedFromRemote) { + if (!noteUpdatedFromRemote.hasOwnProperty(n)) continue; + if (n == 'sync_time') continue; + expect(noteUpdatedFromRemote[n]).toBe(note2[n], 'Property: ' + n); + } - // done(); - // }); + done(); + }); - // it('should resolve folders conflicts', async (done) => { - // let folder1 = await Folder.save({ title: "folder1" }); - // let note1 = await Note.save({ title: "un", parent_id: folder1.id }); - // await synchronizer().start(); + it('should resolve folders conflicts', async (done) => { + let folder1 = await Folder.save({ title: "folder1" }); + let note1 = await Note.save({ title: "un", parent_id: folder1.id }); + await synchronizer().start(); - // await switchClient(2); // ---------------------------------- + await switchClient(2); // ---------------------------------- - // await synchronizer().start(); + await synchronizer().start(); - // await sleep(0.1); + await sleep(0.1); - // let folder1_modRemote = await Folder.load(folder1.id); - // folder1_modRemote.title = "folder1 UPDATE CLIENT 2"; - // await Folder.save(folder1_modRemote); - // folder1_modRemote = await Folder.load(folder1_modRemote.id); + let folder1_modRemote = await Folder.load(folder1.id); + folder1_modRemote.title = "folder1 UPDATE CLIENT 2"; + await Folder.save(folder1_modRemote); + folder1_modRemote = await Folder.load(folder1_modRemote.id); - // await synchronizer().start(); + await synchronizer().start(); - // await switchClient(1); // ---------------------------------- + await switchClient(1); // ---------------------------------- - // await sleep(0.1); + await sleep(0.1); - // let folder1_modLocal = await Folder.load(folder1.id); - // folder1_modLocal.title = "folder1 UPDATE CLIENT 1"; - // await Folder.save(folder1_modLocal); - // folder1_modLocal = await Folder.load(folder1.id); + let folder1_modLocal = await Folder.load(folder1.id); + folder1_modLocal.title = "folder1 UPDATE CLIENT 1"; + await Folder.save(folder1_modLocal); + folder1_modLocal = await Folder.load(folder1.id); - // await synchronizer().start(); + await synchronizer().start(); - // let folder1_final = await Folder.load(folder1.id); - // expect(folder1_final.title).toBe(folder1_modRemote.title); + let folder1_final = await Folder.load(folder1.id); + expect(folder1_final.title).toBe(folder1_modRemote.title); - // done(); - // }); + done(); + }); - // it('should delete remote notes', async (done) => { - // let folder1 = await Folder.save({ title: "folder1" }); - // let note1 = await Note.save({ title: "un", parent_id: folder1.id }); - // await synchronizer().start(); + it('should delete remote notes', async (done) => { + let folder1 = await Folder.save({ title: "folder1" }); + let note1 = await Note.save({ title: "un", parent_id: folder1.id }); + await synchronizer().start(); - // await switchClient(2); + await switchClient(2); - // await synchronizer().start(); + await synchronizer().start(); - // await sleep(0.1); + await sleep(0.1); - // await Note.delete(note1.id); + await Note.delete(note1.id); - // await synchronizer().start(); + await synchronizer().start(); - // let files = await fileApi().list(); - // files = files.items; + let files = await fileApi().list(); + files = files.items; - // expect(files.length).toBe(1); - // expect(files[0].path).toBe(Folder.systemPath(folder1)); + expect(files.length).toBe(1); + expect(files[0].path).toBe(Folder.systemPath(folder1)); - // let deletedItems = await BaseModel.deletedItems(); - // expect(deletedItems.length).toBe(0); + let deletedItems = await BaseModel.deletedItems(); + expect(deletedItems.length).toBe(0); - // done(); - // }); + done(); + }); - // it('should delete local notes', async (done) => { - // let folder1 = await Folder.save({ title: "folder1" }); - // let note1 = await Note.save({ title: "un", parent_id: folder1.id }); - // await synchronizer().start(); + it('should delete local notes', async (done) => { + let folder1 = await Folder.save({ title: "folder1" }); + let note1 = await Note.save({ title: "un", parent_id: folder1.id }); + await synchronizer().start(); - // await switchClient(2); + await switchClient(2); - // await synchronizer().start(); + await synchronizer().start(); - // await sleep(0.1); + await sleep(0.1); - // await Note.delete(note1.id); + await Note.delete(note1.id); - // await synchronizer().start(); + await synchronizer().start(); - // await switchClient(1); + await switchClient(1); - // await synchronizer().start(); + await synchronizer().start(); - // let items = await allItems(); + let items = await allItems(); - // expect(items.length).toBe(1); + expect(items.length).toBe(1); - // let deletedItems = await BaseModel.deletedItems(); + let deletedItems = await BaseModel.deletedItems(); - // expect(deletedItems.length).toBe(0); + expect(deletedItems.length).toBe(0); - // done(); - // }); + done(); + }); - // it('should delete remote folder', async (done) => { - // let folder1 = await Folder.save({ title: "folder1" }); - // let folder2 = await Folder.save({ title: "folder2" }); - // await synchronizer().start(); + it('should delete remote folder', async (done) => { + let folder1 = await Folder.save({ title: "folder1" }); + let folder2 = await Folder.save({ title: "folder2" }); + await synchronizer().start(); - // await switchClient(2); + await switchClient(2); - // await synchronizer().start(); + await synchronizer().start(); - // await sleep(0.1); + await sleep(0.1); - // await Folder.delete(folder2.id); + await Folder.delete(folder2.id); - // await synchronizer().start(); + await synchronizer().start(); - // localItemsSameAsRemote(); + let all = await allItems(); + localItemsSameAsRemote(all, expect); - // done(); - // }); + done(); + }); it('should delete local folder', async (done) => { let folder1 = await Folder.save({ title: "folder1" }); @@ -318,102 +319,102 @@ describe('Synchronizer', function() { done(); }); - // it('should handle conflict when remote note is deleted then local note is modified', async (done) => { - // let folder1 = await Folder.save({ title: "folder1" }); - // let note1 = await Note.save({ title: "un", parent_id: folder1.id }); - // await synchronizer().start(); + it('should handle conflict when remote note is deleted then local note is modified', async (done) => { + let folder1 = await Folder.save({ title: "folder1" }); + let note1 = await Note.save({ title: "un", parent_id: folder1.id }); + await synchronizer().start(); - // await switchClient(2); + await switchClient(2); - // await synchronizer().start(); + await synchronizer().start(); - // await sleep(0.1); + await sleep(0.1); - // await Note.delete(note1.id); + await Note.delete(note1.id); - // await synchronizer().start(); + await synchronizer().start(); - // await switchClient(1); + await switchClient(1); - // let newTitle = 'Modified after having been deleted'; - // await Note.save({ id: note1.id, title: newTitle }); + let newTitle = 'Modified after having been deleted'; + await Note.save({ id: note1.id, title: newTitle }); - // await synchronizer().start(); + await synchronizer().start(); - // let conflictedNotes = await Note.conflictedNotes(); + let conflictedNotes = await Note.conflictedNotes(); - // expect(conflictedNotes.length).toBe(1); - // expect(conflictedNotes[0].title).toBe(newTitle); + expect(conflictedNotes.length).toBe(1); + expect(conflictedNotes[0].title).toBe(newTitle); - // done(); - // }); + done(); + }); - // it('should handle conflict when remote folder is deleted then local folder is renamed', async (done) => { - // let folder1 = await Folder.save({ title: "folder1" }); - // let folder2 = await Folder.save({ title: "folder2" }); - // let note1 = await Note.save({ title: "un", parent_id: folder1.id }); - // await synchronizer().start(); + it('should handle conflict when remote folder is deleted then local folder is renamed', async (done) => { + let folder1 = await Folder.save({ title: "folder1" }); + let folder2 = await Folder.save({ title: "folder2" }); + let note1 = await Note.save({ title: "un", parent_id: folder1.id }); + await synchronizer().start(); - // await switchClient(2); + await switchClient(2); - // await synchronizer().start(); + await synchronizer().start(); - // await sleep(0.1); + await sleep(0.1); - // await Folder.delete(folder1.id); + await Folder.delete(folder1.id); - // await synchronizer().start(); + await synchronizer().start(); - // await switchClient(1); + await switchClient(1); - // await sleep(0.1); + await sleep(0.1); - // let newTitle = 'Modified after having been deleted'; - // await Folder.save({ id: folder1.id, title: newTitle }); + let newTitle = 'Modified after having been deleted'; + await Folder.save({ id: folder1.id, title: newTitle }); - // await synchronizer().start(); + await synchronizer().start(); - // let items = await allItems(); + let items = await allItems(); - // expect(items.length).toBe(1); + expect(items.length).toBe(1); - // done(); - // }); + done(); + }); - // it('should allow duplicate folder title and rename the new one', async (done) => { - // let localF1 = await Folder.save({ title: "folder" }); + it('should allow duplicate folder title and rename the new one', async (done) => { + let localF1 = await Folder.save({ title: "folder" }); - // await switchClient(2); + await switchClient(2); - // let remoteF2 = await Folder.save({ title: "folder" }); - // await synchronizer().start(); + let remoteF2 = await Folder.save({ title: "folder" }); + await synchronizer().start(); - // await switchClient(1); + await switchClient(1); - // await sleep(0.1); + await sleep(0.1); - // await synchronizer().start(); + await synchronizer().start(); - // let localF2 = await Folder.load(remoteF2.id); + let localF2 = await Folder.load(remoteF2.id); - // expect(localF2.title == remoteF2.title).toBe(false); + expect(localF2.title == remoteF2.title).toBe(false); - // // Then that folder that has been renamed locally should be set in such a way - // // that synchronizing it applies the title change remotely, and that new title - // // should be retrieved by client 2. + // Then that folder that has been renamed locally should be set in such a way + // that synchronizing it applies the title change remotely, and that new title + // should be retrieved by client 2. - // await synchronizer().start(); + await synchronizer().start(); - // await switchClient(2); - // await sleep(0.1); + await switchClient(2); + await sleep(0.1); - // await synchronizer().start(); + await synchronizer().start(); - // remoteF2 = await Folder.load(remoteF2.id); + remoteF2 = await Folder.load(remoteF2.id); - // expect(remoteF2.title == localF2.title).toBe(true); + expect(remoteF2.title == localF2.title).toBe(true); - // done(); - // }); + done(); + }); }); \ No newline at end of file diff --git a/lib/models/base-item.js b/lib/models/base-item.js index 2605ee166d..63043b0316 100644 --- a/lib/models/base-item.js +++ b/lib/models/base-item.js @@ -30,6 +30,13 @@ class BaseItem extends BaseModel { } } + // Returns the IDs of the items that have been synced at least once + static async syncedItems() { + let folders = await Folder.modelSelectAll('SELECT id FROM folders WHERE sync_time > 0'); + let notes = await Note.modelSelectAll('SELECT id FROM notes WHERE is_conflict = 0 AND sync_time > 0'); + return folders.concat(notes); + } + static pathToId(path) { let s = path.split('.'); return s[0]; diff --git a/lib/models/folder.js b/lib/models/folder.js index a78785b6fb..18b18d1f5b 100644 --- a/lib/models/folder.js +++ b/lib/models/folder.js @@ -40,16 +40,6 @@ class Folder extends BaseItem { } } - static syncedNoteIds() { - return this.db().selectAll('SELECT id FROM notes WHERE is_conflict = 0 AND sync_time > 0').then((rows) => { - let output = []; - for (let i = 0; i < rows.length; i++) { - output.push(rows[i].id); - } - return output; - }); - } - static noteIds(parentId) { return this.db().selectAll('SELECT id FROM notes WHERE is_conflict = 0 AND parent_id = ?', [parentId]).then((rows) => { let output = []; diff --git a/lib/synchronizer.js b/lib/synchronizer.js index c060888b89..6faff68226 100644 --- a/lib/synchronizer.js +++ b/lib/synchronizer.js @@ -317,14 +317,16 @@ class Synchronizer { // means the item has been deleted. // ------------------------------------------------------------------------ - let noteIds = await Folder.syncedNoteIds(); - for (let i = 0; i < noteIds.length; i++) { - let noteId = noteIds[i]; - if (remoteIds.indexOf(noteId) < 0) { + let items = await BaseItem.syncedItems(); + for (let i = 0; i < items.length; i++) { + let item = items[i]; + if (remoteIds.indexOf(item.id) < 0) { report.localsToDelete++; options.onProgress(report); - this.logSyncOperation('deleteLocal', { id: noteId }, null, 'remote has been deleted'); - await Note.delete(noteId, { trackDeleted: false }); + this.logSyncOperation('deleteLocal', { id: item.id }, null, 'remote has been deleted'); + + let ItemClass = BaseItem.itemClass(item); + await ItemClass.delete(item.id, { trackDeleted: false }); report['deleteLocal']++; options.onProgress(report); }