You've already forked joplin
							
							
				mirror of
				https://github.com/laurent22/joplin.git
				synced 2025-10-31 00:07:48 +02:00 
			
		
		
		
	Updated tools
This commit is contained in:
		| @@ -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 | ||||
| (cd "$ROOT_DIR" && npm test tests-build/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(); | ||||
| 	}); | ||||
|  | ||||
| }); | ||||
| @@ -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 "$@" | ||||
| ./node_modules/.bin/electron . --env dev --log-level warn --open-dev-tools "$@" | ||||
							
								
								
									
										18
									
								
								Tools/android-release-post-process.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								Tools/android-release-post-process.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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()); | ||||
| @@ -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); | ||||
|   | ||||
							
								
								
									
										14
									
								
								Tools/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										14
									
								
								Tools/package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -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", | ||||
|   | ||||
| @@ -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" | ||||
|   } | ||||
| } | ||||
|   | ||||
							
								
								
									
										84
									
								
								Tools/tool-utils.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								Tools/tool-utils.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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; | ||||
							
								
								
									
										27
									
								
								Tools/update-homebrew.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								Tools/update-homebrew.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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); | ||||
| }); | ||||
		Reference in New Issue
	
	Block a user