Skip to content

Commit

Permalink
Merge branch 'main-ose' into 1031-mkcalendar-send-vtimezone-in-calend…
Browse files Browse the repository at this point in the history
…ar-timezone
  • Loading branch information
rfc2822 authored Oct 7, 2024
2 parents d232d7f + 1ca73b6 commit bd4364a
Show file tree
Hide file tree
Showing 27 changed files with 501 additions and 316 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@ import androidx.work.Configuration
import androidx.work.WorkInfo
import androidx.work.WorkManager
import androidx.work.testing.WorkManagerTestInitHelper
import at.bitfire.davdroid.repository.DavCollectionRepository
import at.bitfire.davdroid.repository.DavServiceRepository
import at.bitfire.davdroid.settings.AccountSettings
import at.bitfire.davdroid.sync.account.TestAccountAuthenticator
import at.bitfire.davdroid.sync.worker.OneTimeSyncWorker
import at.bitfire.davdroid.sync.worker.SyncWorkerManager
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.android.testing.HiltAndroidRule
import dagger.hilt.android.testing.HiltAndroidTest
Expand All @@ -39,21 +42,33 @@ import org.junit.Rule
import org.junit.Test
import org.junit.rules.Timeout
import java.util.concurrent.Executors
import java.util.logging.Logger
import javax.inject.Inject
import javax.inject.Provider
import kotlin.coroutines.cancellation.CancellationException

