From ab8c66a361f207b1b8096ea15defcfea1e3c435f Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Mon, 4 Dec 2017 18:16:14 +0000 Subject: [PATCH] Updated tools --- CliClient/run_test.sh | 2 +- CliClient/tests/synchronizer.js | 789 +++++++++++++------------- ElectronClient/run.sh | 2 +- Tools/android-release-post-process.js | 18 + Tools/build-translation.js | 20 +- Tools/package-lock.json | 14 + Tools/package.json | 3 +- Tools/tool-utils.js | 84 +++ Tools/update-homebrew.js | 27 + 9 files changed, 529 insertions(+), 430 deletions(-) create mode 100644 Tools/android-release-post-process.js create mode 100644 Tools/tool-utils.js create mode 100644 Tools/update-homebrew.js diff --git a/CliClient/run_test.sh b/CliClient/run_test.sh index b235e24cc..45540c425 100755 --- a/CliClient/run_test.sh +++ b/CliClient/run_test.sh @@ -7,4 +7,4 @@ rsync -a "$ROOT_DIR/../ReactNativeClient/lib/" "$BUILD_DIR/lib/" rsync -a "$ROOT_DIR/build/locales/" "$BUILD_DIR/locales/" mkdir -p "$BUILD_DIR/data" -npm test tests-build/synchronizer.js \ No newline at end of file +(cd "$ROOT_DIR" && npm test tests-build/synchronizer.js) \ No newline at end of file diff --git a/CliClient/tests/synchronizer.js b/CliClient/tests/synchronizer.js index 1ce2a1ffe..5328879b2 100644 --- a/CliClient/tests/synchronizer.js +++ b/CliClient/tests/synchronizer.js @@ -15,7 +15,7 @@ process.on('unhandledRejection', (reason, p) => { console.log('Unhandled Rejection at: Promise', p, 'reason:', reason); }); -jasmine.DEFAULT_TIMEOUT_INTERVAL = 9000; // The first test is slow because the database needs to be built +jasmine.DEFAULT_TIMEOUT_INTERVAL = 15000; // The first test is slow because the database needs to be built async function allItems() { let folders = await Folder.all(); @@ -62,598 +62,571 @@ 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 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(); - // done(); - // }); + await localItemsSameAsRemote(all, expect); - // 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(); + done(); + }); - // await switchClient(2); + 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 synchronizer().start(); + await switchClient(2); - // await sleep(0.1); + await synchronizer().start(); - // let note2 = await Note.load(note1.id); - // note2.title = "Updated on client 2"; - // await Note.save(note2); - // note2 = await Note.load(note2.id); + await sleep(0.1); - // await synchronizer().start(); + let note2 = await Note.load(note1.id); + note2.title = "Updated on client 2"; + await Note.save(note2); + note2 = await Note.load(note2.id); - // await switchClient(1); + await synchronizer().start(); - // await synchronizer().start(); + await switchClient(1); - // let all = await allItems(); + await synchronizer().start(); - // await localItemsSameAsRemote(all, expect); + let all = await allItems(); - // done(); - // }); + await localItemsSameAsRemote(all, expect); - // 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(); + done(); + }); - // await switchClient(2); + 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 synchronizer().start(); - // 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 switchClient(2); - // await switchClient(1); + await synchronizer().start(); + 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(); - // 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(); - // let conflictedNotes = await Note.conflictedNotes(); - // expect(conflictedNotes.length).toBe(1); + await switchClient(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); - // } + 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(); + let conflictedNotes = await Note.conflictedNotes(); + expect(conflictedNotes.length).toBe(1); - // let noteUpdatedFromRemote = await Note.load(note1.id); - // for (let n in noteUpdatedFromRemote) { - // if (!noteUpdatedFromRemote.hasOwnProperty(n)) continue; - // expect(noteUpdatedFromRemote[n]).toBe(note2[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); + } - // done(); - // }); + let noteUpdatedFromRemote = await Note.load(note1.id); + for (let n in noteUpdatedFromRemote) { + if (!noteUpdatedFromRemote.hasOwnProperty(n)) continue; + expect(noteUpdatedFromRemote[n]).toBe(note2[n], 'Property: ' + n); + } - // 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(); + done(); + }); - // await switchClient(2); // ---------------------------------- + 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 synchronizer().start(); + await switchClient(2); // ---------------------------------- - // await sleep(0.1); + await synchronizer().start(); - // 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 sleep(0.1); - // await synchronizer().start(); + 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 switchClient(1); // ---------------------------------- + await synchronizer().start(); - // await sleep(0.1); + await switchClient(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); + await sleep(0.1); - // await synchronizer().start(); + 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_final = await Folder.load(folder1.id); - // expect(folder1_final.title).toBe(folder1_modRemote.title); + await synchronizer().start(); - // done(); - // }); + let folder1_final = await Folder.load(folder1.id); + expect(folder1_final.title).toBe(folder1_modRemote.title); - // 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(); + done(); + }); - // await switchClient(2); + 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 synchronizer().start(); + await switchClient(2); - // await sleep(0.1); + await synchronizer().start(); - // await Note.delete(note1.id); + await sleep(0.1); - // await synchronizer().start(); + await Note.delete(note1.id); - // let files = await fileApi().list(); - // files = files.items; + await synchronizer().start(); - // expect(files.length).toBe(1); - // expect(files[0].path).toBe(Folder.systemPath(folder1)); + let files = await fileApi().list(); + files = files.items; - // let deletedItems = await BaseItem.deletedItems(syncTargetId()); - // expect(deletedItems.length).toBe(0); + expect(files.length).toBe(1); + expect(files[0].path).toBe(Folder.systemPath(folder1)); - // done(); - // }); + let deletedItems = await BaseItem.deletedItems(syncTargetId()); + expect(deletedItems.length).toBe(0); - // 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(); + done(); + }); - // await switchClient(2); + 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 synchronizer().start(); - // await Note.delete(note1.id); - // await synchronizer().start(); + await switchClient(2); - // await switchClient(1); + await synchronizer().start(); + await Note.delete(note1.id); + await synchronizer().start(); - // await synchronizer().start(); - // let items = await allItems(); - // expect(items.length).toBe(1); - // let deletedItems = await BaseItem.deletedItems(syncTargetId()); - // expect(deletedItems.length).toBe(0); + await switchClient(1); + + await synchronizer().start(); + let items = await allItems(); + expect(items.length).toBe(1); + let deletedItems = await BaseItem.deletedItems(syncTargetId()); + 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(); - // let all = await allItems(); - // localItemsSameAsRemote(all, expect); + let all = await allItems(); + localItemsSameAsRemote(all, expect); - // done(); - // }); + done(); + }); - // it('should delete local folder', async (done) => { - // let folder1 = await Folder.save({ title: "folder1" }); - // let folder2 = await Folder.save({ title: "folder2" }); - // await synchronizer().start(); + it('should delete local 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(); - // await switchClient(1); + await switchClient(1); - // await synchronizer().start(); + await synchronizer().start(); - // let items = await allItems(); - // localItemsSameAsRemote(items, expect); + let items = await allItems(); + localItemsSameAsRemote(items, expect); - // done(); - // }); + done(); + }); - // it('should resolve conflict if remote folder has been deleted, but note has been added to folder locally', async (done) => { - // let folder1 = await Folder.save({ title: "folder1" }); - // await synchronizer().start(); + it('should resolve conflict if remote folder has been deleted, but note has been added to folder locally', async (done) => { + let folder1 = await Folder.save({ title: "folder1" }); + await synchronizer().start(); - // await switchClient(2); + await switchClient(2); - // await synchronizer().start(); - // await Folder.delete(folder1.id); - // await synchronizer().start(); + await synchronizer().start(); + await Folder.delete(folder1.id); + await synchronizer().start(); - // await switchClient(1); + await switchClient(1); - // let note = await Note.save({ title: "note1", parent_id: folder1.id }); - // await synchronizer().start(); - // let items = await allItems(); - // expect(items.length).toBe(1); - // expect(items[0].title).toBe('note1'); - // expect(items[0].is_conflict).toBe(1); + let note = await Note.save({ title: "note1", parent_id: folder1.id }); + await synchronizer().start(); + let items = await allItems(); + expect(items.length).toBe(1); + expect(items[0].title).toBe('note1'); + expect(items[0].is_conflict).toBe(1); - // done(); - // }); + done(); + }); - // it('should resolve conflict if note has been deleted remotely and locally', async (done) => { - // let folder = await Folder.save({ title: "folder" }); - // let note = await Note.save({ title: "note", parent_id: folder.title }); - // await synchronizer().start(); + it('should resolve conflict if note has been deleted remotely and locally', async (done) => { + let folder = await Folder.save({ title: "folder" }); + let note = await Note.save({ title: "note", parent_id: folder.title }); + await synchronizer().start(); - // await switchClient(2); + await switchClient(2); - // await synchronizer().start(); - // await Note.delete(note.id); - // await synchronizer().start(); + await synchronizer().start(); + await Note.delete(note.id); + await synchronizer().start(); - // await switchClient(1); + await switchClient(1); - // await Note.delete(note.id); - // await synchronizer().start(); + await Note.delete(note.id); + await synchronizer().start(); - // let items = await allItems(); - // expect(items.length).toBe(1); - // expect(items[0].title).toBe('folder'); + let items = await allItems(); + expect(items.length).toBe(1); + expect(items[0].title).toBe('folder'); - // localItemsSameAsRemote(items, expect); + localItemsSameAsRemote(items, expect); - // done(); - // }); + done(); + }); - // it('should cross delete all folders', async (done) => { - // // If client1 and 2 have two folders, client 1 deletes item 1 and client - // // 2 deletes item 2, they should both end up with no items after sync. + it('should cross delete all folders', async (done) => { + // If client1 and 2 have two folders, client 1 deletes item 1 and client + // 2 deletes item 2, they should both end up with no items after sync. - // let folder1 = await Folder.save({ title: "folder1" }); - // let folder2 = await Folder.save({ title: "folder2" }); - // await synchronizer().start(); + 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(folder1.id); + await Folder.delete(folder1.id); - // await switchClient(1); + await switchClient(1); - // await Folder.delete(folder2.id); + await Folder.delete(folder2.id); - // await synchronizer().start(); + await synchronizer().start(); - // await switchClient(2); + await switchClient(2); - // await synchronizer().start(); + await synchronizer().start(); - // let items2 = await allItems(); + let items2 = await allItems(); - // await switchClient(1); + await switchClient(1); - // await synchronizer().start(); + await synchronizer().start(); - // let items1 = await allItems(); + let items1 = await allItems(); - // expect(items1.length).toBe(0); - // expect(items1.length).toBe(items2.length); + expect(items1.length).toBe(0); + expect(items1.length).toBe(items2.length); - // done(); - // }); + 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); - // let unconflictedNotes = await Note.unconflictedNotes(); + let unconflictedNotes = await Note.unconflictedNotes(); - // expect(unconflictedNotes.length).toBe(0); + expect(unconflictedNotes.length).toBe(0); - // 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 titles', async (done) => { - // let localF1 = await Folder.save({ title: "folder" }); + it('should allow duplicate folder titles', 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(true); + expect(localF2.title == remoteF2.title).toBe(true); - // // 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(); + }); - // it('should sync tags', async (done) => { - // let f1 = await Folder.save({ title: "folder" }); - // let n1 = await Note.save({ title: "mynote" }); - // let n2 = await Note.save({ title: "mynote2" }); - // let tag = await Tag.save({ title: 'mytag' }); - // await synchronizer().start(); + it('should sync tags', async (done) => { + let f1 = await Folder.save({ title: "folder" }); + let n1 = await Note.save({ title: "mynote" }); + let n2 = await Note.save({ title: "mynote2" }); + let tag = await Tag.save({ title: 'mytag' }); + await synchronizer().start(); - // await switchClient(2); + await switchClient(2); - // await synchronizer().start(); - // let remoteTag = await Tag.loadByTitle(tag.title); - // expect(!!remoteTag).toBe(true); - // expect(remoteTag.id).toBe(tag.id); - // await Tag.addNote(remoteTag.id, n1.id); - // await Tag.addNote(remoteTag.id, n2.id); - // let noteIds = await Tag.noteIds(tag.id); - // expect(noteIds.length).toBe(2); - // await synchronizer().start(); + await synchronizer().start(); + let remoteTag = await Tag.loadByTitle(tag.title); + expect(!!remoteTag).toBe(true); + expect(remoteTag.id).toBe(tag.id); + await Tag.addNote(remoteTag.id, n1.id); + await Tag.addNote(remoteTag.id, n2.id); + let noteIds = await Tag.noteIds(tag.id); + expect(noteIds.length).toBe(2); + await synchronizer().start(); - // await switchClient(1); + await switchClient(1); - // await synchronizer().start(); - // let remoteNoteIds = await Tag.noteIds(tag.id); - // expect(remoteNoteIds.length).toBe(2); - // await Tag.removeNote(tag.id, n1.id); - // remoteNoteIds = await Tag.noteIds(tag.id); - // expect(remoteNoteIds.length).toBe(1); - // await synchronizer().start(); + await synchronizer().start(); + let remoteNoteIds = await Tag.noteIds(tag.id); + expect(remoteNoteIds.length).toBe(2); + await Tag.removeNote(tag.id, n1.id); + remoteNoteIds = await Tag.noteIds(tag.id); + expect(remoteNoteIds.length).toBe(1); + await synchronizer().start(); - // await switchClient(2); + await switchClient(2); - // await synchronizer().start(); - // noteIds = await Tag.noteIds(tag.id); - // expect(noteIds.length).toBe(1); - // expect(remoteNoteIds[0]).toBe(noteIds[0]); + await synchronizer().start(); + noteIds = await Tag.noteIds(tag.id); + expect(noteIds.length).toBe(1); + expect(remoteNoteIds[0]).toBe(noteIds[0]); - // done(); - // }); + done(); + }); - // it('should not sync notes with conflicts', async (done) => { - // let f1 = await Folder.save({ title: "folder" }); - // let n1 = await Note.save({ title: "mynote", parent_id: f1.id, is_conflict: 1 }); - // await synchronizer().start(); + it('should not sync notes with conflicts', async (done) => { + let f1 = await Folder.save({ title: "folder" }); + let n1 = await Note.save({ title: "mynote", parent_id: f1.id, is_conflict: 1 }); + await synchronizer().start(); - // await switchClient(2); + await switchClient(2); - // await synchronizer().start(); - // let notes = await Note.all(); - // let folders = await Folder.all() - // expect(notes.length).toBe(0); - // expect(folders.length).toBe(1); + await synchronizer().start(); + let notes = await Note.all(); + let folders = await Folder.all() + expect(notes.length).toBe(0); + expect(folders.length).toBe(1); - // done(); - // }); + done(); + }); - // it('should not try to delete on remote conflicted notes that have been deleted', async (done) => { - // let f1 = await Folder.save({ title: "folder" }); - // let n1 = await Note.save({ title: "mynote", parent_id: f1.id }); - // await synchronizer().start(); + it('should not try to delete on remote conflicted notes that have been deleted', async (done) => { + let f1 = await Folder.save({ title: "folder" }); + let n1 = await Note.save({ title: "mynote", parent_id: f1.id }); + await synchronizer().start(); - // await switchClient(2); + await switchClient(2); - // await synchronizer().start(); - // await Note.save({ id: n1.id, is_conflict: 1 }); - // await Note.delete(n1.id); - // const deletedItems = await BaseItem.deletedItems(syncTargetId()); + await synchronizer().start(); + await Note.save({ id: n1.id, is_conflict: 1 }); + await Note.delete(n1.id); + const deletedItems = await BaseItem.deletedItems(syncTargetId()); - // expect(deletedItems.length).toBe(0); + expect(deletedItems.length).toBe(0); - // done(); - // }); + done(); + }); - // it('should not consider it is a conflict if neither the title nor body of the note have changed', async (done) => { - // // That was previously a common conflict: - // // - Client 1 mark todo as "done", and sync - // // - Client 2 doesn't sync, mark todo as "done" todo. Then sync. - // // In theory it is a conflict because the todo_completed dates are different - // // but in practice it doesn't matter, we can just take the date when the - // // todo was marked as "done" the first time. + it('should not consider it is a conflict if neither the title nor body of the note have changed', async (done) => { + // That was previously a common conflict: + // - Client 1 mark todo as "done", and sync + // - Client 2 doesn't sync, mark todo as "done" todo. Then sync. + // In theory it is a conflict because the todo_completed dates are different + // but in practice it doesn't matter, we can just take the date when the + // todo was marked as "done" the first time. - // let folder1 = await Folder.save({ title: "folder1" }); - // let note1 = await Note.save({ title: "un", is_todo: 1, parent_id: folder1.id }); - // await synchronizer().start(); - - // await switchClient(2); - - // await synchronizer().start(); - // let note2 = await Note.load(note1.id); - // note2.todo_completed = time.unixMs()-1; - // await Note.save(note2); - // note2 = await Note.load(note2.id); - // await synchronizer().start(); - - // await switchClient(1); - - // let note2conf = await Note.load(note1.id); - // note2conf.todo_completed = time.unixMs(); - // await Note.save(note2conf); - // note2conf = await Note.load(note1.id); - // await synchronizer().start(); - - // let conflictedNotes = await Note.conflictedNotes(); - // expect(conflictedNotes.length).toBe(0); - - // let notes = await Note.all(); - // expect(notes.length).toBe(1); - // expect(notes[0].id).toBe(note1.id); - // expect(notes[0].todo_completed).toBe(note2.todo_completed); - - // done(); - // }); - - // it('items should be downloaded again when user cancels in the middle of delta operation', async (done) => { - // let folder1 = await Folder.save({ title: "folder1" }); - // let note1 = await Note.save({ title: "un", is_todo: 1, parent_id: folder1.id }); - // await synchronizer().start(); - - // await switchClient(2); - - // synchronizer().debugFlags_ = ['cancelDeltaLoop2']; - // let context = await synchronizer().start(); - // let notes = await Note.all(); - // expect(notes.length).toBe(0); - - // synchronizer().debugFlags_ = []; - // await synchronizer().start({ context: context }); - // notes = await Note.all(); - // expect(notes.length).toBe(1); - - // done(); - // }); - - it('should result in the same state if items are synchronised twice with no changes in between', async (done) => { let folder1 = await Folder.save({ title: "folder1" }); let note1 = await Note.save({ title: "un", is_todo: 1, parent_id: folder1.id }); - await synchronizer().start(); - await Note.save({id: note1.id, body: "changed", type_: note1.type_ }); - note1 = await Note.load(note1.id); + await switchClient(2); await synchronizer().start(); - - await Note.save({id: note1.id, body: "changed 2", type_: note1.type_ }); - note1 = await Note.load(note1.id); - + let note2 = await Note.load(note1.id); + note2.todo_completed = time.unixMs()-1; + await Note.save(note2); + note2 = await Note.load(note2.id); await synchronizer().start(); - let noteNew1 = await Note.load(note1.id); + await switchClient(1); - //console.info(noteNew1); + let note2conf = await Note.load(note1.id); + note2conf.todo_completed = time.unixMs(); + await Note.save(note2conf); + note2conf = await Note.load(note1.id); + await synchronizer().start(); let conflictedNotes = await Note.conflictedNotes(); expect(conflictedNotes.length).toBe(0); - expect(BaseModel.modelsAreSame(note1, noteNew1)).toBe(true); + let notes = await Note.all(); + expect(notes.length).toBe(1); + expect(notes[0].id).toBe(note1.id); + expect(notes[0].todo_completed).toBe(note2.todo_completed); done(); }); - + + it('items should be downloaded again when user cancels in the middle of delta operation', async (done) => { + let folder1 = await Folder.save({ title: "folder1" }); + let note1 = await Note.save({ title: "un", is_todo: 1, parent_id: folder1.id }); + await synchronizer().start(); + + await switchClient(2); + + synchronizer().debugFlags_ = ['cancelDeltaLoop2']; + let context = await synchronizer().start(); + let notes = await Note.all(); + expect(notes.length).toBe(0); + + synchronizer().debugFlags_ = []; + await synchronizer().start({ context: context }); + notes = await Note.all(); + expect(notes.length).toBe(1); + + done(); + }); + }); \ No newline at end of file diff --git a/ElectronClient/run.sh b/ElectronClient/run.sh index ca79bff01..eeebbf8dd 100755 --- a/ElectronClient/run.sh +++ b/ElectronClient/run.sh @@ -3,4 +3,4 @@ ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd "$ROOT_DIR" ./build.sh || exit 1 cd "$ROOT_DIR/app" -./node_modules/.bin/electron . --env dev --log-level debug --open-dev-tools "$@" \ No newline at end of file +./node_modules/.bin/electron . --env dev --log-level warn --open-dev-tools "$@" \ No newline at end of file diff --git a/Tools/android-release-post-process.js b/Tools/android-release-post-process.js new file mode 100644 index 000000000..a9d49fe99 --- /dev/null +++ b/Tools/android-release-post-process.js @@ -0,0 +1,18 @@ +const fs = require('fs-extra'); +const toolUtils = require('./tool-utils.js'); + +const rnDir = __dirname + '/../ReactNativeClient'; + +function androidVersionNumber() { + let content = fs.readFileSync(rnDir + '/android/app/build.gradle', 'utf8'); + const r = content.match(/versionName\s+"(\d+?\.\d+?\.\d+)"/) + if (r.length !== 2) throw new Error('Could not get version number'); + return r[1]; +} + +// const + +// '/android/app/build/outputs/apk/app-armeabi-v7a-release.apk' + + +console.info(androidVersionNumber()); \ No newline at end of file diff --git a/Tools/build-translation.js b/Tools/build-translation.js index c0b6a5897..fdc6f3e1f 100644 --- a/Tools/build-translation.js +++ b/Tools/build-translation.js @@ -15,25 +15,7 @@ const cliLocalesDir = cliDir + '/locales'; const rnDir = rootDir + '/ReactNativeClient'; const electronDir = rootDir + '/ElectronClient/app'; -function execCommand(command) { - if (!silentLog) console.info('Running: ' + command); - - const exec = require('child_process').exec - - return new Promise((resolve, reject) => { - let childProcess = exec(command, (error, stdout, stderr) => { - if (error) { - if (error.signal == 'SIGTERM') { - resolve('Process was killed'); - } else { - reject(error); - } - } else { - resolve(stdout.trim()); - } - }); - }); -} +const { execCommand } = require('./tool-utils.js'); function parsePoFile(filePath) { const content = fs.readFileSync(filePath); diff --git a/Tools/package-lock.json b/Tools/package-lock.json index b478b4309..70f802de9 100644 --- a/Tools/package-lock.json +++ b/Tools/package-lock.json @@ -41,6 +41,11 @@ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" + }, "jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", @@ -59,6 +64,15 @@ "resolved": "https://registry.npmjs.org/mustache/-/mustache-2.3.0.tgz", "integrity": "sha1-QCj3d4sXcIpImTCm5SrDvKDaQdA=" }, + "node-fetch": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", + "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", + "requires": { + "encoding": "0.1.12", + "is-stream": "1.1.0" + } + }, "safe-buffer": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", diff --git a/Tools/package.json b/Tools/package.json index 73ba24530..c22dbaa35 100644 --- a/Tools/package.json +++ b/Tools/package.json @@ -12,6 +12,7 @@ "fs-extra": "^4.0.2", "gettext-parser": "^1.3.0", "marked": "^0.3.7", - "mustache": "^2.3.0" + "mustache": "^2.3.0", + "node-fetch": "^1.7.3" } } diff --git a/Tools/tool-utils.js b/Tools/tool-utils.js new file mode 100644 index 000000000..d1a02931b --- /dev/null +++ b/Tools/tool-utils.js @@ -0,0 +1,84 @@ +const toolUtils = {}; + +toolUtils.execCommand = function(command) { + const exec = require('child_process').exec + + return new Promise((resolve, reject) => { + let childProcess = exec(command, (error, stdout, stderr) => { + if (error) { + if (error.signal == 'SIGTERM') { + resolve('Process was killed'); + } else { + reject(error); + } + } else { + resolve(stdout.trim()); + } + }); + }); +} + +toolUtils.downloadFile = function(url, targetPath) { + const https = require('https'); + const fs = require('fs'); + + return new Promise((resolve, reject) => { + const file = fs.createWriteStream(targetPath); + const request = https.get(url, function(response) { + if (response.statusCode !== 200) reject(new Error('HTTP error ' + response.statusCode)); + response.pipe(file); + file.on('finish', function() { + file.close(); + resolve(); + }); + }).on('error', (error) => { + reject(error); + }); + }); +} + +toolUtils.fileSha256 = function(filePath) { + return new Promise((resolve, reject) => { + const crypto = require('crypto'); + const fs = require('fs'); + const algo = 'sha256'; + const shasum = crypto.createHash(algo); + + const s = fs.ReadStream(filePath); + s.on('data', function(d) { shasum.update(d); }); + s.on('end', function() { + const d = shasum.digest('hex'); + resolve(d); + }); + s.on('error', function(error) { + reject(error); + }); + }); +} + +toolUtils.unlinkForce = async function(filePath) { + const fs = require('fs-extra'); + + try { + await fs.unlink(filePath); + } catch (error) { + if (error.code === 'ENOENT') return; + throw error; + } +} + +toolUtils.fileExists = async function(filePath) { + return new Promise((resolve, reject) => { + fs.stat(filePath, function(err, stat) { + if (err == null) { + resolve(true); + } else if(err.code == 'ENOENT') { + resolve(false); + } else { + reject(err); + } + }); + }); +} + +module.exports = toolUtils; \ No newline at end of file diff --git a/Tools/update-homebrew.js b/Tools/update-homebrew.js new file mode 100644 index 000000000..ef2f8fe1d --- /dev/null +++ b/Tools/update-homebrew.js @@ -0,0 +1,27 @@ +"use strict" + +// https://github.com/Homebrew/homebrew-core/blob/master/CONTRIBUTING.md + +const rootDir = __dirname + '/..'; +const { execCommand, downloadFile, fileSha256, unlinkForce } = require('./tool-utils.js'); +const fetch = require('node-fetch'); +const fs = require('fs-extra'); + +async function main() { + const url = await execCommand('npm view joplin dist.tarball'); + const targetPath = rootDir + '/latest-cli.tar.gz'; + await unlinkForce(targetPath); + await downloadFile(url, targetPath); + const sha256 = await fileSha256(targetPath); + await unlinkForce(targetPath); + + console.info('URL = ' + url); + console.info('SHA256 = ' + sha256); + console.info(''); + console.info('brew bump-formula-pr --strict joplin --url=' + url + ' --sha256=' + sha256); +} + +main().catch((error) => { + console.error('Fatal error'); + console.error(error); +}); \ No newline at end of file