From eb2821338f9a9bed1298948a9546c583d3878ecf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karol=20S=C3=B3jko?= Date: Fri, 2 Feb 2024 13:08:12 +0100 Subject: [PATCH] add e2e tests --- .../Application/ApplicationInterface.ts | 2 + packages/snjs/lib/Application/Application.ts | 5 ++ packages/snjs/mocha/lib/AppContext.js | 8 +++ packages/snjs/mocha/sync_tests/online.test.js | 63 +++++++++++++++++++ 4 files changed, 78 insertions(+) diff --git a/packages/services/src/Domain/Application/ApplicationInterface.ts b/packages/services/src/Domain/Application/ApplicationInterface.ts index 6cba3a6eb9a..280358f6450 100644 --- a/packages/services/src/Domain/Application/ApplicationInterface.ts +++ b/packages/services/src/Domain/Application/ApplicationInterface.ts @@ -13,6 +13,7 @@ import { MfaServiceInterface, GenerateUuid, CreateDecryptedBackupFile, + SyncBackoffServiceInterface, } from '@standardnotes/services' import { VaultLockServiceInterface } from './../VaultLock/VaultLockServiceInterface' import { HistoryServiceInterface } from './../History/HistoryServiceInterface' @@ -100,6 +101,7 @@ export interface ApplicationInterface { get storage(): StorageServiceInterface get subscriptions(): SubscriptionManagerInterface get sync(): SyncServiceInterface + get syncBackoff(): SyncBackoffServiceInterface get user(): UserServiceInterface get vaultInvites(): VaultInviteServiceInterface get vaultLocks(): VaultLockServiceInterface diff --git a/packages/snjs/lib/Application/Application.ts b/packages/snjs/lib/Application/Application.ts index 466d42e0456..cace59007fc 100644 --- a/packages/snjs/lib/Application/Application.ts +++ b/packages/snjs/lib/Application/Application.ts @@ -81,6 +81,7 @@ import { CreateDecryptedBackupFile, CreateEncryptedBackupFile, WebSocketsService, + SyncBackoffServiceInterface, } from '@standardnotes/services' import { SNNote, @@ -1016,6 +1017,10 @@ export class SNApplication implements ApplicationInterface, AppGroupManagedAppli return this.dependencies.get(TYPES.SyncService) } + public get syncBackoff(): SyncBackoffServiceInterface { + return this.dependencies.get(TYPES.SyncBackoffService) + } + public get user(): UserServiceInterface { return this.dependencies.get(TYPES.UserService) } diff --git a/packages/snjs/mocha/lib/AppContext.js b/packages/snjs/mocha/lib/AppContext.js index 087a0f8e827..0192f19b408 100644 --- a/packages/snjs/mocha/lib/AppContext.js +++ b/packages/snjs/mocha/lib/AppContext.js @@ -593,6 +593,14 @@ export class AppContext { return note } + async createUnsyncedNote(title = 'foo', text = 'bar') { + const payload = createNotePayload(title, text) + const item = await this.application.mutator.emitItemFromPayload(payload, PayloadEmitSource.LocalChanged) + await this.application.mutator.setItemDirty(item) + + return item + } + lockSyncing() { this.application.sync.lockSyncing() } diff --git a/packages/snjs/mocha/sync_tests/online.test.js b/packages/snjs/mocha/sync_tests/online.test.js index 86c20a097fb..d1486de2181 100644 --- a/packages/snjs/mocha/sync_tests/online.test.js +++ b/packages/snjs/mocha/sync_tests/online.test.js @@ -627,6 +627,69 @@ describe('online syncing', function () { await secondContext.deinit() }).timeout(Factory.SixtySecondTimeout) + it('should eventually sync notes that are backed off for a penalty time because of creating too large of a payload', async function () { + const response = await fetch('/mocha/assets/small_file.md') + const buffer = new Uint8Array(await response.arrayBuffer()) + const contents = buffer.toString() + const numberOfNotesToExceedThe1MBPayloadLimit = Math.ceil(100_000 / buffer.length) + 1 + + expect(application.items.getDirtyItems().length).to.equal(0) + + for (let i = 0; i < numberOfNotesToExceedThe1MBPayloadLimit; i++) { + await context.createUnsyncedNote(`note ${i}`, contents) + expectedItemCount++ + } + await context.sync() + + expect(application.items.getDirtyItems().length).to.equal(numberOfNotesToExceedThe1MBPayloadLimit) + + while (application.items.getDirtyItems().length > 0) { + application.items.getDirtyItems().length + + await context.sync() + + await Factory.sleep(1) + } + + expect(application.items.getDirtyItems().length).to.equal(0) + }).timeout(Factory.TwentySecondTimeout) + + it('should not sync notes that solely create a too large payload and are backed off for a penalty time', async function () { + const response = await fetch('/mocha/assets/small_file.md') + const buffer = new Uint8Array(await response.arrayBuffer()) + const contents = buffer.toString() + const numberOfNotesToExceedThe1MBPayloadLimit = Math.ceil(100_000 / buffer.length) + 1 + + expect(application.items.getDirtyItems().length).to.equal(0) + + let hugeContents = '' + for (let i = 0; i < numberOfNotesToExceedThe1MBPayloadLimit; i++) { + hugeContents += contents + } + const hugeNote = await context.createUnsyncedNote(`Huge note that never should be synced`, hugeContents) + expectedItemCount++ + const smallNote = await context.createUnsyncedNote(`Small note that should be synced`, 'Small note that should be synced') + expectedItemCount++ + + await context.sync() + + expect(application.items.getDirtyItems().length).to.equal(2) + + while (application.items.getDirtyItems().length > 1) { + await Factory.sleep(1) + + application.items.getDirtyItems().length + + await context.sync() + } + + expect(application.syncBackoff.isItemInBackoff(smallNote)).to.equal(false) + expect(application.syncBackoff.isItemInBackoff(hugeNote)).to.equal(true) + + const hugeNoteIsNotConsideredForAPotentialCandidateForNextSync = application.syncBackoff.getSmallerSubsetOfItemUuidsInBackoff().length === 0 + expect(hugeNoteIsNotConsideredForAPotentialCandidateForNextSync).to.equal(true) + }).timeout(Factory.TwentySecondTimeout) + it('syncing an item should storage it encrypted', async function () { const note = await Factory.createMappedNote(application) await application.mutator.setItemDirty(note)