@HiltAndroidTest
class SyncAdapterServicesTest {

lateinit var account: Account

@Inject
lateinit var accountSettingsFactory: AccountSettings.Factory

@Inject
lateinit var collectionRepository: DavCollectionRepository

@Inject
@ApplicationContext
lateinit var context: Context

@Inject
lateinit var syncAdapterProvider: Provider<SyncAdapterService.SyncAdapter>
lateinit var logger: Logger

@Inject
lateinit var serviceRepository: DavServiceRepository

@Inject
lateinit var syncConditionsFactory: SyncConditions.Factory

@Inject
lateinit var workerFactory: HiltWorkerFactory
Expand Down Expand Up @@ -87,14 +102,29 @@ class SyncAdapterServicesTest {
}


private fun syncAdapter(
syncWorkerManager: SyncWorkerManager
): SyncAdapterService.SyncAdapter =
SyncAdapterService.SyncAdapter(
accountSettingsFactory = accountSettingsFactory,
collectionRepository = collectionRepository,
serviceRepository = serviceRepository,
context = context,
logger = logger,
syncConditionsFactory = syncConditionsFactory,
syncWorkerManager = syncWorkerManager
)


@Test
fun testSyncAdapter_onPerformSync_cancellation() {
val syncAdapter = syncAdapterProvider.get()
val syncWorkerManager = mockk<SyncWorkerManager>()
val syncAdapter = syncAdapter(syncWorkerManager = syncWorkerManager)
val workManager = WorkManager.getInstance(context)

mockkObject(OneTimeSyncWorker, workManager) {
mockkObject(workManager) {
// don't actually create a worker
every { OneTimeSyncWorker.enqueue(any(), any(), any()) } returns "TheSyncWorker"
every { syncWorkerManager.enqueueOneTime(any(), any()) } returns "TheSyncWorker"

// assume worker takes a long time
every { workManager.getWorkInfosForUniqueWorkFlow("TheSyncWorker") } just Awaits
Expand All @@ -115,12 +145,13 @@ class SyncAdapterServicesTest {

@Test
fun testSyncAdapter_onPerformSync_returnsAfterTimeout() {
val syncAdapter = syncAdapterProvider.get()
val syncWorkerManager = mockk<SyncWorkerManager>()
val syncAdapter = syncAdapter(syncWorkerManager = syncWorkerManager)
val workManager = WorkManager.getInstance(context)

mockkObject(OneTimeSyncWorker, workManager) {
mockkObject(workManager) {
// don't actually create a worker
every { OneTimeSyncWorker.enqueue(any(), any(), any()) } returns "TheSyncWorker"
every { syncWorkerManager.enqueueOneTime(any(), any()) } returns "TheSyncWorker"

// assume worker takes a long time
every { workManager.getWorkInfosForUniqueWorkFlow("TheSyncWorker") } just Awaits
Expand All @@ -136,12 +167,13 @@ class SyncAdapterServicesTest {

@Test
fun testSyncAdapter_onPerformSync_runsInTime() {
val syncAdapter = syncAdapterProvider.get()
val syncWorkerManager = mockk<SyncWorkerManager>()
val syncAdapter = syncAdapter(syncWorkerManager = syncWorkerManager)
val workManager = WorkManager.getInstance(context)

mockkObject(OneTimeSyncWorker, workManager) {
mockkObject(workManager) {
// don't actually create a worker
every { OneTimeSyncWorker.enqueue(any(), any(), any()) } returns "TheSyncWorker"
every { syncWorkerManager.enqueueOneTime(any(), any()) } returns "TheSyncWorker"

// assume worker immediately returns with success
val success = mockk<WorkInfo>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class AccountUtilsTest {

val manager = AccountManager.get(context)
try {
assertTrue(AccountUtils.createAccount(context, account, userData))
assertTrue(SystemAccountUtils.createAccount(context, account, userData))

// validate user data
assertEquals("1", manager.getUserData(account, "int"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class TestAccountAuthenticator: Service() {
val accountType = context.getString(R.string.account_type_test)
val account = Account("Test Account", accountType)

assertTrue(AccountUtils.createAccount(context, account, AccountSettings.initialUserData(null)))
assertTrue(SystemAccountUtils.createAccount(context, account, AccountSettings.initialUserData(null)))

return account
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import androidx.work.WorkerParameters
import androidx.work.testing.TestListenableWorkerBuilder
import androidx.work.testing.WorkManagerTestInitHelper
import androidx.work.workDataOf
import at.bitfire.davdroid.TestUtils.workScheduledOrRunning
import at.bitfire.davdroid.sync.account.TestAccountAuthenticator
import at.bitfire.davdroid.test.R
import dagger.hilt.android.qualifiers.ApplicationContext
Expand All @@ -27,7 +26,6 @@ import io.mockk.mockkObject
import io.mockk.verify
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Rule
Expand Down Expand Up @@ -69,21 +67,6 @@ class PeriodicSyncWorkerTest {
}


@Test
fun enable_enqueuesPeriodicWorker() {
PeriodicSyncWorker.enable(context, account, CalendarContract.AUTHORITY, 60, false)
val workerName = PeriodicSyncWorker.workerName(account, CalendarContract.AUTHORITY)
assertTrue(workScheduledOrRunning(context, workerName))
}

@Test
fun disable_removesPeriodicWorker() {
PeriodicSyncWorker.enable(context, account, CalendarContract.AUTHORITY, 60, false)
PeriodicSyncWorker.disable(context, account, CalendarContract.AUTHORITY)
val workerName = PeriodicSyncWorker.workerName(account, CalendarContract.AUTHORITY)
assertFalse(workScheduledOrRunning(context, workerName))
}

@Test
fun doWork_cancelsItselfOnInvalidAccount() {
val invalidAccount = Account("invalid", testContext.getString(R.string.account_type_test))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
*/

package at.bitfire.davdroid.sync.worker

import android.accounts.Account
import android.content.Context
import android.provider.CalendarContract
import android.util.Log
import androidx.hilt.work.HiltWorkerFactory
import androidx.work.Configuration
import androidx.work.testing.WorkManagerTestInitHelper
import at.bitfire.davdroid.TestUtils
import at.bitfire.davdroid.TestUtils.workScheduledOrRunning
import at.bitfire.davdroid.sync.account.TestAccountAuthenticator
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.android.testing.HiltAndroidRule
import dagger.hilt.android.testing.HiltAndroidTest
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import javax.inject.Inject

@HiltAndroidTest
class SyncWorkerManagerTest {

@get:Rule
val hiltRule = HiltAndroidRule(this)

@Inject
@ApplicationContext
lateinit var context: Context

@Inject
lateinit var syncWorkerManager: SyncWorkerManager

@Inject
lateinit var workerFactory: HiltWorkerFactory

lateinit var account: Account

@Before
fun setUp() {
hiltRule.inject()

// Initialize WorkManager for instrumentation tests.
val config = Configuration.Builder()
.setMinimumLoggingLevel(Log.DEBUG)
.setWorkerFactory(workerFactory)
.build()
WorkManagerTestInitHelper.initializeTestWorkManager(context, config)

account = TestAccountAuthenticator.create()
}

@After
fun tearDown() {
TestAccountAuthenticator.remove(account)
}


// one-time sync workers

@Test
fun testEnqueueOneTime() {
val workerName = OneTimeSyncWorker.workerName(account, CalendarContract.AUTHORITY)
assertFalse(TestUtils.workScheduledOrRunningOrSuccessful(context, workerName))

val returnedName = syncWorkerManager.enqueueOneTime(account, CalendarContract.AUTHORITY)
assertEquals(workerName, returnedName)
assertTrue(TestUtils.workScheduledOrRunningOrSuccessful(context, workerName))
}


// periodic sync workers

@Test
fun enablePeriodic() {
syncWorkerManager.enablePeriodic(account, CalendarContract.AUTHORITY, 60, false).result.get()

val workerName = PeriodicSyncWorker.workerName(account, CalendarContract.AUTHORITY)
assertTrue(workScheduledOrRunning(context, workerName))
}

@Test
fun disablePeriodic() {
syncWorkerManager.enablePeriodic(account, CalendarContract.AUTHORITY, 60, false).result.get()
syncWorkerManager.disablePeriodic(account, CalendarContract.AUTHORITY).result.get()

val workerName = PeriodicSyncWorker.workerName(account, CalendarContract.AUTHORITY)
assertFalse(workScheduledOrRunning(context, workerName))
}

}
17 changes: 17 additions & 0 deletions app/src/main/kotlin/at/bitfire/davdroid/db/Collection.kt
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,28 @@ data class Collection(
*/
var url: HttpUrl,

/**
* Whether we have the permission to change contents of the collection on the server.
* Even if this flag is set, there may still be other reasons why a collection is effectively read-only.
*/
var privWriteContent: Boolean = true,
/**
* Whether we have the permission to delete the collection on the server
*/
var privUnbind: Boolean = true,
/**
* Whether the user has manually set the "force read-only" flag.
* Even if this flag is not set, there may still be other reasons why a collection is effectively read-only.
*/
var forceReadOnly: Boolean = false,

/**
* Human-readable name of the collection
*/
var displayName: String? = null,
/**
* Human-readable description of the collection
*/
var description: String? = null,

// CalDAV only
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import at.bitfire.davdroid.repository.AccountRepository
import at.bitfire.davdroid.repository.DavCollectionRepository
import at.bitfire.davdroid.repository.DavServiceRepository
import at.bitfire.davdroid.repository.PreferenceRepository
import at.bitfire.davdroid.sync.worker.OneTimeSyncWorker
import at.bitfire.davdroid.sync.worker.SyncWorkerManager
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
Expand Down Expand Up @@ -40,6 +40,9 @@ class UnifiedPushReceiver: MessagingReceiver() {
@Inject
lateinit var parsePushMessage: PushMessageParser

@Inject
lateinit var syncWorkerManager: SyncWorkerManager


override fun onNewEndpoint(context: Context, endpoint: String, instance: String) {
// remember new endpoint
Expand Down Expand Up @@ -71,14 +74,14 @@ class UnifiedPushReceiver: MessagingReceiver() {
collectionRepository.getSyncableByTopic(topic)?.let { collection ->
serviceRepository.get(collection.serviceId)?.let { service ->
val account = accountRepository.fromName(service.accountName)
OneTimeSyncWorker.enqueueAllAuthorities(context, account)
syncWorkerManager.enqueueOneTimeAllAuthorities(account)
}
}

} else {
logger.warning("Got push message without topic, syncing all accounts")
for (account in accountRepository.getAll())
OneTimeSyncWorker.enqueueAllAuthorities(context, account)
syncWorkerManager.enqueueOneTimeAllAuthorities(account)

}
}
Expand Down
Loading

0 comments on commit bd4364a

Please sign in to comment.