Skip to content

Commit 50c9e1f

Browse files
committed
add: test cases for create user subscription mapping
1 parent e266904 commit 50c9e1f

File tree

1 file changed

+120
-0
lines changed

1 file changed

+120
-0
lines changed

OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/operations/LoginUserOperationExecutorTests.kt

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -739,4 +739,124 @@ class LoginUserOperationExecutorTests : FunSpec({
739739
exactly = 0,
740740
) { mockUserBackendService.createUser(appId, any(), any(), any()) }
741741
}
742+
743+
test("create user maps subscriptions when backend order is different (match by id/token)") {
744+
// Given
745+
val mockUserBackendService = mockk<IUserBackendService>()
746+
// backend returns EMAIL first (with token), then PUSH — out of order
747+
coEvery { mockUserBackendService.createUser(any(), any(), any(), any()) } returns
748+
CreateUserResponse(
749+
mapOf(IdentityConstants.ONESIGNAL_ID to remoteOneSignalId),
750+
PropertiesObject(),
751+
listOf(
752+
SubscriptionObject(id = remoteSubscriptionId2, type = SubscriptionObjectType.EMAIL, token = "name@company.com"),
753+
SubscriptionObject(id = remoteSubscriptionId1, type = SubscriptionObjectType.ANDROID_PUSH, token = "pushToken2"),
754+
),
755+
)
756+
757+
val mockIdentityOperationExecutor = mockk<IdentityOperationExecutor>()
758+
val mockIdentityModelStore = MockHelper.identityModelStore()
759+
val mockPropertiesModelStore = MockHelper.propertiesModelStore()
760+
val mockSubscriptionsModelStore = mockk<SubscriptionModelStore>()
761+
every { mockSubscriptionsModelStore.get(any()) } returns null
762+
763+
val executor =
764+
LoginUserOperationExecutor(
765+
mockIdentityOperationExecutor,
766+
AndroidMockHelper.applicationService(),
767+
MockHelper.deviceService(),
768+
mockUserBackendService,
769+
mockIdentityModelStore,
770+
mockPropertiesModelStore,
771+
mockSubscriptionsModelStore,
772+
MockHelper.configModelStore(),
773+
MockHelper.languageContext(),
774+
)
775+
776+
// send PUSH then EMAIL (local IDs 1,2) — order differs from backend response
777+
val ops =
778+
listOf(
779+
LoginUserOperation(appId, localOneSignalId, null, null),
780+
CreateSubscriptionOperation(appId, localOneSignalId, localSubscriptionId1, SubscriptionType.PUSH, true, "pushToken2", SubscriptionStatus.SUBSCRIBED),
781+
CreateSubscriptionOperation(appId, localOneSignalId, localSubscriptionId2, SubscriptionType.EMAIL, true, "name@company.com", SubscriptionStatus.SUBSCRIBED),
782+
)
783+
784+
// When
785+
val response = executor.execute(ops)
786+
787+
// Then
788+
response.result shouldBe ExecutionResult.SUCCESS
789+
// ensure local to remote mapping is correct despite different order
790+
response.idTranslations shouldBe
791+
mapOf(
792+
localOneSignalId to remoteOneSignalId,
793+
// push
794+
localSubscriptionId1 to remoteSubscriptionId1,
795+
// email
796+
localSubscriptionId2 to remoteSubscriptionId2,
797+
)
798+
coVerify(exactly = 1) { mockUserBackendService.createUser(appId, mapOf(), any(), any()) }
799+
}
800+
801+
test("create user maps push subscription by type when id and token don't match (case for deleted push sub)") {
802+
// Given
803+
val mockUserBackendService = mockk<IUserBackendService>()
804+
// simulate server-side push sub recreated with new ID and no token; must match by type
805+
coEvery { mockUserBackendService.createUser(any(), any(), any(), any()) } returns
806+
CreateUserResponse(
807+
mapOf(IdentityConstants.ONESIGNAL_ID to remoteOneSignalId),
808+
PropertiesObject(),
809+
listOf(
810+
SubscriptionObject(id = remoteSubscriptionId1, type = SubscriptionObjectType.ANDROID_PUSH, token = null),
811+
),
812+
)
813+
814+
val mockIdentityOperationExecutor = mockk<IdentityOperationExecutor>()
815+
val mockIdentityModelStore = MockHelper.identityModelStore()
816+
val mockPropertiesModelStore = MockHelper.propertiesModelStore()
817+
818+
val mockSubscriptionsModelStore = mockk<SubscriptionModelStore>()
819+
// provide a local push model so the executor can hydrate its id
820+
val localPushModel = SubscriptionModel().apply { id = localSubscriptionId1 }
821+
every { mockSubscriptionsModelStore.get(localSubscriptionId1) } returns localPushModel
822+
823+
val configModelStore = MockHelper.configModelStore()
824+
// assume current push sub is the local one we are creating
825+
configModelStore.model.pushSubscriptionId = localSubscriptionId1
826+
827+
val executor =
828+
LoginUserOperationExecutor(
829+
mockIdentityOperationExecutor,
830+
AndroidMockHelper.applicationService(),
831+
MockHelper.deviceService(),
832+
mockUserBackendService,
833+
mockIdentityModelStore,
834+
mockPropertiesModelStore,
835+
mockSubscriptionsModelStore,
836+
configModelStore,
837+
MockHelper.languageContext(),
838+
)
839+
840+
val ops =
841+
listOf(
842+
LoginUserOperation(appId, localOneSignalId, null, null),
843+
CreateSubscriptionOperation(appId, localOneSignalId, localSubscriptionId1, SubscriptionType.PUSH, true, "pushToken1", SubscriptionStatus.SUBSCRIBED),
844+
)
845+
846+
// When
847+
val response = executor.execute(ops)
848+
849+
// Then
850+
response.result shouldBe ExecutionResult.SUCCESS
851+
// should map by type and update both idTranslations and local model
852+
response.idTranslations shouldBe
853+
mapOf(
854+
localOneSignalId to remoteOneSignalId,
855+
localSubscriptionId1 to remoteSubscriptionId1,
856+
)
857+
localPushModel.id shouldBe remoteSubscriptionId1
858+
// pushSubscriptionId should be updated from local to remote id
859+
configModelStore.model.pushSubscriptionId shouldBe remoteSubscriptionId1
860+
coVerify(exactly = 1) { mockUserBackendService.createUser(appId, mapOf(), any(), any()) }
861+
}
742862
})

0 commit comments

Comments
 (0)