Disable periodic sync workers that don't exist anymore (#602)

* Disable old periodic worker when renaming accounts

* Periodic sync worker now disables itself when an account is not available anymore

* Add test
This commit is contained in:
Ricki Hirner 2024-02-28 13:38:45 +01:00 committed by GitHub
parent 86742f5b18
commit 334fdb5953
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 43 additions and 2 deletions

View file

@ -24,7 +24,6 @@ import at.bitfire.davdroid.ui.NotificationUtils
import at.bitfire.ical4android.TaskProvider
import dagger.hilt.android.testing.HiltAndroidRule
import dagger.hilt.android.testing.HiltAndroidTest
import org.junit.After
import org.junit.AfterClass
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
@ -97,6 +96,28 @@ class PeriodicSyncWorkerTest {
assertFalse(workScheduledOrRunning(context, workerName))
}
@Test
fun doWork_cancelsItselfOnInvalidAccount() {
val invalidAccount = Account("invalid", context.getString(R.string.account_type))
val authority = CalendarContract.AUTHORITY
// Enable the PeriodicSyncWorker
PeriodicSyncWorker.enable(context, invalidAccount, authority, 15*60, false)
assertTrue(workScheduledOrRunning(context, PeriodicSyncWorker.workerName(account, authority)))
// Run PeriodicSyncWorker as TestWorker
val inputData = workDataOf(
PeriodicSyncWorker.ARG_AUTHORITY to authority,
PeriodicSyncWorker.ARG_ACCOUNT_NAME to invalidAccount.name,
PeriodicSyncWorker.ARG_ACCOUNT_TYPE to invalidAccount.type
)
val result = TestWorkerBuilder<PeriodicSyncWorker>(context, executor, inputData).build().doWork()
// Verify that the PeriodicSyncWorker cancelled itself
assertTrue(result is androidx.work.ListenableWorker.Result.Failure)
assertFalse(workScheduledOrRunning(context, PeriodicSyncWorker.workerName(invalidAccount, authority)))
}
@Test
fun doWork_immediatelyEnqueuesSyncWorkerForGivenAuthority() {
val authorities = listOf(

View file

@ -17,6 +17,7 @@ import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager
import androidx.work.Worker
import androidx.work.WorkerParameters
import at.bitfire.davdroid.InvalidAccountException
import at.bitfire.davdroid.log.Logger
import at.bitfire.davdroid.settings.AccountSettings
import dagger.assisted.Assisted
@ -117,7 +118,13 @@ class PeriodicSyncWorker @AssistedInject constructor(
val authority = inputData.getString(ARG_AUTHORITY) ?: throw IllegalArgumentException("$ARG_AUTHORITY required")
Logger.log.info("Running periodic sync worker: account=$account, authority=$authority")
val accountSettings = AccountSettings(applicationContext, account)
val accountSettings = try {
AccountSettings(applicationContext, account)
} catch (e: InvalidAccountException) {
Logger.log.warning("Account $account doesn't exist anymore, cancelling periodic sync")
disable(applicationContext, account, authority)
return Result.failure()
}
if (!SyncWorker.wifiConditionsMet(applicationContext, accountSettings)) {
Logger.log.info("Sync conditions not met. Won't run sync.")
return Result.failure()

View file

@ -49,6 +49,7 @@ import at.bitfire.davdroid.resource.LocalAddressBook
import at.bitfire.davdroid.resource.LocalTaskList
import at.bitfire.davdroid.settings.AccountSettings
import at.bitfire.davdroid.syncadapter.AccountsCleanupWorker
import at.bitfire.davdroid.syncadapter.PeriodicSyncWorker
import at.bitfire.davdroid.syncadapter.SyncWorker
import at.bitfire.ical4android.TaskProvider
import com.google.accompanist.themeadapter.material.MdcTheme
@ -207,6 +208,13 @@ class RenameAccountFragment: DialogFragment() {
}
}
/**
* Called when an account has been renamed.
*
* @param oldAccount the old account
* @param newName the new account
* @param syncIntervals map with entries of type (authority -> sync interval) of the old account
*/
@SuppressLint("Recycle")
@WorkerThread
fun onAccountRenamed(accountManager: AccountManager, oldAccount: Account, newName: String, syncIntervals: List<Pair<String, Long?>>) {
@ -214,6 +222,11 @@ class RenameAccountFragment: DialogFragment() {
Logger.log.info("Updating account name references")
val context: Application = getApplication()
// disable periodic workers of old account
syncIntervals.forEach { (authority, _) ->
PeriodicSyncWorker.disable(context, oldAccount, authority)
}
// cancel maybe running synchronization
SyncWorker.cancelSync(context, oldAccount)
for (addrBookAccount in accountManager.getAccountsByType(context.getString(R.string.account_type_address_book)))