Skip to content

Commit 53dccfc

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

File tree

5 files changed

+117
-0
lines changed

5 files changed

+117
-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,25 @@
1+
package com.onesignal.user.internal.migrations
2+
3+
import com.onesignal.debug.internal.logging.Logging
4+
5+
open class MigrationRecovery : IMigrationRecovery {
6+
override fun isInBadState(): Boolean {
7+
return false
8+
}
9+
10+
override fun recover() {
11+
// left blank intentionally
12+
}
13+
14+
override fun recoveryMessage(): String {
15+
return ""
16+
}
17+
18+
override fun start() {
19+
// log a message and take the corrective action if it is determined that app is in a bad state
20+
if (isInBadState()) {
21+
Logging.warn(recoveryMessage())
22+
recover()
23+
}
24+
}
25+
}
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,42 @@
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+
import io.mockk.spyk
14+
15+
class MigrationRecoveryTests : FunSpec({
16+
beforeAny {
17+
Logging.logLevel = LogLevel.NONE
18+
}
19+
20+
test("ensure RecoverConfigPushSubscription adds the missing push sub ID") {
21+
// Given
22+
val configModelStore = MockHelper.configModelStore()
23+
val mockSubscriptionModelStore = mockk<SubscriptionModelStore>()
24+
val recovery = RecoverConfigPushSubscription(configModelStore, mockSubscriptionModelStore)
25+
26+
// Set up config model store with null push subscription ID
27+
val configModel = configModelStore.model
28+
configModel.pushSubscriptionId = null
29+
30+
// Add a push subscription
31+
val pushSubscription = SubscriptionModel()
32+
pushSubscription.type = SubscriptionType.PUSH
33+
pushSubscription.id = "0"
34+
every { mockSubscriptionModelStore.list() } returns listOf(pushSubscription)
35+
36+
// When
37+
recovery.start()
38+
39+
// Then
40+
configModelStore.model.pushSubscriptionId shouldBe "0"
41+
}
42+
})

0 commit comments

Comments
 (0)