Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weโ€™ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PM-15087] Update the device push token every 7 days #4386

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,15 @@ import kotlinx.serialization.json.Json
import java.time.Clock
import java.time.ZoneOffset
import java.time.ZonedDateTime
import java.time.temporal.ChronoUnit
import javax.inject.Inject
import kotlin.time.Duration
import kotlin.time.Duration.Companion.days
import kotlin.time.toJavaDuration

/**
* The amount of time to delay before updating the push token against Bitwarden server.
*/
private val PUSH_TOKEN_UPDATE_DELAY: Duration = 7.days

/**
* Primary implementation of [PushManager].
Expand Down Expand Up @@ -279,11 +286,6 @@ class PushManagerImpl @Inject constructor(
val userId = activeUserId ?: return
if (!isLoggedIn(userId)) return

// If the last registered token is from less than a day before, skip this for now
val lastRegistration = pushDiskSource.getLastPushTokenRegistrationDate(userId)?.toInstant()
val dayBefore = clock.instant().minus(1, ChronoUnit.DAYS)
if (lastRegistration?.isAfter(dayBefore) == true) return

ioScope.launch {
pushDiskSource.registeredPushToken?.let {
registerPushTokenIfNecessaryInternal(
Expand All @@ -296,14 +298,11 @@ class PushManagerImpl @Inject constructor(

private suspend fun registerPushTokenIfNecessaryInternal(userId: String, token: String) {
val currentToken = pushDiskSource.getCurrentPushToken(userId)

if (token == currentToken) {
// Our token is up-to-date, so just update the last registration date
pushDiskSource.storeLastPushTokenRegistrationDate(
userId = userId,
registrationDate = ZonedDateTime.ofInstant(clock.instant(), ZoneOffset.UTC),
)
return
val lastRegistration =
pushDiskSource.getLastPushTokenRegistrationDate(userId)?.toInstant() ?: return
val updateTime = clock.instant().minus(PUSH_TOKEN_UPDATE_DELAY.toJavaDuration())
if (updateTime.isBefore(lastRegistration)) return
}

pushService
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ class PushManagerTest {

private val pushDiskSource: PushDiskSource = PushDiskSourceImpl(FakeSharedPreferences())

private val pushService: PushService = mockk()
private val pushService: PushService = mockk {
coEvery { putDeviceToken(any()) } returns Unit.asSuccess()
}

private lateinit var pushManager: PushManager

Expand Down Expand Up @@ -650,56 +652,102 @@ class PushManagerTest {
authDiskSource.userState = UserStateJson(userId, mapOf(userId to account))
}

@Suppress("MaxLineLength")
@Test
fun `registerStoredPushTokenIfNecessary should do nothing if registered less than a day before`() {
val lastRegistration = ZonedDateTime.ofInstant(
clock.instant().minus(23, ChronoUnit.HOURS),
ZoneOffset.UTC,
)
pushDiskSource.registeredPushToken = existingToken
pushDiskSource.storeLastPushTokenRegistrationDate(
userId,
lastRegistration,
)
pushManager.registerStoredPushTokenIfNecessary()

// Assert the last registration value has not changed
assertEquals(
lastRegistration.toEpochSecond(),
pushDiskSource.getLastPushTokenRegistrationDate(userId)!!.toEpochSecond(),
)
}

@Nested
inner class MatchingToken {
private val newToken = "existingToken"
private val newToken = existingToken

@Suppress("MaxLineLength")
@Test
fun `registerPushTokenIfNecessary should update registeredPushToken and lastPushTokenRegistrationDate`() {
fun `registerPushTokenIfNecessary should do nothing if registered less than 7 days before`() {
val lastRegistration = ZonedDateTime.ofInstant(
clock.instant().minus(6, ChronoUnit.DAYS).minus(23, ChronoUnit.HOURS),
ZoneOffset.UTC,
)
pushDiskSource.storeLastPushTokenRegistrationDate(
userId,
lastRegistration,
)
pushManager.registerPushTokenIfNecessary(newToken)

coVerify(exactly = 0) { pushService.putDeviceToken(any()) }
assertEquals(newToken, pushDiskSource.registeredPushToken)
// Assert the last registration value has not changed
assertEquals(
clock.instant().epochSecond,
pushDiskSource.getLastPushTokenRegistrationDate(userId)?.toEpochSecond(),
lastRegistration.toEpochSecond(),
pushDiskSource.getLastPushTokenRegistrationDate(userId)!!.toEpochSecond(),
)
}

@Suppress("MaxLineLength")
@Test
fun `registerStoredPushTokenIfNecessary should update registeredPushToken and lastPushTokenRegistrationDate`() {
fun `registerStoredPushTokenIfNecessary should do nothing if registered less than 7 days before`() {
val lastRegistration = ZonedDateTime.ofInstant(
clock.instant().minus(6, ChronoUnit.DAYS).minus(23, ChronoUnit.HOURS),
ZoneOffset.UTC,
)
pushDiskSource.registeredPushToken = newToken
pushDiskSource.storeLastPushTokenRegistrationDate(
userId,
lastRegistration,
)
pushManager.registerStoredPushTokenIfNecessary()

coVerify(exactly = 0) { pushService.putDeviceToken(any()) }
assertEquals(newToken, pushDiskSource.registeredPushToken)
// Assert the last registration value has not changed
assertEquals(
lastRegistration.toEpochSecond(),
pushDiskSource.getLastPushTokenRegistrationDate(userId)!!.toEpochSecond(),
)
}

@Suppress("MaxLineLength")
@Test
fun `registerPushTokenIfNecessary should update registeredPushToken, lastPushTokenRegistrationDate and currentPushToken`() {
val lastRegistration = ZonedDateTime.ofInstant(
clock.instant().minus(8, ChronoUnit.DAYS),
ZoneOffset.UTC,
)
pushDiskSource.storeLastPushTokenRegistrationDate(
userId,
lastRegistration,
)
pushManager.registerPushTokenIfNecessary(newToken)

coVerify(exactly = 1) {
pushService.putDeviceToken(PushTokenRequest(newToken))
}
assertEquals(
clock.instant().epochSecond,
pushDiskSource.getLastPushTokenRegistrationDate(userId)?.toEpochSecond(),
)
assertEquals(newToken, pushDiskSource.registeredPushToken)
assertEquals(newToken, pushDiskSource.getCurrentPushToken(userId))
}

@Suppress("MaxLineLength")
@Test
fun `registerStoredPushTokenIfNecessary should update registeredPushToken, lastPushTokenRegistrationDate and currentPushToken`() {
val lastRegistration = ZonedDateTime.ofInstant(
clock.instant().minus(8, ChronoUnit.DAYS),
ZoneOffset.UTC,
)
pushDiskSource.storeLastPushTokenRegistrationDate(
userId,
lastRegistration,
)
pushDiskSource.registeredPushToken = newToken
pushManager.registerStoredPushTokenIfNecessary()

coVerify(exactly = 1) {
pushService.putDeviceToken(PushTokenRequest(newToken))
}
assertEquals(
clock.instant().epochSecond,
pushDiskSource.getLastPushTokenRegistrationDate(userId)?.toEpochSecond(),
)
assertEquals(newToken, pushDiskSource.registeredPushToken)
assertEquals(newToken, pushDiskSource.getCurrentPushToken(userId))
}
}

Expand Down