From 6fd4be20e3747ea147c6c2d16ef160a4ba25cf35 Mon Sep 17 00:00:00 2001 From: David Perez Date: Tue, 18 Jun 2024 09:10:32 -0500 Subject: [PATCH] Add support for the FCMv1 format in push notifications (#1456) --- .../data/platform/manager/PushManager.kt | 9 +- .../data/platform/manager/PushManagerImpl.kt | 22 +- .../push/BitwardenFirebaseMessagingService.kt | 6 +- .../data/platform/manager/PushManagerTest.kt | 686 +++++++++++++++++- 4 files changed, 679 insertions(+), 44 deletions(-) diff --git a/app/src/main/java/com/x8bit/bitwarden/data/platform/manager/PushManager.kt b/app/src/main/java/com/x8bit/bitwarden/data/platform/manager/PushManager.kt index 15d9d2ee1f..1e5fd65588 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/platform/manager/PushManager.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/platform/manager/PushManager.kt @@ -65,10 +65,17 @@ interface PushManager { val syncSendUpsertFlow: Flow /** - * Handles the necessary steps to take when a push notification with payload [data] is received. + * Handles the necessary steps to take when a push notification with a legacy FCM [data] + * payload is received. */ fun onMessageReceived(data: String) + /** + * Handles the necessary steps to take when a push notification with FCM v1 payload is + * received. + */ + fun onMessageReceived(data: Map) + /** * Registers a [token] for the current user with Bitwarden's server if needed. */ diff --git a/app/src/main/java/com/x8bit/bitwarden/data/platform/manager/PushManagerImpl.kt b/app/src/main/java/com/x8bit/bitwarden/data/platform/manager/PushManagerImpl.kt index 063b483bbb..5420e98232 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/platform/manager/PushManagerImpl.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/platform/manager/PushManagerImpl.kt @@ -106,14 +106,34 @@ class PushManagerImpl @Inject constructor( .launchIn(unconfinedScope) } - @Suppress("LongMethod", "CyclomaticComplexMethod", "ReturnCount") override fun onMessageReceived(data: String) { val notification = try { json.decodeFromString(data) } catch (exception: IllegalArgumentException) { return } + onMessageReceived(notification) + } + @Suppress("ReturnCount") + override fun onMessageReceived(data: Map) { + val type = data["type"] ?: return + val payload = data["payload"] ?: return + val notificationType = try { + json.decodeFromString(string = type) + } catch (exception: IllegalArgumentException) { + return + } + val notification = BitwardenNotification( + contextId = data["contextId"], + notificationType = notificationType, + payload = payload, + ) + onMessageReceived(notification) + } + + @Suppress("LongMethod", "CyclomaticComplexMethod", "ReturnCount") + private fun onMessageReceived(notification: BitwardenNotification) { if (authDiskSource.uniqueAppId == notification.contextId) return val userId = activeUserId ?: return diff --git a/app/src/standard/java/com/x8bit/bitwarden/data/push/BitwardenFirebaseMessagingService.kt b/app/src/standard/java/com/x8bit/bitwarden/data/push/BitwardenFirebaseMessagingService.kt index 3af9758c75..e75b7ec591 100644 --- a/app/src/standard/java/com/x8bit/bitwarden/data/push/BitwardenFirebaseMessagingService.kt +++ b/app/src/standard/java/com/x8bit/bitwarden/data/push/BitwardenFirebaseMessagingService.kt @@ -17,8 +17,10 @@ class BitwardenFirebaseMessagingService : FirebaseMessagingService() { lateinit var pushManager: PushManager override fun onMessageReceived(message: RemoteMessage) { - val data = message.data["data"] ?: return - pushManager.onMessageReceived(data) + message + .data["data"] + ?.let { pushManager.onMessageReceived(it) } + ?: pushManager.onMessageReceived(message.data) } override fun onNewToken(token: String) { diff --git a/app/src/test/java/com/x8bit/bitwarden/data/platform/manager/PushManagerTest.kt b/app/src/test/java/com/x8bit/bitwarden/data/platform/manager/PushManagerTest.kt index 0cb56e5461..c9e1e04387 100644 --- a/app/src/test/java/com/x8bit/bitwarden/data/platform/manager/PushManagerTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/data/platform/manager/PushManagerTest.kt @@ -82,12 +82,17 @@ class PushManagerTest { } @Test - fun `onMessageReceived invalid JSON does not crash`() { + fun `onMessageReceived json invalid JSON does not crash`() { pushManager.onMessageReceived(INVALID_NOTIFICATION_JSON) } @Test - fun `onMessageReceived auth request emits to passwordlessRequestFlow`() = runTest { + fun `onMessageReceived map invalid JSON does not crash`() { + pushManager.onMessageReceived(INVALID_NOTIFICATION_MAP) + } + + @Test + fun `onMessageReceived json auth request emits to passwordlessRequestFlow`() = runTest { pushManager.passwordlessRequestFlow.test { pushManager.onMessageReceived(AUTH_REQUEST_NOTIFICATION_JSON) assertEquals( @@ -101,9 +106,9 @@ class PushManagerTest { } @Test - fun `onMessageReceived auth request response emits to passwordlessRequestFlow`() = runTest { + fun `onMessageReceived map auth request emits to passwordlessRequestFlow`() = runTest { pushManager.passwordlessRequestFlow.test { - pushManager.onMessageReceived(AUTH_REQUEST_RESPONSE_NOTIFICATION_JSON) + pushManager.onMessageReceived(AUTH_REQUEST_NOTIFICATION_MAP) assertEquals( PasswordlessRequestData( loginRequestId = "aab5cdcc-f4a7-4e65-bf6d-5e0eab052321", @@ -115,7 +120,37 @@ class PushManagerTest { } @Test - fun `onMessageReceived logout should emit to logoutFlow`() = runTest { + fun `onMessageReceived json auth request response emits to passwordlessRequestFlow`() = + runTest { + pushManager.passwordlessRequestFlow.test { + pushManager.onMessageReceived(AUTH_REQUEST_RESPONSE_NOTIFICATION_JSON) + assertEquals( + PasswordlessRequestData( + loginRequestId = "aab5cdcc-f4a7-4e65-bf6d-5e0eab052321", + userId = "078966a2-93c2-4618-ae2a-0a2394c88d37", + ), + awaitItem(), + ) + } + } + + @Test + fun `onMessageReceived map auth request response emits to passwordlessRequestFlow`() = + runTest { + pushManager.passwordlessRequestFlow.test { + pushManager.onMessageReceived(AUTH_REQUEST_RESPONSE_NOTIFICATION_MAP) + assertEquals( + PasswordlessRequestData( + loginRequestId = "aab5cdcc-f4a7-4e65-bf6d-5e0eab052321", + userId = "078966a2-93c2-4618-ae2a-0a2394c88d37", + ), + awaitItem(), + ) + } + } + + @Test + fun `onMessageReceived json logout should emit to logoutFlow`() = runTest { val accountTokens = AccountTokensJson( accessToken = "accessToken", refreshToken = "refreshToken", @@ -132,6 +167,24 @@ class PushManagerTest { } } + @Test + fun `onMessageReceived map logout should emit to logoutFlow`() = runTest { + val accountTokens = AccountTokensJson( + accessToken = "accessToken", + refreshToken = "refreshToken", + ) + authDiskSource.storeAccountTokens(userId, accountTokens) + authDiskSource.userState = UserStateJson(userId, mapOf(userId to mockk())) + + pushManager.logoutFlow.test { + pushManager.onMessageReceived(LOGOUT_NOTIFICATION_MAP) + assertEquals( + NotificationLogoutData(userId = "078966a2-93c2-4618-ae2a-0a2394c88d37"), + awaitItem(), + ) + } + } + @Nested inner class LoggedOutUserState { @BeforeEach @@ -143,7 +196,7 @@ class PushManagerTest { } @Test - fun `onMessageReceived logout emits to logoutFlow`() = runTest { + fun `onMessageReceived json logout emits to logoutFlow`() = runTest { pushManager.logoutFlow.test { pushManager.onMessageReceived(LOGOUT_NOTIFICATION_JSON) assertEquals( @@ -154,7 +207,18 @@ class PushManagerTest { } @Test - fun `onMessageReceived sync ciphers emits to fullSyncFlow`() = runTest { + fun `onMessageReceived map logout emits to logoutFlow`() = runTest { + pushManager.logoutFlow.test { + pushManager.onMessageReceived(LOGOUT_NOTIFICATION_MAP) + assertEquals( + NotificationLogoutData(userId = "078966a2-93c2-4618-ae2a-0a2394c88d37"), + awaitItem(), + ) + } + } + + @Test + fun `onMessageReceived json sync ciphers emits to fullSyncFlow`() = runTest { pushManager.fullSyncFlow.test { pushManager.onMessageReceived(SYNC_CIPHERS_NOTIFICATION_JSON) assertEquals( @@ -165,7 +229,18 @@ class PushManagerTest { } @Test - fun `onMessageReceived sync org keys does nothing`() = runTest { + fun `onMessageReceived map ciphers emits to fullSyncFlow`() = runTest { + pushManager.fullSyncFlow.test { + pushManager.onMessageReceived(SYNC_CIPHERS_NOTIFICATION_MAP) + assertEquals( + Unit, + awaitItem(), + ) + } + } + + @Test + fun `onMessageReceived json sync org keys does nothing`() = runTest { pushManager.fullSyncFlow.test { pushManager.onMessageReceived(SYNC_ORG_KEYS_NOTIFICATION_JSON) expectNoEvents() @@ -173,7 +248,15 @@ class PushManagerTest { } @Test - fun `onMessageReceived sync settings emits to fullSyncFlow`() = runTest { + fun `onMessageReceived map sync org keys does nothing`() = runTest { + pushManager.fullSyncFlow.test { + pushManager.onMessageReceived(SYNC_ORG_KEYS_NOTIFICATION_MAP) + expectNoEvents() + } + } + + @Test + fun `onMessageReceived json sync settings emits to fullSyncFlow`() = runTest { pushManager.fullSyncFlow.test { pushManager.onMessageReceived(SYNC_SETTINGS_NOTIFICATION_JSON) assertEquals( @@ -184,7 +267,18 @@ class PushManagerTest { } @Test - fun `onMessageReceived sync vault emits to fullSyncFlow`() = runTest { + fun `onMessageReceived map sync settings emits to fullSyncFlow`() = runTest { + pushManager.fullSyncFlow.test { + pushManager.onMessageReceived(SYNC_SETTINGS_NOTIFICATION_MAP) + assertEquals( + Unit, + awaitItem(), + ) + } + } + + @Test + fun `onMessageReceived json sync vault emits to fullSyncFlow`() = runTest { pushManager.fullSyncFlow.test { pushManager.onMessageReceived(SYNC_VAULT_NOTIFICATION_JSON) assertEquals( @@ -193,6 +287,17 @@ class PushManagerTest { ) } } + + @Test + fun `onMessageReceived map vault emits to fullSyncFlow`() = runTest { + pushManager.fullSyncFlow.test { + pushManager.onMessageReceived(SYNC_VAULT_NOTIFICATION_MAP) + assertEquals( + Unit, + awaitItem(), + ) + } + } } @Nested @@ -210,7 +315,7 @@ class PushManagerTest { } @Test - fun `onMessageReceived sync cipher create emits to syncCipherUpsertFlow`() = + fun `onMessageReceived json sync cipher create emits to syncCipherUpsertFlow`() = runTest { pushManager.syncCipherUpsertFlow.test { pushManager.onMessageReceived(SYNC_CIPHER_CREATE_NOTIFICATION_JSON) @@ -228,7 +333,25 @@ class PushManagerTest { } @Test - fun `onMessageReceived sync cipher delete emits to syncCipherDeleteFlow`() = + fun `onMessageReceived map sync cipher create emits to syncCipherUpsertFlow`() = + runTest { + pushManager.syncCipherUpsertFlow.test { + pushManager.onMessageReceived(SYNC_CIPHER_CREATE_NOTIFICATION_MAP) + assertEquals( + SyncCipherUpsertData( + cipherId = "aab5cdcc-f4a7-4e65-bf6d-5e0eab052321", + organizationId = "6a41d965-ed95-4eae-98c3-5f1ec609c2c1", + collectionIds = listOf(), + revisionDate = ZonedDateTime.parse("2023-10-27T12:00:00.000Z"), + isUpdate = false, + ), + awaitItem(), + ) + } + } + + @Test + fun `onMessageReceived json sync cipher delete emits to syncCipherDeleteFlow`() = runTest { pushManager.syncCipherDeleteFlow.test { pushManager.onMessageReceived(SYNC_CIPHER_DELETE_NOTIFICATION_JSON) @@ -242,7 +365,21 @@ class PushManagerTest { } @Test - fun `onMessageReceived sync cipher update emits to syncCipherUpsertFlow`() = + fun `onMessageReceived map sync cipher delete emits to syncCipherDeleteFlow`() = + runTest { + pushManager.syncCipherDeleteFlow.test { + pushManager.onMessageReceived(SYNC_CIPHER_DELETE_NOTIFICATION_MAP) + assertEquals( + SyncCipherDeleteData( + cipherId = "aab5cdcc-f4a7-4e65-bf6d-5e0eab052321", + ), + awaitItem(), + ) + } + } + + @Test + fun `onMessageReceived json sync cipher update emits to syncCipherUpsertFlow`() = runTest { pushManager.syncCipherUpsertFlow.test { pushManager.onMessageReceived(SYNC_CIPHER_UPDATE_NOTIFICATION_JSON) @@ -260,7 +397,25 @@ class PushManagerTest { } @Test - fun `onMessageReceived sync folder create emits to syncFolderUpsertFlow`() = + fun `onMessageReceived map sync cipher update emits to syncCipherUpsertFlow`() = + runTest { + pushManager.syncCipherUpsertFlow.test { + pushManager.onMessageReceived(SYNC_CIPHER_UPDATE_NOTIFICATION_MAP) + assertEquals( + SyncCipherUpsertData( + cipherId = "aab5cdcc-f4a7-4e65-bf6d-5e0eab052321", + organizationId = "6a41d965-ed95-4eae-98c3-5f1ec609c2c1", + collectionIds = listOf(), + revisionDate = ZonedDateTime.parse("2023-10-27T12:00:00.000Z"), + isUpdate = true, + ), + awaitItem(), + ) + } + } + + @Test + fun `onMessageReceived json sync folder create emits to syncFolderUpsertFlow`() = runTest { pushManager.syncFolderUpsertFlow.test { pushManager.onMessageReceived(SYNC_FOLDER_CREATE_NOTIFICATION_JSON) @@ -276,7 +431,23 @@ class PushManagerTest { } @Test - fun `onMessageReceived sync folder delete emits to syncFolderDeleteFlow`() = + fun `onMessageReceived map sync folder create emits to syncFolderUpsertFlow`() = + runTest { + pushManager.syncFolderUpsertFlow.test { + pushManager.onMessageReceived(SYNC_FOLDER_CREATE_NOTIFICATION_MAP) + assertEquals( + SyncFolderUpsertData( + folderId = "aab5cdcc-f4a7-4e65-bf6d-5e0eab052321", + revisionDate = ZonedDateTime.parse("2023-10-27T12:00:00.000Z"), + isUpdate = false, + ), + awaitItem(), + ) + } + } + + @Test + fun `onMessageReceived json sync folder delete emits to syncFolderDeleteFlow`() = runTest { pushManager.syncFolderDeleteFlow.test { pushManager.onMessageReceived(SYNC_FOLDER_DELETE_NOTIFICATION_JSON) @@ -290,7 +461,21 @@ class PushManagerTest { } @Test - fun `onMessageReceived sync folder update emits to syncFolderUpsertFlow`() = + fun `onMessageReceived map sync folder delete emits to syncFolderDeleteFlow`() = + runTest { + pushManager.syncFolderDeleteFlow.test { + pushManager.onMessageReceived(SYNC_FOLDER_DELETE_NOTIFICATION_MAP) + assertEquals( + SyncFolderDeleteData( + folderId = "aab5cdcc-f4a7-4e65-bf6d-5e0eab052321", + ), + awaitItem(), + ) + } + } + + @Test + fun `onMessageReceived json sync folder update emits to syncFolderUpsertFlow`() = runTest { pushManager.syncFolderUpsertFlow.test { pushManager.onMessageReceived(SYNC_FOLDER_UPDATE_NOTIFICATION_JSON) @@ -306,7 +491,23 @@ class PushManagerTest { } @Test - fun `onMessageReceived sync login delete emits to syncCipherDeleteFlow`() = + fun `onMessageReceived map sync folder update emits to syncFolderUpsertFlow`() = + runTest { + pushManager.syncFolderUpsertFlow.test { + pushManager.onMessageReceived(SYNC_FOLDER_UPDATE_NOTIFICATION_MAP) + assertEquals( + SyncFolderUpsertData( + folderId = "aab5cdcc-f4a7-4e65-bf6d-5e0eab052321", + revisionDate = ZonedDateTime.parse("2023-10-27T12:00:00.000Z"), + isUpdate = true, + ), + awaitItem(), + ) + } + } + + @Test + fun `onMessageReceived json sync login delete emits to syncCipherDeleteFlow`() = runTest { pushManager.syncCipherDeleteFlow.test { pushManager.onMessageReceived(SYNC_LOGIN_DELETE_NOTIFICATION_JSON) @@ -320,7 +521,21 @@ class PushManagerTest { } @Test - fun `onMessageReceived sync send create emits to syncSendUpsertFlow`() = + fun `onMessageReceived map sync login delete emits to syncCipherDeleteFlow`() = + runTest { + pushManager.syncCipherDeleteFlow.test { + pushManager.onMessageReceived(SYNC_LOGIN_DELETE_NOTIFICATION_MAP) + assertEquals( + SyncCipherDeleteData( + cipherId = "aab5cdcc-f4a7-4e65-bf6d-5e0eab052321", + ), + awaitItem(), + ) + } + } + + @Test + fun `onMessageReceived json sync send create emits to syncSendUpsertFlow`() = runTest { pushManager.syncSendUpsertFlow.test { pushManager.onMessageReceived(SYNC_SEND_CREATE_NOTIFICATION_JSON) @@ -336,7 +551,22 @@ class PushManagerTest { } @Test - fun `onMessageReceived sync send delete emits to syncSendDeleteFlow`() = + fun `onMessageReceived map sync send create emits to syncSendUpsertFlow`() = runTest { + pushManager.syncSendUpsertFlow.test { + pushManager.onMessageReceived(SYNC_SEND_CREATE_NOTIFICATION_MAP) + assertEquals( + SyncSendUpsertData( + sendId = "aab5cdcc-f4a7-4e65-bf6d-5e0eab052321", + revisionDate = ZonedDateTime.parse("2023-10-27T12:00:00.000Z"), + isUpdate = false, + ), + awaitItem(), + ) + } + } + + @Test + fun `onMessageReceived json sync send delete emits to syncSendDeleteFlow`() = runTest { pushManager.syncSendDeleteFlow.test { pushManager.onMessageReceived(SYNC_SEND_DELETE_NOTIFICATION_JSON) @@ -350,7 +580,20 @@ class PushManagerTest { } @Test - fun `onMessageReceived sync send update emits to syncSendUpsertFlow`() = + fun `onMessageReceived map sync send delete emits to syncSendDeleteFlow`() = runTest { + pushManager.syncSendDeleteFlow.test { + pushManager.onMessageReceived(SYNC_SEND_DELETE_NOTIFICATION_MAP) + assertEquals( + SyncSendDeleteData( + sendId = "aab5cdcc-f4a7-4e65-bf6d-5e0eab052321", + ), + awaitItem(), + ) + } + } + + @Test + fun `onMessageReceived json sync send update emits to syncSendUpsertFlow`() = runTest { pushManager.syncSendUpsertFlow.test { pushManager.onMessageReceived(SYNC_SEND_UPDATE_NOTIFICATION_JSON) @@ -364,6 +607,21 @@ class PushManagerTest { ) } } + + @Test + fun `onMessageReceived map sync send update emits to syncSendUpsertFlow`() = runTest { + pushManager.syncSendUpsertFlow.test { + pushManager.onMessageReceived(SYNC_SEND_UPDATE_NOTIFICATION_MAP) + assertEquals( + SyncSendUpsertData( + sendId = "aab5cdcc-f4a7-4e65-bf6d-5e0eab052321", + revisionDate = ZonedDateTime.parse("2023-10-27T12:00:00.000Z"), + isUpdate = true, + ), + awaitItem(), + ) + } + } } @Nested @@ -381,7 +639,7 @@ class PushManagerTest { } @Test - fun `onMessageReceived sync cipher create does nothing`() = runTest { + fun `onMessageReceived json sync cipher create does nothing`() = runTest { pushManager.syncCipherUpsertFlow.test { pushManager.onMessageReceived(SYNC_CIPHER_CREATE_NOTIFICATION_JSON) expectNoEvents() @@ -389,7 +647,15 @@ class PushManagerTest { } @Test - fun `onMessageReceived sync cipher delete does nothing`() = runTest { + fun `onMessageReceived map sync cipher create does nothing`() = runTest { + pushManager.syncCipherUpsertFlow.test { + pushManager.onMessageReceived(SYNC_CIPHER_CREATE_NOTIFICATION_MAP) + expectNoEvents() + } + } + + @Test + fun `onMessageReceived json sync cipher delete does nothing`() = runTest { pushManager.syncCipherDeleteFlow.test { pushManager.onMessageReceived(SYNC_CIPHER_DELETE_NOTIFICATION_JSON) expectNoEvents() @@ -397,7 +663,15 @@ class PushManagerTest { } @Test - fun `onMessageReceived sync cipher update does nothing`() = runTest { + fun `onMessageReceived map sync cipher delete does nothing`() = runTest { + pushManager.syncCipherDeleteFlow.test { + pushManager.onMessageReceived(SYNC_CIPHER_DELETE_NOTIFICATION_MAP) + expectNoEvents() + } + } + + @Test + fun `onMessageReceived json sync cipher update does nothing`() = runTest { pushManager.syncCipherUpsertFlow.test { pushManager.onMessageReceived(SYNC_CIPHER_UPDATE_NOTIFICATION_JSON) expectNoEvents() @@ -405,7 +679,15 @@ class PushManagerTest { } @Test - fun `onMessageReceived sync folder create does nothing`() = runTest { + fun `onMessageReceived map sync cipher update does nothing`() = runTest { + pushManager.syncCipherUpsertFlow.test { + pushManager.onMessageReceived(SYNC_CIPHER_UPDATE_NOTIFICATION_MAP) + expectNoEvents() + } + } + + @Test + fun `onMessageReceived json sync folder create does nothing`() = runTest { pushManager.syncFolderUpsertFlow.test { pushManager.onMessageReceived(SYNC_FOLDER_CREATE_NOTIFICATION_JSON) expectNoEvents() @@ -413,7 +695,15 @@ class PushManagerTest { } @Test - fun `onMessageReceived sync folder delete does nothing`() = runTest { + fun `onMessageReceived map sync folder create does nothing`() = runTest { + pushManager.syncFolderUpsertFlow.test { + pushManager.onMessageReceived(SYNC_FOLDER_CREATE_NOTIFICATION_MAP) + expectNoEvents() + } + } + + @Test + fun `onMessageReceived json sync folder delete does nothing`() = runTest { pushManager.syncFolderDeleteFlow.test { pushManager.onMessageReceived(SYNC_FOLDER_DELETE_NOTIFICATION_JSON) expectNoEvents() @@ -421,7 +711,15 @@ class PushManagerTest { } @Test - fun `onMessageReceived sync folder update does nothing`() = runTest { + fun `onMessageReceived map sync folder delete does nothing`() = runTest { + pushManager.syncFolderDeleteFlow.test { + pushManager.onMessageReceived(SYNC_FOLDER_DELETE_NOTIFICATION_MAP) + expectNoEvents() + } + } + + @Test + fun `onMessageReceived json sync folder update does nothing`() = runTest { pushManager.syncFolderDeleteFlow.test { pushManager.onMessageReceived(SYNC_FOLDER_UPDATE_NOTIFICATION_JSON) expectNoEvents() @@ -429,7 +727,15 @@ class PushManagerTest { } @Test - fun `onMessageReceived sync login delete does nothing`() = runTest { + fun `onMessageReceived map sync folder update does nothing`() = runTest { + pushManager.syncFolderDeleteFlow.test { + pushManager.onMessageReceived(SYNC_FOLDER_UPDATE_NOTIFICATION_MAP) + expectNoEvents() + } + } + + @Test + fun `onMessageReceived json sync login delete does nothing`() = runTest { pushManager.syncCipherDeleteFlow.test { pushManager.onMessageReceived(SYNC_LOGIN_DELETE_NOTIFICATION_JSON) expectNoEvents() @@ -437,7 +743,15 @@ class PushManagerTest { } @Test - fun `onMessageReceived sync send create does nothing`() = runTest { + fun `onMessageReceived map sync login delete does nothing`() = runTest { + pushManager.syncCipherDeleteFlow.test { + pushManager.onMessageReceived(SYNC_LOGIN_DELETE_NOTIFICATION_MAP) + expectNoEvents() + } + } + + @Test + fun `onMessageReceived json sync send create does nothing`() = runTest { pushManager.syncSendUpsertFlow.test { pushManager.onMessageReceived(SYNC_SEND_CREATE_NOTIFICATION_JSON) expectNoEvents() @@ -445,7 +759,15 @@ class PushManagerTest { } @Test - fun `onMessageReceived sync send delete does nothing`() = runTest { + fun `onMessageReceived map sync send create does nothing`() = runTest { + pushManager.syncSendUpsertFlow.test { + pushManager.onMessageReceived(SYNC_SEND_CREATE_NOTIFICATION_MAP) + expectNoEvents() + } + } + + @Test + fun `onMessageReceived json sync send delete does nothing`() = runTest { pushManager.syncSendDeleteFlow.test { pushManager.onMessageReceived(SYNC_SEND_DELETE_NOTIFICATION_JSON) expectNoEvents() @@ -453,12 +775,28 @@ class PushManagerTest { } @Test - fun `onMessageReceived sync send update does nothing`() = runTest { + fun `onMessageReceived map sync send delete does nothing`() = runTest { + pushManager.syncSendDeleteFlow.test { + pushManager.onMessageReceived(SYNC_SEND_DELETE_NOTIFICATION_MAP) + expectNoEvents() + } + } + + @Test + fun `onMessageReceived json sync send update does nothing`() = runTest { pushManager.syncSendUpsertFlow.test { pushManager.onMessageReceived(SYNC_SEND_UPDATE_NOTIFICATION_JSON) expectNoEvents() } } + + @Test + fun `onMessageReceived map sync send update does nothing`() = runTest { + pushManager.syncSendUpsertFlow.test { + pushManager.onMessageReceived(SYNC_SEND_UPDATE_NOTIFICATION_MAP) + expectNoEvents() + } + } } @Nested @@ -469,7 +807,7 @@ class PushManagerTest { } @Test - fun `onMessageReceived logout does nothing`() = runTest { + fun `onMessageReceived json logout does nothing`() = runTest { pushManager.logoutFlow.test { pushManager.onMessageReceived(LOGOUT_NOTIFICATION_JSON) expectNoEvents() @@ -477,7 +815,15 @@ class PushManagerTest { } @Test - fun `onMessageReceived sync ciphers does nothing`() = runTest { + fun `onMessageReceived map logout does nothing`() = runTest { + pushManager.logoutFlow.test { + pushManager.onMessageReceived(LOGOUT_NOTIFICATION_MAP) + expectNoEvents() + } + } + + @Test + fun `onMessageReceived json sync ciphers does nothing`() = runTest { pushManager.fullSyncFlow.test { pushManager.onMessageReceived(SYNC_CIPHERS_NOTIFICATION_JSON) expectNoEvents() @@ -485,7 +831,15 @@ class PushManagerTest { } @Test - fun `onMessageReceived sync org keys does nothing`() = runTest { + fun `onMessageReceived map sync ciphers does nothing`() = runTest { + pushManager.fullSyncFlow.test { + pushManager.onMessageReceived(SYNC_CIPHERS_NOTIFICATION_MAP) + expectNoEvents() + } + } + + @Test + fun `onMessageReceived json sync org keys does nothing`() = runTest { pushManager.fullSyncFlow.test { pushManager.onMessageReceived(SYNC_ORG_KEYS_NOTIFICATION_JSON) expectNoEvents() @@ -493,7 +847,15 @@ class PushManagerTest { } @Test - fun `onMessageReceived sync settings does nothing`() = runTest { + fun `onMessageReceived map sync org keys does nothing`() = runTest { + pushManager.fullSyncFlow.test { + pushManager.onMessageReceived(SYNC_ORG_KEYS_NOTIFICATION_MAP) + expectNoEvents() + } + } + + @Test + fun `onMessageReceived json sync settings does nothing`() = runTest { pushManager.fullSyncFlow.test { pushManager.onMessageReceived(SYNC_SETTINGS_NOTIFICATION_JSON) expectNoEvents() @@ -501,12 +863,28 @@ class PushManagerTest { } @Test - fun `onMessageReceived sync vault does nothing`() = runTest { + fun `onMessageReceived map sync settings does nothing`() = runTest { + pushManager.fullSyncFlow.test { + pushManager.onMessageReceived(SYNC_SETTINGS_NOTIFICATION_MAP) + expectNoEvents() + } + } + + @Test + fun `onMessageReceived json sync vault does nothing`() = runTest { pushManager.fullSyncFlow.test { pushManager.onMessageReceived(SYNC_VAULT_NOTIFICATION_JSON) expectNoEvents() } } + + @Test + fun `onMessageReceived map sync vault does nothing`() = runTest { + pushManager.fullSyncFlow.test { + pushManager.onMessageReceived(SYNC_VAULT_NOTIFICATION_MAP) + expectNoEvents() + } + } } @Nested @@ -524,7 +902,7 @@ class PushManagerTest { } @Test - fun `onMessageReceived logout emits to logoutFlow`() = runTest { + fun `onMessageReceived json logout emits to logoutFlow`() = runTest { pushManager.logoutFlow.test { pushManager.onMessageReceived(LOGOUT_NOTIFICATION_JSON) assertEquals( @@ -535,7 +913,18 @@ class PushManagerTest { } @Test - fun `onMessageReceived sync ciphers emits to fullSyncFlow`() = runTest { + fun `onMessageReceived map logout emits to logoutFlow`() = runTest { + pushManager.logoutFlow.test { + pushManager.onMessageReceived(LOGOUT_NOTIFICATION_MAP) + assertEquals( + NotificationLogoutData(userId = "078966a2-93c2-4618-ae2a-0a2394c88d37"), + awaitItem(), + ) + } + } + + @Test + fun `onMessageReceived json sync ciphers emits to fullSyncFlow`() = runTest { pushManager.fullSyncFlow.test { pushManager.onMessageReceived(SYNC_CIPHERS_NOTIFICATION_JSON) assertEquals( @@ -546,7 +935,18 @@ class PushManagerTest { } @Test - fun `onMessageReceived sync org keys emits to syncOrgKeysFlow`() = runTest { + fun `onMessageReceived map sync ciphers emits to fullSyncFlow`() = runTest { + pushManager.fullSyncFlow.test { + pushManager.onMessageReceived(SYNC_CIPHERS_NOTIFICATION_MAP) + assertEquals( + Unit, + awaitItem(), + ) + } + } + + @Test + fun `onMessageReceived json sync org keys emits to syncOrgKeysFlow`() = runTest { pushManager.syncOrgKeysFlow.test { pushManager.onMessageReceived(SYNC_ORG_KEYS_NOTIFICATION_JSON) assertEquals( @@ -557,7 +957,18 @@ class PushManagerTest { } @Test - fun `onMessageReceived sync settings emits to fullSyncFlow`() = runTest { + fun `onMessageReceived map sync org keys emits to syncOrgKeysFlow`() = runTest { + pushManager.syncOrgKeysFlow.test { + pushManager.onMessageReceived(SYNC_ORG_KEYS_NOTIFICATION_MAP) + assertEquals( + Unit, + awaitItem(), + ) + } + } + + @Test + fun `onMessageReceived json sync settings emits to fullSyncFlow`() = runTest { pushManager.fullSyncFlow.test { pushManager.onMessageReceived(SYNC_SETTINGS_NOTIFICATION_JSON) assertEquals( @@ -568,7 +979,18 @@ class PushManagerTest { } @Test - fun `onMessageReceived sync vault emits to fullSyncFlow`() = runTest { + fun `onMessageReceived map sync settings emits to fullSyncFlow`() = runTest { + pushManager.fullSyncFlow.test { + pushManager.onMessageReceived(SYNC_SETTINGS_NOTIFICATION_MAP) + assertEquals( + Unit, + awaitItem(), + ) + } + } + + @Test + fun `onMessageReceived json sync vault emits to fullSyncFlow`() = runTest { pushManager.fullSyncFlow.test { pushManager.onMessageReceived(SYNC_VAULT_NOTIFICATION_JSON) assertEquals( @@ -577,6 +999,17 @@ class PushManagerTest { ) } } + + @Test + fun `onMessageReceived map sync vault emits to fullSyncFlow`() = runTest { + pushManager.fullSyncFlow.test { + pushManager.onMessageReceived(SYNC_VAULT_NOTIFICATION_MAP) + assertEquals( + Unit, + awaitItem(), + ) + } + } } } @@ -806,6 +1239,15 @@ private const val AUTH_REQUEST_NOTIFICATION_JSON = """ } """ +private val AUTH_REQUEST_NOTIFICATION_MAP = mapOf( + "contextId" to "801f459d-8e51-47d0-b072-3f18c9f66f64", + "type" to "15", + "payload" to """{ + "Id": "aab5cdcc-f4a7-4e65-bf6d-5e0eab052321", + "UserId": "078966a2-93c2-4618-ae2a-0a2394c88d37" + }""", +) + private const val AUTH_REQUEST_RESPONSE_NOTIFICATION_JSON = """ { "contextId": "801f459d-8e51-47d0-b072-3f18c9f66f64", @@ -817,10 +1259,21 @@ private const val AUTH_REQUEST_RESPONSE_NOTIFICATION_JSON = """ } """ +private val AUTH_REQUEST_RESPONSE_NOTIFICATION_MAP = mapOf( + "contextId" to "801f459d-8e51-47d0-b072-3f18c9f66f64", + "type" to "16", + "payload" to """{ + "Id": "aab5cdcc-f4a7-4e65-bf6d-5e0eab052321", + "UserId": "078966a2-93c2-4618-ae2a-0a2394c88d37" + }""", +) + private const val INVALID_NOTIFICATION_JSON = """ {} """ +private val INVALID_NOTIFICATION_MAP = emptyMap() + private const val LOGOUT_NOTIFICATION_JSON = """ { "contextId": "801f459d-8e51-47d0-b072-3f18c9f66f64", @@ -832,6 +1285,15 @@ private const val LOGOUT_NOTIFICATION_JSON = """ } """ +private val LOGOUT_NOTIFICATION_MAP = mapOf( + "contextId" to "801f459d-8e51-47d0-b072-3f18c9f66f64", + "type" to "11", + "payload" to """{ + "UserId": "078966a2-93c2-4618-ae2a-0a2394c88d37", + "Date": "2023-10-27T12:00:00.000Z" + }""", +) + private const val SYNC_CIPHER_CREATE_NOTIFICATION_JSON = """ { "contextId": "801f459d-8e51-47d0-b072-3f18c9f66f64", @@ -846,6 +1308,18 @@ private const val SYNC_CIPHER_CREATE_NOTIFICATION_JSON = """ } """ +private val SYNC_CIPHER_CREATE_NOTIFICATION_MAP = mapOf( + "contextId" to "801f459d-8e51-47d0-b072-3f18c9f66f64", + "type" to "1", + "payload" to """{ + "Id": "aab5cdcc-f4a7-4e65-bf6d-5e0eab052321", + "UserId": "078966a2-93c2-4618-ae2a-0a2394c88d37", + "OrganizationId": "6a41d965-ed95-4eae-98c3-5f1ec609c2c1", + "CollectionIds": [], + "RevisionDate": "2023-10-27T12:00:00.000Z" + }""", +) + private const val SYNC_CIPHER_DELETE_NOTIFICATION_JSON = """ { "contextId": "801f459d-8e51-47d0-b072-3f18c9f66f64", @@ -860,6 +1334,18 @@ private const val SYNC_CIPHER_DELETE_NOTIFICATION_JSON = """ } """ +private val SYNC_CIPHER_DELETE_NOTIFICATION_MAP = mapOf( + "contextId" to "801f459d-8e51-47d0-b072-3f18c9f66f64", + "type" to "9", + "payload" to """{ + "Id": "aab5cdcc-f4a7-4e65-bf6d-5e0eab052321", + "UserId": "078966a2-93c2-4618-ae2a-0a2394c88d37", + "OrganizationId": "6a41d965-ed95-4eae-98c3-5f1ec609c2c1", + "CollectionIds": [], + "RevisionDate": "2023-10-27T12:00:00.000Z" + }""", +) + private const val SYNC_CIPHER_UPDATE_NOTIFICATION_JSON = """ { "contextId": "801f459d-8e51-47d0-b072-3f18c9f66f64", @@ -874,6 +1360,18 @@ private const val SYNC_CIPHER_UPDATE_NOTIFICATION_JSON = """ } """ +private val SYNC_CIPHER_UPDATE_NOTIFICATION_MAP = mapOf( + "contextId" to "801f459d-8e51-47d0-b072-3f18c9f66f64", + "type" to "0", + "payload" to """{ + "Id": "aab5cdcc-f4a7-4e65-bf6d-5e0eab052321", + "UserId": "078966a2-93c2-4618-ae2a-0a2394c88d37", + "OrganizationId": "6a41d965-ed95-4eae-98c3-5f1ec609c2c1", + "CollectionIds": [], + "RevisionDate": "2023-10-27T12:00:00.000Z" + }""", +) + private const val SYNC_CIPHERS_NOTIFICATION_JSON = """ { "contextId": "801f459d-8e51-47d0-b072-3f18c9f66f64", @@ -885,6 +1383,15 @@ private const val SYNC_CIPHERS_NOTIFICATION_JSON = """ } """ +private val SYNC_CIPHERS_NOTIFICATION_MAP = mapOf( + "contextId" to "801f459d-8e51-47d0-b072-3f18c9f66f64", + "type" to "4", + "payload" to """{ + "UserId": "078966a2-93c2-4618-ae2a-0a2394c88d37", + "RevisionDate": "2023-10-27T12:00:00.000Z" + }""", +) + private const val SYNC_FOLDER_CREATE_NOTIFICATION_JSON = """ { "contextId": "801f459d-8e51-47d0-b072-3f18c9f66f64", @@ -897,6 +1404,16 @@ private const val SYNC_FOLDER_CREATE_NOTIFICATION_JSON = """ } """ +private val SYNC_FOLDER_CREATE_NOTIFICATION_MAP = mapOf( + "contextId" to "801f459d-8e51-47d0-b072-3f18c9f66f64", + "type" to "7", + "payload" to """{ + "Id": "aab5cdcc-f4a7-4e65-bf6d-5e0eab052321", + "UserId": "078966a2-93c2-4618-ae2a-0a2394c88d37", + "RevisionDate": "2023-10-27T12:00:00.000Z" + }""", +) + private const val SYNC_FOLDER_DELETE_NOTIFICATION_JSON = """ { "contextId": "801f459d-8e51-47d0-b072-3f18c9f66f64", @@ -909,6 +1426,16 @@ private const val SYNC_FOLDER_DELETE_NOTIFICATION_JSON = """ } """ +private val SYNC_FOLDER_DELETE_NOTIFICATION_MAP = mapOf( + "contextId" to "801f459d-8e51-47d0-b072-3f18c9f66f64", + "type" to "3", + "payload" to """{ + "Id": "aab5cdcc-f4a7-4e65-bf6d-5e0eab052321", + "UserId": "078966a2-93c2-4618-ae2a-0a2394c88d37", + "RevisionDate": "2023-10-27T12:00:00.000Z" + }""", +) + private const val SYNC_FOLDER_UPDATE_NOTIFICATION_JSON = """ { "contextId": "801f459d-8e51-47d0-b072-3f18c9f66f64", @@ -921,6 +1448,16 @@ private const val SYNC_FOLDER_UPDATE_NOTIFICATION_JSON = """ } """ +private val SYNC_FOLDER_UPDATE_NOTIFICATION_MAP = mapOf( + "contextId" to "801f459d-8e51-47d0-b072-3f18c9f66f64", + "type" to "8", + "payload" to """{ + "Id": "aab5cdcc-f4a7-4e65-bf6d-5e0eab052321", + "UserId": "078966a2-93c2-4618-ae2a-0a2394c88d37", + "RevisionDate": "2023-10-27T12:00:00.000Z" + }""", +) + private const val SYNC_LOGIN_DELETE_NOTIFICATION_JSON = """ { "contextId": "801f459d-8e51-47d0-b072-3f18c9f66f64", @@ -935,6 +1472,18 @@ private const val SYNC_LOGIN_DELETE_NOTIFICATION_JSON = """ } """ +private val SYNC_LOGIN_DELETE_NOTIFICATION_MAP = mapOf( + "contextId" to "801f459d-8e51-47d0-b072-3f18c9f66f64", + "type" to "2", + "payload" to """{ + "Id": "aab5cdcc-f4a7-4e65-bf6d-5e0eab052321", + "UserId": "078966a2-93c2-4618-ae2a-0a2394c88d37", + "OrganizationId": "6a41d965-ed95-4eae-98c3-5f1ec609c2c1", + "CollectionIds": [], + "RevisionDate": "2023-10-27T12:00:00.000Z" + }""", +) + private const val SYNC_ORG_KEYS_NOTIFICATION_JSON = """ { "contextId": "801f459d-8e51-47d0-b072-3f18c9f66f64", @@ -946,6 +1495,15 @@ private const val SYNC_ORG_KEYS_NOTIFICATION_JSON = """ } """ +private val SYNC_ORG_KEYS_NOTIFICATION_MAP = mapOf( + "contextId" to "801f459d-8e51-47d0-b072-3f18c9f66f64", + "type" to "6", + "payload" to """{ + "UserId": "078966a2-93c2-4618-ae2a-0a2394c88d37", + "Date": "2023-10-27T12:00:00.000Z" + }""", +) + private const val SYNC_SEND_CREATE_NOTIFICATION_JSON = """ { "contextId": "801f459d-8e51-47d0-b072-3f18c9f66f64", @@ -958,6 +1516,16 @@ private const val SYNC_SEND_CREATE_NOTIFICATION_JSON = """ } """ +private val SYNC_SEND_CREATE_NOTIFICATION_MAP = mapOf( + "contextId" to "801f459d-8e51-47d0-b072-3f18c9f66f64", + "type" to "12", + "payload" to """{ + "Id": "aab5cdcc-f4a7-4e65-bf6d-5e0eab052321", + "UserId": "078966a2-93c2-4618-ae2a-0a2394c88d37", + "RevisionDate": "2023-10-27T12:00:00.000Z" + }""", +) + private const val SYNC_SEND_DELETE_NOTIFICATION_JSON = """ { "contextId": "801f459d-8e51-47d0-b072-3f18c9f66f64", @@ -970,6 +1538,16 @@ private const val SYNC_SEND_DELETE_NOTIFICATION_JSON = """ } """ +private val SYNC_SEND_DELETE_NOTIFICATION_MAP = mapOf( + "contextId" to "801f459d-8e51-47d0-b072-3f18c9f66f64", + "type" to "14", + "payload" to """{ + "Id": "aab5cdcc-f4a7-4e65-bf6d-5e0eab052321", + "UserId": "078966a2-93c2-4618-ae2a-0a2394c88d37", + "RevisionDate": "2023-10-27T12:00:00.000Z" + }""", +) + private const val SYNC_SEND_UPDATE_NOTIFICATION_JSON = """ { "contextId": "801f459d-8e51-47d0-b072-3f18c9f66f64", @@ -982,6 +1560,16 @@ private const val SYNC_SEND_UPDATE_NOTIFICATION_JSON = """ } """ +private val SYNC_SEND_UPDATE_NOTIFICATION_MAP = mapOf( + "contextId" to "801f459d-8e51-47d0-b072-3f18c9f66f64", + "type" to "13", + "payload" to """{ + "Id": "aab5cdcc-f4a7-4e65-bf6d-5e0eab052321", + "UserId": "078966a2-93c2-4618-ae2a-0a2394c88d37", + "RevisionDate": "2023-10-27T12:00:00.000Z" + }""", +) + private const val SYNC_SETTINGS_NOTIFICATION_JSON = """ { "contextId": "801f459d-8e51-47d0-b072-3f18c9f66f64", @@ -993,6 +1581,15 @@ private const val SYNC_SETTINGS_NOTIFICATION_JSON = """ } """ +private val SYNC_SETTINGS_NOTIFICATION_MAP = mapOf( + "contextId" to "801f459d-8e51-47d0-b072-3f18c9f66f64", + "type" to "10", + "payload" to """{ + "UserId": "078966a2-93c2-4618-ae2a-0a2394c88d37", + "Date": "2023-10-27T12:00:00.000Z" + }""", +) + private const val SYNC_VAULT_NOTIFICATION_JSON = """ { "contextId": "801f459d-8e51-47d0-b072-3f18c9f66f64", @@ -1003,3 +1600,12 @@ private const val SYNC_VAULT_NOTIFICATION_JSON = """ }" } """ + +private val SYNC_VAULT_NOTIFICATION_MAP = mapOf( + "contextId" to "801f459d-8e51-47d0-b072-3f18c9f66f64", + "type" to "5", + "payload" to """{ + "UserId": "078966a2-93c2-4618-ae2a-0a2394c88d37", + "Date": "2023-10-27T12:00:00.000Z" + }""", +)