Skip to content

Commit 05fd286

Browse files
committed
fix: missing push sub ID by a new recovery
1 parent 84dab24 commit 05fd286

File tree

5 files changed

+104
-0
lines changed

5 files changed

+104
-0
lines changed

OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/UserModule.kt

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import com.onesignal.user.internal.backend.impl.UserBackendService
1717
import com.onesignal.user.internal.builduser.IRebuildUserService
1818
import com.onesignal.user.internal.builduser.impl.RebuildUserService
1919
import com.onesignal.user.internal.identity.IdentityModelStore
20+
import com.onesignal.user.internal.migrations.RecoverConfigPushSubscription
2021
import com.onesignal.user.internal.migrations.RecoverFromDroppedLoginBug
2122
import com.onesignal.user.internal.operations.impl.executors.IdentityOperationExecutor
2223
import com.onesignal.user.internal.operations.impl.executors.LoginUserFromSubscriptionOperationExecutor
@@ -74,6 +75,7 @@ internal class UserModule : IModule {
7475
builder.register<UserRefreshService>().provides<IStartableService>()
7576

7677
builder.register<RecoverFromDroppedLoginBug>().provides<IStartableService>()
78+
builder.register<RecoverConfigPushSubscription>().provides<IStartableService>()
7779

7880
// Shared state between Executors
7981
builder.register<NewRecordsState>().provides<NewRecordsState>()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.onesignal.user.internal.migrations
2+
3+
import com.onesignal.core.internal.startup.IStartableService
4+
5+
/**
6+
* Purpose: allow to identify and take corrective action for some specific bad states during migration
7+
*
8+
* Implement these properties to:
9+
* - isInBadState(): return true the condition for the bad state has met
10+
* - recover(): take a recovery action if the bad state has been identified
11+
* - recoveryMessage: log a message after the bad state is found and the corrective action is taken
12+
*/
13+
interface IMigrationRecovery : IStartableService {
14+
fun isInBadState(): Boolean
15+
16+
fun recover()
17+
18+
fun recoveryMessage(): String
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.onesignal.user.internal.migrations
2+
3+
import com.onesignal.debug.internal.logging.Logging
4+
5+
abstract class MigrationRecovery : IMigrationRecovery {
6+
override fun start() {
7+
// log a message and take the corrective action if it is determined that app is in a bad state
8+
if (isInBadState()) {
9+
Logging.warn(recoveryMessage())
10+
recover()
11+
}
12+
}
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.onesignal.user.internal.migrations
2+
3+
import com.onesignal.core.internal.config.ConfigModelStore
4+
import com.onesignal.user.internal.subscriptions.SubscriptionModelStore
5+
import com.onesignal.user.internal.subscriptions.SubscriptionType
6+
7+
/**
8+
* Purpose: Automatically recovers a missing push sub ID in the config model store due
9+
* to a bug migrating from the SDK 5.2.0-beta
10+
*/
11+
class RecoverConfigPushSubscription(
12+
private val _configModelStore: ConfigModelStore,
13+
private val _subscriptionModelStore: SubscriptionModelStore,
14+
) : MigrationRecovery() {
15+
val activePushSubscription by lazy { _subscriptionModelStore.list().firstOrNull { it.type == SubscriptionType.PUSH } }
16+
17+
override fun isInBadState(): Boolean {
18+
val isPushSubIdMissing = _configModelStore.model.pushSubscriptionId == null
19+
return isPushSubIdMissing && activePushSubscription != null
20+
}
21+
22+
override fun recover() {
23+
_configModelStore.model.pushSubscriptionId = activePushSubscription?.id
24+
}
25+
26+
override fun recoveryMessage(): String {
27+
return "Recovering missing push subscription ID in the config model store."
28+
}
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package com.onesignal.user.internal.migrations
2+
3+
import com.onesignal.debug.LogLevel
4+
import com.onesignal.debug.internal.logging.Logging
5+
import com.onesignal.mocks.MockHelper
6+
import com.onesignal.user.internal.subscriptions.SubscriptionModel
7+
import com.onesignal.user.internal.subscriptions.SubscriptionModelStore
8+
import com.onesignal.user.internal.subscriptions.SubscriptionType
9+
import io.kotest.core.spec.style.FunSpec
10+
import io.kotest.matchers.shouldBe
11+
import io.mockk.every
12+
import io.mockk.mockk
13+
14+
class MigrationRecoveryTests : FunSpec({
15+
beforeAny {
16+
Logging.logLevel = LogLevel.NONE
17+
}
18+
19+
test("ensure RecoverConfigPushSubscription adds the missing push sub ID") {
20+
// Given
21+
val configModelStore = MockHelper.configModelStore()
22+
val mockSubscriptionModelStore = mockk<SubscriptionModelStore>()
23+
val recovery = RecoverConfigPushSubscription(configModelStore, mockSubscriptionModelStore)
24+
25+
// Set up config model store with null push subscription ID
26+
val configModel = configModelStore.model
27+
configModel.pushSubscriptionId = null
28+
29+
// Add a push subscription
30+
val pushSubscription = SubscriptionModel()
31+
pushSubscription.type = SubscriptionType.PUSH
32+
pushSubscription.id = "0"
33+
every { mockSubscriptionModelStore.list() } returns listOf(pushSubscription)
34+
35+
// When
36+
recovery.start()
37+
38+
// Then
39+
configModelStore.model.pushSubscriptionId shouldBe "0"
40+
}
41+
})

0 commit comments

Comments
 (0)