From 01a40c8560f33daba1b1c0fe8597d41ebd671637 Mon Sep 17 00:00:00 2001 From: Lukas Lechner <lukas.lechner@sap.com> Date: Tue, 4 May 2021 12:35:18 +0200 Subject: [PATCH] Refactor Contact Diary Work Scheduler (DEV) (#3026) * Refactor ContactDiaryWorkScheduler.kt to our new way of scheduling work * Remove ContactDiaryWorkScheduler dependency from MainActivity.kt --- .../coronawarnapp/CoronaWarnApplication.kt | 7 ++-- .../retention/ContactDiaryWorkScheduler.kt | 23 +++++++++++-- .../rki/coronawarnapp/ui/main/MainActivity.kt | 3 -- .../ContactDiaryWorkSchedulerTest.kt | 34 +++++++++++++++---- 4 files changed, 50 insertions(+), 17 deletions(-) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/CoronaWarnApplication.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/CoronaWarnApplication.kt index b0c270e62..3767a49ea 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/CoronaWarnApplication.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/CoronaWarnApplication.kt @@ -31,7 +31,6 @@ import de.rki.coronawarnapp.presencetracing.risk.execution.PresenceTracingRiskWo import de.rki.coronawarnapp.presencetracing.storage.retention.TraceLocationDbCleanUpScheduler import de.rki.coronawarnapp.risk.RiskLevelChangeDetector import de.rki.coronawarnapp.risk.execution.ExposureWindowRiskWorkScheduler -import de.rki.coronawarnapp.storage.OnboardingSettings import de.rki.coronawarnapp.submission.auto.AutoSubmission import de.rki.coronawarnapp.task.TaskController import de.rki.coronawarnapp.util.CWADebug @@ -68,7 +67,6 @@ class CoronaWarnApplication : Application(), HasAndroidInjector { @Inject lateinit var deviceTimeHandler: DeviceTimeHandler @Inject lateinit var autoSubmission: AutoSubmission @Inject lateinit var coronaTestRepository: CoronaTestRepository - @Inject lateinit var onboardingSettings: OnboardingSettings @Inject lateinit var autoCheckOut: AutoCheckOut @Inject lateinit var traceLocationDbCleanupScheduler: TraceLocationDbCleanUpScheduler @Inject lateinit var shareTestResultNotificationService: ShareTestResultNotificationService @@ -111,9 +109,8 @@ class CoronaWarnApplication : Application(), HasAndroidInjector { .onEach { isAppInForeground = it } .launchIn(GlobalScope) - if (onboardingSettings.isOnboarded) { - contactDiaryWorkScheduler.schedulePeriodic() - } + Timber.v("Setting up contact diary work scheduler") + contactDiaryWorkScheduler.setup() Timber.v("Setting up deadman notification scheduler") deadmanNotificationScheduler.setup() diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/retention/ContactDiaryWorkScheduler.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/retention/ContactDiaryWorkScheduler.kt index 15bbc81bd..4e6c7aff3 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/retention/ContactDiaryWorkScheduler.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/contactdiary/retention/ContactDiaryWorkScheduler.kt @@ -1,22 +1,39 @@ package de.rki.coronawarnapp.contactdiary.retention +import androidx.annotation.VisibleForTesting import androidx.work.ExistingPeriodicWorkPolicy import androidx.work.WorkManager import dagger.Reusable +import de.rki.coronawarnapp.storage.OnboardingSettings +import de.rki.coronawarnapp.util.coroutine.AppScope +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import timber.log.Timber import javax.inject.Inject @Reusable class ContactDiaryWorkScheduler @Inject constructor( - val workManager: WorkManager, - private val workBuilder: ContactDiaryWorkBuilder + @AppScope val appScope: CoroutineScope, + private val workManager: WorkManager, + private val workBuilder: ContactDiaryWorkBuilder, + private val onboardingSettings: OnboardingSettings ) { + fun setup() { + onboardingSettings.isOnboardedFlow.onEach { isOnboarded -> + if (isOnboarded) { + schedulePeriodic() + } + }.launchIn(appScope) + } + /** * Enqueue background contact diary clean periodic worker * Replace with new if older work exists. */ - fun schedulePeriodic() { + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + internal fun schedulePeriodic() { Timber.d("ContactDiaryWorkScheduler schedulePeriodic()") // Create unique work and enqueue workManager.enqueueUniquePeriodicWork( diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivity.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivity.kt index 09f6ce0b1..4c29cfed0 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivity.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/main/MainActivity.kt @@ -18,7 +18,6 @@ import dagger.android.DispatchingAndroidInjector import dagger.android.HasAndroidInjector import de.rki.coronawarnapp.NavGraphDirections import de.rki.coronawarnapp.R -import de.rki.coronawarnapp.contactdiary.retention.ContactDiaryWorkScheduler import de.rki.coronawarnapp.contactdiary.ui.overview.ContactDiaryOverviewFragmentDirections import de.rki.coronawarnapp.databinding.ActivityMainBinding import de.rki.coronawarnapp.datadonation.analytics.worker.DataDonationAnalyticsScheduler @@ -75,7 +74,6 @@ class MainActivity : AppCompatActivity(), HasAndroidInjector { private val navController by lazy { supportFragmentManager.findNavController(R.id.nav_host_fragment) } @Inject lateinit var powerManagement: PowerManagement - @Inject lateinit var contactDiaryWorkScheduler: ContactDiaryWorkScheduler @Inject lateinit var dataDonationAnalyticsScheduler: DataDonationAnalyticsScheduler override fun onCreate(savedInstanceState: Bundle?) { @@ -193,7 +191,6 @@ class MainActivity : AppCompatActivity(), HasAndroidInjector { override fun onResume() { super.onResume() vm.doBackgroundNoiseCheck() - contactDiaryWorkScheduler.schedulePeriodic() dataDonationAnalyticsScheduler.schedulePeriodic() } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/contactdiary/retention/ContactDiaryWorkSchedulerTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/contactdiary/retention/ContactDiaryWorkSchedulerTest.kt index 0bd5a76f4..573679b16 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/contactdiary/retention/ContactDiaryWorkSchedulerTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/contactdiary/retention/ContactDiaryWorkSchedulerTest.kt @@ -4,13 +4,18 @@ import androidx.work.ExistingPeriodicWorkPolicy import androidx.work.Operation import androidx.work.PeriodicWorkRequest import androidx.work.WorkManager +import de.rki.coronawarnapp.storage.OnboardingSettings import io.mockk.MockKAnnotations import io.mockk.every import io.mockk.impl.annotations.MockK -import io.mockk.verifySequence +import io.mockk.verify +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.test.runBlockingTest import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import testhelpers.BaseTest +import testhelpers.coroutines.runBlockingTest2 class ContactDiaryWorkSchedulerTest : BaseTest() { @@ -18,6 +23,7 @@ class ContactDiaryWorkSchedulerTest : BaseTest() { @MockK lateinit var operation: Operation @MockK lateinit var workBuilder: ContactDiaryWorkBuilder @MockK lateinit var periodicWorkRequest: PeriodicWorkRequest + @MockK lateinit var onBoardingSettings: OnboardingSettings @BeforeEach fun setup() { @@ -32,16 +38,32 @@ class ContactDiaryWorkSchedulerTest : BaseTest() { } returns operation } - private fun createScheduler() = ContactDiaryWorkScheduler( + private fun createScheduler(scope: CoroutineScope) = ContactDiaryWorkScheduler( + appScope = scope, workManager = workManager, - workBuilder = workBuilder + workBuilder = workBuilder, + onboardingSettings = onBoardingSettings ) @Test - fun `test periodic work was scheduled`() { - createScheduler().schedulePeriodic() + fun `test periodic work was scheduled`() = runBlockingTest { + createScheduler(this).schedulePeriodic() + verifyIfWorkWasScheduled() + } + + @Test + fun `periodic work should be scheduled after onboaring`() = runBlockingTest2(ignoreActive = true) { + val onboardingFlow = MutableStateFlow(false) + every { onBoardingSettings.isOnboardedFlow } returns onboardingFlow + createScheduler(this).setup() + verifyIfWorkWasScheduled(exactly = 0) + + onboardingFlow.value = true + verifyIfWorkWasScheduled(exactly = 1) + } - verifySequence { + private fun verifyIfWorkWasScheduled(exactly: Int = 1) { + verify(exactly = exactly) { workManager.enqueueUniquePeriodicWork( ContactDiaryWorkScheduler.PERIODIC_WORK_NAME, ExistingPeriodicWorkPolicy.REPLACE, -- GitLab