diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/common/Calculations.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/common/Calculations.kt new file mode 100644 index 0000000000000000000000000000000000000000..25531761c63d7553637cce94d1418271e1f927d3 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/common/Calculations.kt @@ -0,0 +1,17 @@ +package de.rki.coronawarnapp.datadonation.analytics.common + +import de.rki.coronawarnapp.util.TimeAndDateExtensions.toLocalDate +import org.joda.time.Days +import org.joda.time.Instant + +fun calculateDaysSinceMostRecentDateAtRiskLevelAtTestRegistration( + lastChangeCheckedRiskLevelTimestamp: Instant?, + testRegisteredAt: Instant? +): Int { + val lastChangeCheckedRiskLevelDate = lastChangeCheckedRiskLevelTimestamp?.toLocalDate() ?: return 0 + val testRegisteredAtDate = testRegisteredAt?.toLocalDate() ?: return 0 + return Days.daysBetween( + lastChangeCheckedRiskLevelDate, + testRegisteredAtDate + ).days +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/exposurewindows/AnalyticsExposureWindowDonor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/exposurewindows/AnalyticsExposureWindowDonor.kt index 20483943d92062ecf5fafdf68654d18f69fcb955..aba744f242fd913e2fc50cbc059f528b5b6b2a28 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/exposurewindows/AnalyticsExposureWindowDonor.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/exposurewindows/AnalyticsExposureWindowDonor.kt @@ -76,7 +76,7 @@ internal fun List<AnalyticsExposureWindowEntityWrapper>.asPpaData() = map { } val exposureWindow = PpaData.PPAExposureWindow.newBuilder() - .setDate(it.exposureWindowEntity.dateMillis) + .setDate(it.exposureWindowEntity.dateMillis / 1000) .setCalibrationConfidence(it.exposureWindowEntity.calibrationConfidence) .setInfectiousnessValue(it.exposureWindowEntity.infectiousness) .setReportTypeValue(it.exposureWindowEntity.reportType) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/keysubmission/AnalyticsKeySubmissionDonor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/keysubmission/AnalyticsKeySubmissionDonor.kt index 43be380985e0258331d73625b7e037fe7dcc700b..f92c04cfc8b4a207d35b7f9c3f46bc0403096a36 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/keysubmission/AnalyticsKeySubmissionDonor.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/keysubmission/AnalyticsKeySubmissionDonor.kt @@ -11,7 +11,7 @@ import javax.inject.Singleton @Singleton class AnalyticsKeySubmissionDonor @Inject constructor( - val repository: AnalyticsKeySubmissionRepository, + private val repository: AnalyticsKeySubmissionRepository, private val timeStamper: TimeStamper ) : DonorModule { @@ -54,7 +54,8 @@ class AnalyticsKeySubmissionDonor @Inject constructor( .setSubmittedInBackground(repository.submittedInBackground) .setSubmittedWithTeleTAN(repository.submittedWithTeleTAN) - private fun shouldSubmitData(timeSinceTestResultToSubmit: Duration): Boolean { + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + internal fun shouldSubmitData(timeSinceTestResultToSubmit: Duration): Boolean { return positiveTestResultReceived && ( keysSubmitted || enoughTimeHasPassedSinceResult(timeSinceTestResultToSubmit) ) @@ -66,7 +67,8 @@ class AnalyticsKeySubmissionDonor @Inject constructor( private val keysSubmitted: Boolean get() = repository.submitted - private fun enoughTimeHasPassedSinceResult(timeSinceTestResultToSubmit: Duration): Boolean = + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) + internal fun enoughTimeHasPassedSinceResult(timeSinceTestResultToSubmit: Duration): Boolean = timeStamper.nowUTC.minus(timeSinceTestResultToSubmit) > Instant.ofEpochMilli(repository.testResultReceivedAt) override suspend fun deleteData() { @@ -74,7 +76,7 @@ class AnalyticsKeySubmissionDonor @Inject constructor( } } -@VisibleForTesting +@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) object AnalyticsKeySubmissionNoContribution : DonorModule.Contribution { override suspend fun injectData(protobufContainer: PpaData.PPADataAndroid.Builder) = Unit override suspend fun finishDonation(successful: Boolean) = Unit diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/keysubmission/AnalyticsKeySubmissionRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/keysubmission/AnalyticsKeySubmissionRepository.kt index 8982f68c86e54aa6a91873ed41244e1446ac447c..b2d639381ce9edda8d010567061a65ffbf3a8d16 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/keysubmission/AnalyticsKeySubmissionRepository.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/keysubmission/AnalyticsKeySubmissionRepository.kt @@ -1,5 +1,6 @@ package de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission +import de.rki.coronawarnapp.datadonation.analytics.common.calculateDaysSinceMostRecentDateAtRiskLevelAtTestRegistration import de.rki.coronawarnapp.risk.RiskLevelSettings import org.joda.time.Duration import org.joda.time.Instant @@ -47,10 +48,10 @@ class AnalyticsKeySubmissionRepository @Inject constructor( get() = Duration.millis(max(submittedAt - testRegisteredAt, 0L)).toStandardHours().hours val daysSinceMostRecentDateAtRiskLevelAtTestRegistration: Int - get() = Duration( + get() = calculateDaysSinceMostRecentDateAtRiskLevelAtTestRegistration( riskLevelSettings.lastChangeCheckedRiskLevelTimestamp, Instant.ofEpochMilli(testRegisteredAt) - ).standardDays.toInt() + ) val hoursSinceHighRiskWarningAtTestRegistration: Int get() = storage.hoursSinceHighRiskWarningAtTestRegistration.value diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/registeredtest/TestResultDataCollector.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/registeredtest/TestResultDataCollector.kt index 914bd7cc0e81776c4b5700926e03cec87b980452..52b8be6d4a4c6d7012d4306dba6a3f0f759cf252 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/registeredtest/TestResultDataCollector.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/registeredtest/TestResultDataCollector.kt @@ -19,6 +19,14 @@ class TestResultDataCollector @Inject constructor( * exclude any registered test result before giving a consent */ suspend fun saveTestResultAnalyticsSettings(testResult: TestResult) { + val validTestResults = listOf( + TestResult.POSITIVE, + TestResult.PENDING, + TestResult.NEGATIVE + ) + + if (testResult !in validTestResults) return // Not interested in other values + if (analyticsSettings.analyticsEnabled.value) { val lastRiskResult = riskLevelStorage .latestAndLastSuccessful diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/registeredtest/TestResultDonor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/registeredtest/TestResultDonor.kt index c2e83444227257deed67e55f255ece8db2dbe47b..4a2053feca5bf156a479f8fb6085c4f70e80faf2 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/registeredtest/TestResultDonor.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/datadonation/analytics/modules/registeredtest/TestResultDonor.kt @@ -1,5 +1,6 @@ package de.rki.coronawarnapp.datadonation.analytics.modules.registeredtest +import de.rki.coronawarnapp.datadonation.analytics.common.calculateDaysSinceMostRecentDateAtRiskLevelAtTestRegistration import de.rki.coronawarnapp.datadonation.analytics.modules.DonorModule import de.rki.coronawarnapp.datadonation.analytics.storage.TestResultDonorSettings import de.rki.coronawarnapp.risk.RiskLevelSettings @@ -50,10 +51,10 @@ class TestResultDonor @Inject constructor( testResultDonorSettings.testResultAtRegistration.value ?: return TestResultMetadataNoContribution val daysSinceMostRecentDateAtRiskLevelAtTestRegistration = - Duration( + calculateDaysSinceMostRecentDateAtRiskLevelAtTestRegistration( riskLevelSettings.lastChangeCheckedRiskLevelTimestamp, registrationTime - ).standardDays.toInt() + ) val riskLevelAtRegistration = testResultDonorSettings.riskLevelAtTestRegistration.value diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/tekhistory/DefaultTEKHistoryProvider.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/tekhistory/DefaultTEKHistoryProvider.kt index 2452ac44b62c3ab3b127e9e083ff96a803bcd373..756128817bbf0c7af6c7b91ca01f7ce88e7cf1f8 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/tekhistory/DefaultTEKHistoryProvider.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/tekhistory/DefaultTEKHistoryProvider.kt @@ -130,29 +130,16 @@ class DefaultTEKHistoryProvider @Inject constructor( } private suspend fun getPreAuthTEKHistoryOnV18(): List<TemporaryExposureKey> { - val isPreAuthorized = try { - preAuthorizeExposureKeyHistory() + return try { + Timber.d("Pre-Auth retrieving TEK.") + getPreAuthorizedExposureKeys().also { + Timber.d("Pre-Auth TEK: %s", it.joinToString("\n")) + } } catch (exception: Exception) { - Timber.d(exception, "Requesting Pre-Auth history failed") + Timber.d(exception, "Pre-Auth retrieving TEK failed") if (exception.isResolvable) throw exception - false - } - - return if (isPreAuthorized) { - try { - Timber.d("Pre-Auth retrieving TEK.") - getPreAuthorizedExposureKeys().also { - Timber.d("Pre-Auth TEK: %s", it.joinToString("\n")) - } - } catch (exception: Exception) { - Timber.d(exception, "Pre-Auth retrieving TEK failed") - if (exception.isResolvable) throw exception - Timber.d("Fallback: Retrieving TEK on pre v1.8") - getTEKHistoryOnPreV18() - } - } else { - Timber.d("Retrieving TEK on pre v1.8") + Timber.d("Fallback: Retrieving TEK on pre v1.8") getTEKHistoryOnPreV18() } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/SubmissionRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/SubmissionRepository.kt index fc70b8d81502d4dba3bb15c703443778ce207dd2..8f496e37159faa663aadcb93e23adf3709b988b2 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/SubmissionRepository.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/submission/SubmissionRepository.kt @@ -37,7 +37,8 @@ class SubmissionRepository @Inject constructor( private val deadmanNotificationScheduler: DeadmanNotificationScheduler, private val analyticsKeySubmissionCollector: AnalyticsKeySubmissionCollector ) { - private val testResultReceivedDateFlowInternal = MutableStateFlow(Date()) + private val testResultReceivedDateFlowInternal = + MutableStateFlow(Date(LocalData.initialTestResultReceivedTimestamp() ?: System.currentTimeMillis())) val testResultReceivedDateFlow: Flow<Date> = testResultReceivedDateFlowInternal private val deviceUIStateFlowInternal = diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/qrcode/scan/SubmissionQRCodeScanViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/qrcode/scan/SubmissionQRCodeScanViewModel.kt index e4087abac71bccf897054b11663c304de677f51d..250fa3998c34879d1bf4895a14ca99087bc46008 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/qrcode/scan/SubmissionQRCodeScanViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/qrcode/scan/SubmissionQRCodeScanViewModel.kt @@ -56,10 +56,12 @@ class SubmissionQRCodeScanViewModel @AssistedInject constructor( try { registrationState.postValue(RegistrationState(ApiRequestState.STARTED)) val testResult = submissionRepository.asyncRegisterDeviceViaGUID(scanResult.guid!!) + // Order here is important. When `registrationState.postValue` is called before + // `saveTestResultAnalyticsSettings`, this coroutine will get canceled due to the navigation + // to the next screen. + testResultDataCollector.saveTestResultAnalyticsSettings(testResult) checkTestResult(testResult) registrationState.postValue(RegistrationState(ApiRequestState.SUCCESS, testResult)) - // Order here is important. Save Analytics after SUCCESS - testResultDataCollector.saveTestResultAnalyticsSettings(testResult) } catch (err: CwaWebException) { registrationState.postValue(RegistrationState(ApiRequestState.FAILED)) registrationError.postValue(err) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultavailable/SubmissionTestResultAvailableViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultavailable/SubmissionTestResultAvailableViewModel.kt index 83566280d37b0b27506f1007a781499d7c4936df..3e5d0a7cbaf823d3ec6cdf162fa0a64992ffbc39 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultavailable/SubmissionTestResultAvailableViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultavailable/SubmissionTestResultAvailableViewModel.kt @@ -42,43 +42,41 @@ class SubmissionTestResultAvailableViewModel @AssistedInject constructor( override fun onTEKAvailable(teks: List<TemporaryExposureKey>) { Timber.d("onTEKAvailable(teks.size=%d)", teks.size) autoSubmission.updateMode(AutoSubmission.Mode.MONITOR) - + showKeysRetrievalProgress.postValue(false) routeToScreen.postValue( SubmissionTestResultAvailableFragmentDirections .actionSubmissionTestResultAvailableFragmentToSubmissionTestResultConsentGivenFragment() ) - - showKeysRetrievalProgress.postValue(false) } override fun onTEKPermissionDeclined() { Timber.d("onTEKPermissionDeclined") + showKeysRetrievalProgress.postValue(false) routeToScreen.postValue( SubmissionTestResultAvailableFragmentDirections .actionSubmissionTestResultAvailableFragmentToSubmissionTestResultNoConsentFragment() ) - showKeysRetrievalProgress.postValue(false) } override fun onTracingConsentRequired(onConsentResult: (given: Boolean) -> Unit) { Timber.d("onTracingConsentRequired") - showTracingConsentDialog.postValue(onConsentResult) showKeysRetrievalProgress.postValue(false) + showTracingConsentDialog.postValue(onConsentResult) } override fun onPermissionRequired(permissionRequest: (Activity) -> Unit) { Timber.d("onPermissionRequired") - showPermissionRequest.postValue(permissionRequest) showKeysRetrievalProgress.postValue(false) + showPermissionRequest.postValue(permissionRequest) } override fun onError(error: Throwable) { Timber.e(error, "Failed to update TEKs.") + showKeysRetrievalProgress.postValue(false) error.report( exceptionCategory = ExceptionCategory.EXPOSURENOTIFICATION, prefix = "SubmissionTestResultAvailableViewModel" ) - showKeysRetrievalProgress.postValue(false) } } ) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultready/SubmissionResultReadyViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultready/SubmissionResultReadyViewModel.kt index a59d4a698ed5115aa0b9b6cb19749983ef196860..df6c44bed844e135cef802f811cbd844a041f51a 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultready/SubmissionResultReadyViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/resultready/SubmissionResultReadyViewModel.kt @@ -1,5 +1,7 @@ package de.rki.coronawarnapp.ui.submission.resultready +import androidx.lifecycle.LiveData +import androidx.lifecycle.MediatorLiveData import androidx.lifecycle.asLiveData import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject @@ -16,8 +18,18 @@ class SubmissionResultReadyViewModel @AssistedInject constructor( dispatcherProvider: DispatcherProvider ) : CWAViewModel(dispatcherProvider = dispatcherProvider) { - val showUploadDialog = autoSubmission.isSubmissionRunning - .asLiveData(context = dispatcherProvider.Default) + private val mediatorShowUploadDialog = MediatorLiveData<Boolean>() + + init { + mediatorShowUploadDialog.addSource( + autoSubmission.isSubmissionRunning.asLiveData(context = dispatcherProvider.Default) + ) { show -> + mediatorShowUploadDialog.postValue(show) + } + } + + val showUploadDialog: LiveData<Boolean> = mediatorShowUploadDialog + val routeToScreen: SingleLiveEvent<SubmissionNavigationEvents> = SingleLiveEvent() fun onContinueWithSymptomRecordingPressed() { @@ -32,6 +44,8 @@ class SubmissionResultReadyViewModel @AssistedInject constructor( } catch (e: Exception) { Timber.e(e, "greenlightSubmission() failed.") } finally { + Timber.i("Hide uploading progress and navigate to MainActivity") + mediatorShowUploadDialog.postValue(false) routeToScreen.postValue(SubmissionNavigationEvents.NavigateToMainActivity) } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/introduction/SubmissionSymptomIntroductionViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/introduction/SubmissionSymptomIntroductionViewModel.kt index 5d422d14af934617dc1bc59bb78338e361f0678d..6628ddc879fa20a4f736fb7d9b74f4c8bd683273 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/introduction/SubmissionSymptomIntroductionViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/symptoms/introduction/SubmissionSymptomIntroductionViewModel.kt @@ -1,5 +1,7 @@ package de.rki.coronawarnapp.ui.submission.symptoms.introduction +import androidx.lifecycle.LiveData +import androidx.lifecycle.MediatorLiveData import androidx.lifecycle.asLiveData import androidx.navigation.NavDirections import dagger.assisted.AssistedFactory @@ -29,8 +31,17 @@ class SubmissionSymptomIntroductionViewModel @AssistedInject constructor( val navigation = SingleLiveEvent<NavDirections>() val showCancelDialog = SingleLiveEvent<Unit>() - val showUploadDialog = autoSubmission.isSubmissionRunning - .asLiveData(context = dispatcherProvider.Default) + private val mediatorShowUploadDialog = MediatorLiveData<Boolean>() + + init { + mediatorShowUploadDialog.addSource( + autoSubmission.isSubmissionRunning.asLiveData(context = dispatcherProvider.Default) + ) { show -> + mediatorShowUploadDialog.postValue(show) + } + } + + val showUploadDialog: LiveData<Boolean> = mediatorShowUploadDialog fun onNextClicked() { launch { @@ -98,6 +109,8 @@ class SubmissionSymptomIntroductionViewModel @AssistedInject constructor( } catch (e: Exception) { Timber.e(e, "doSubmit() failed.") } finally { + Timber.i("Hide uploading progress and navigate to HomeFragment") + mediatorShowUploadDialog.postValue(false) navigation.postValue( SubmissionSymptomIntroductionFragmentDirections .actionSubmissionSymptomIntroductionFragmentToMainFragment() diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/warnothers/SubmissionResultPositiveOtherWarningNoConsentViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/warnothers/SubmissionResultPositiveOtherWarningNoConsentViewModel.kt index 5eb733701ba3164646c710325bb8e2d944819fc2..da6c4e5148d24e6535c49def2d4de866d86047c9 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/warnothers/SubmissionResultPositiveOtherWarningNoConsentViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/submission/warnothers/SubmissionResultPositiveOtherWarningNoConsentViewModel.kt @@ -100,8 +100,8 @@ class SubmissionResultPositiveOtherWarningNoConsentViewModel @AssistedInject con tekHistoryUpdater.updateTEKHistoryOrRequestPermission() } else { Timber.d("showEnableTracingEvent:Unit") - showEnableTracingEvent.postValue(Unit) showKeysRetrievalProgress.postValue(false) + showEnableTracingEvent.postValue(Unit) } } } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/exposurewindows/AnalyticsExposureWindowDonorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/exposurewindows/AnalyticsExposureWindowDonorTest.kt index 307fade38797106d34a72ae99ce097727abd1b60..1014934eee8cf81209338bd073b688b115b896d5 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/exposurewindows/AnalyticsExposureWindowDonorTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/exposurewindows/AnalyticsExposureWindowDonorTest.kt @@ -2,6 +2,7 @@ package de.rki.coronawarnapp.datadonation.analytics.modules.exposurewindows import de.rki.coronawarnapp.appconfig.ConfigData import de.rki.coronawarnapp.datadonation.analytics.modules.DonorModule +import de.rki.coronawarnapp.server.protocols.internal.ppdd.PpaData import io.kotest.matchers.shouldBe import io.mockk.MockKAnnotations import io.mockk.Runs @@ -25,18 +26,18 @@ class AnalyticsExposureWindowDonorTest : BaseTest() { override val currentConfig: ConfigData get() = configData } - private val window = AnalyticsExposureWindowEntity( - "hash", - 1, - 1L, - 1, - 1, - 1.0, - 1 + private val testWindow = AnalyticsExposureWindowEntity( + sha256Hash = "hash", + calibrationConfidence = 1, + dateMillis = 1234567890L, + infectiousness = 2, + reportType = 3, + normalizedTime = 4.0, + transmissionRiskLevel = 5 ) private val scanInstance = AnalyticsScanInstanceEntity(1, "hash", 1, 1, 1) private val wrapper = AnalyticsExposureWindowEntityWrapper( - window, + testWindow, listOf(scanInstance) ) @@ -49,6 +50,20 @@ class AnalyticsExposureWindowDonorTest : BaseTest() { every { Random.nextDouble() } returns .5 } + @Test + fun `protobuf conversion uses correct formats`() { + val newWindow = listOf(wrapper).asPpaData().single().apply { + normalizedTime shouldBe 4.0 + transmissionRiskLevel shouldBe 5 + } + newWindow.exposureWindow.apply { + date shouldBe 1234567L + calibrationConfidence shouldBe 1 + infectiousness shouldBe PpaData.PPAExposureWindowInfectiousness.INFECTIOUSNESS_HIGH + reportType shouldBe PpaData.PPAExposureWindowReportType.REPORT_TYPE_SELF_REPORT + } + } + @Test fun `skip submission when random number greater than probability`() { val donor = newInstance() diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/keysubmission/AnalyticsKeySubmissionCollectorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/keysubmission/AnalyticsKeySubmissionCollectorTest.kt index ac0144363e0d88499e81d547406dfd63295e2f59..fe9666112e81d20e74876399cd76ef22b47b0ada 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/keysubmission/AnalyticsKeySubmissionCollectorTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/keysubmission/AnalyticsKeySubmissionCollectorTest.kt @@ -1,3 +1,210 @@ package de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission -class AnalyticsKeySubmissionCollectorTest +import de.rki.coronawarnapp.datadonation.analytics.storage.AnalyticsSettings +import de.rki.coronawarnapp.risk.RiskLevelResult +import de.rki.coronawarnapp.risk.RiskLevelSettings +import de.rki.coronawarnapp.risk.RiskState +import de.rki.coronawarnapp.risk.storage.RiskLevelStorage +import de.rki.coronawarnapp.util.TimeStamper +import io.mockk.MockKAnnotations +import io.mockk.coEvery +import io.mockk.every +import io.mockk.impl.annotations.MockK +import io.mockk.verify +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.test.runBlockingTest +import org.joda.time.Hours +import org.joda.time.Instant +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testhelpers.BaseTest +import testhelpers.preferences.mockFlowPreference + +class AnalyticsKeySubmissionCollectorTest : BaseTest() { + + @MockK lateinit var timeStamper: TimeStamper + @MockK lateinit var analyticsSettings: AnalyticsSettings + @MockK lateinit var analyticsKeySubmissionStorage: AnalyticsKeySubmissionStorage + @MockK lateinit var riskLevelStorage: RiskLevelStorage + @MockK lateinit var riskLevelSettings: RiskLevelSettings + @MockK lateinit var riskLevelResult: RiskLevelResult + + private val now = Instant.now() + + @BeforeEach + fun setup() { + MockKAnnotations.init(this) + every { timeStamper.nowUTC } returns now + } + + @Test + fun `save test registered`() { + coEvery { analyticsSettings.analyticsEnabled.value } returns true + every { riskLevelResult.riskState } returns RiskState.INCREASED_RISK + coEvery { + riskLevelStorage.latestAndLastSuccessful + } returns flowOf(listOf(riskLevelResult)) + every { riskLevelSettings.lastChangeToHighRiskLevelTimestamp } returns now.minus( + Hours.hours(2).toStandardDuration() + ) + val testRegisteredAt = mockFlowPreference(now.millis) + coEvery { analyticsKeySubmissionStorage.testRegisteredAt } returns testRegisteredAt + every { riskLevelResult.wasSuccessfullyCalculated } returns true + val riskLevelAtTestRegistration = mockFlowPreference(-1) + every { analyticsKeySubmissionStorage.riskLevelAtTestRegistration } returns riskLevelAtTestRegistration + val hoursSinceHighRiskWarningAtTestRegistration = mockFlowPreference(-1) + every { analyticsKeySubmissionStorage.hoursSinceHighRiskWarningAtTestRegistration } returns hoursSinceHighRiskWarningAtTestRegistration + runBlockingTest { + val collector = createInstance() + collector.reportTestRegistered() + verify { testRegisteredAt.update(any()) } + verify { riskLevelAtTestRegistration.update(any()) } + verify { hoursSinceHighRiskWarningAtTestRegistration.update(any()) } + } + } + + @Test + fun `save keys submitted`() { + coEvery { analyticsSettings.analyticsEnabled.value } returns true + val submittedFlow = mockFlowPreference(false) + every { analyticsKeySubmissionStorage.submitted } returns submittedFlow + val submittedAtFlow = mockFlowPreference(now.millis) + every { analyticsKeySubmissionStorage.submittedAt } returns submittedAtFlow + runBlockingTest { + val collector = createInstance() + collector.reportSubmitted() + verify { submittedFlow.update(any()) } + verify { submittedAtFlow.update(any()) } + } + } + + @Test + fun `save keys submitted after cancel`() { + coEvery { analyticsSettings.analyticsEnabled.value } returns true + val flow = mockFlowPreference(false) + every { analyticsKeySubmissionStorage.submittedAfterCancel } returns flow + runBlockingTest { + val collector = createInstance() + collector.reportSubmittedAfterCancel() + verify { flow.update(any()) } + } + } + + @Test + fun `save keys submitted in background`() { + coEvery { analyticsSettings.analyticsEnabled.value } returns true + val flow = mockFlowPreference(false) + every { analyticsKeySubmissionStorage.submittedInBackground } returns flow + runBlockingTest { + val collector = createInstance() + collector.reportSubmittedInBackground() + verify { flow.update(any()) } + } + } + + @Test + fun `save keys submitted after symptom flow`() { + coEvery { analyticsSettings.analyticsEnabled.value } returns true + val flow = mockFlowPreference(false) + every { analyticsKeySubmissionStorage.submittedAfterSymptomFlow } returns flow + runBlockingTest { + val collector = createInstance() + collector.reportSubmittedAfterSymptomFlow() + verify { flow.update(any()) } + } + } + + @Test + fun `save positive test result received`() { + coEvery { analyticsSettings.analyticsEnabled.value } returns true + val flow = mockFlowPreference(now.millis) + every { analyticsKeySubmissionStorage.testResultReceivedAt } returns flow + runBlockingTest { + val collector = createInstance() + collector.reportPositiveTestResultReceived() + verify { flow.update(any()) } + } + } + + @Test + fun `save advanced consent given`() { + coEvery { analyticsSettings.analyticsEnabled.value } returns true + val flow = mockFlowPreference(false) + every { analyticsKeySubmissionStorage.advancedConsentGiven } returns flow + runBlockingTest { + val collector = createInstance() + collector.reportAdvancedConsentGiven() + verify { flow.update(any()) } + } + } + + @Test + fun `save consent withdrawn`() { + coEvery { analyticsSettings.analyticsEnabled.value } returns true + val flow = mockFlowPreference(false) + every { analyticsKeySubmissionStorage.advancedConsentGiven } returns flow + runBlockingTest { + val collector = createInstance() + collector.reportConsentWithdrawn() + verify { flow.update(any()) } + } + } + + @Test + fun `save registered with tele tan`() { + coEvery { analyticsSettings.analyticsEnabled.value } returns true + val flow = mockFlowPreference(false) + every { analyticsKeySubmissionStorage.registeredWithTeleTAN } returns flow + runBlockingTest { + val collector = createInstance() + collector.reportRegisteredWithTeleTAN() + verify { flow.update(any()) } + } + } + + @Test + fun `save last submission flow screen`() { + coEvery { analyticsSettings.analyticsEnabled.value } returns true + val flow = mockFlowPreference(0) + every { analyticsKeySubmissionStorage.lastSubmissionFlowScreen } returns flow + runBlockingTest { + val collector = createInstance() + collector.reportLastSubmissionFlowScreen(Screen.WARN_OTHERS) + verify { flow.update(any()) } + } + } + + @Test + fun `no data collection if disabled`() { + coEvery { analyticsSettings.analyticsEnabled.value } returns false + runBlockingTest { + val collector = createInstance() + collector.reportTestRegistered() + verify(exactly = 0) { analyticsKeySubmissionStorage.testRegisteredAt } + verify(exactly = 0) { analyticsKeySubmissionStorage.riskLevelAtTestRegistration } + verify(exactly = 0) { analyticsKeySubmissionStorage.hoursSinceHighRiskWarningAtTestRegistration } + collector.reportSubmitted() + verify(exactly = 0) { analyticsKeySubmissionStorage.submitted } + collector.reportSubmittedInBackground() + verify(exactly = 0) { analyticsKeySubmissionStorage.submittedInBackground } + collector.reportAdvancedConsentGiven() + verify(exactly = 0) { analyticsKeySubmissionStorage.advancedConsentGiven } + collector.reportConsentWithdrawn() + verify(exactly = 0) { analyticsKeySubmissionStorage.advancedConsentGiven } + collector.reportLastSubmissionFlowScreen(Screen.UNKNOWN) + verify(exactly = 0) { analyticsKeySubmissionStorage.lastSubmissionFlowScreen } + collector.reportPositiveTestResultReceived() + verify(exactly = 0) { analyticsKeySubmissionStorage.testResultReceivedAt } + collector.reportSubmittedAfterCancel() + verify(exactly = 0) { analyticsKeySubmissionStorage.submittedAfterCancel } + } + } + + fun createInstance() = AnalyticsKeySubmissionCollector( + timeStamper, + analyticsSettings, + analyticsKeySubmissionStorage, + riskLevelStorage, + riskLevelSettings + ) +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/keysubmission/AnalyticsKeySubmissionDonorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/keysubmission/AnalyticsKeySubmissionDonorTest.kt index 252fa5d3b015fc6d749f9c1188bfe66fce6d568b..990fb04b761c9b46f61f41e8df2f594dc97b233b 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/keysubmission/AnalyticsKeySubmissionDonorTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/keysubmission/AnalyticsKeySubmissionDonorTest.kt @@ -1,3 +1,102 @@ package de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission -class AnalyticsKeySubmissionDonorTest +import de.rki.coronawarnapp.appconfig.ConfigData +import de.rki.coronawarnapp.datadonation.analytics.modules.DonorModule +import de.rki.coronawarnapp.server.protocols.internal.ppdd.PpaData +import de.rki.coronawarnapp.util.TimeStamper +import io.kotest.matchers.shouldBe +import io.mockk.MockKAnnotations +import io.mockk.Runs +import io.mockk.coVerify +import io.mockk.every +import io.mockk.impl.annotations.MockK +import io.mockk.just +import io.mockk.verify +import kotlinx.coroutines.test.runBlockingTest +import org.joda.time.Duration +import org.joda.time.Instant +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testhelpers.BaseTest + +class AnalyticsKeySubmissionDonorTest : BaseTest() { + @MockK lateinit var repository: AnalyticsKeySubmissionRepository + @MockK lateinit var timeStamper: TimeStamper + @MockK lateinit var configData: ConfigData + private val request = object : DonorModule.Request { + override val currentConfig: ConfigData + get() = configData + } + private val now = Instant.now() + + @MockK lateinit var ppaData: PpaData.PPADataAndroid.Builder + + @BeforeEach + fun setup() { + MockKAnnotations.init(this) + every { timeStamper.nowUTC } returns now + every { configData.analytics.hoursSinceTestResultToSubmitKeySubmissionMetadata } returns 6 + } + + @Test + fun `no contribution without test result`() { + every { repository.testResultReceivedAt } returns -1 + every { repository.submitted } returns false + runBlockingTest { + val donor = createInstance() + donor.beginDonation(request) shouldBe AnalyticsKeySubmissionNoContribution + } + } + + @Test + fun `no contribution when neither submitted nor enough time passed`() { + every { repository.testResultReceivedAt } returns now.minus(Duration.standardHours(4)).millis + every { repository.submitted } returns false + runBlockingTest { + val donor = createInstance() + donor.beginDonation(request) shouldBe AnalyticsKeySubmissionNoContribution + } + } + + @Test + fun `regular contribution when keys submitted`() { + every { repository.testResultReceivedAt } returns now.minus(Duration.standardHours(4)).millis + every { repository.advancedConsentGiven } returns true + every { repository.daysSinceMostRecentDateAtRiskLevelAtTestRegistration } returns 1 + every { repository.hoursSinceHighRiskWarningAtTestRegistration } returns 1 + every { repository.hoursSinceTestResult } returns 1 + every { repository.hoursSinceTestRegistration } returns 1 + every { repository.lastSubmissionFlowScreen } returns 1 + every { repository.submittedAfterCancel } returns true + every { repository.submittedAfterSymptomFlow } returns true + every { repository.submittedInBackground } returns true + every { repository.submittedWithTeleTAN } returns false + every { repository.submitted } returns true + every { ppaData.addKeySubmissionMetadataSet(any<PpaData.PPAKeySubmissionMetadata.Builder>()) } returns ppaData + every { repository.reset() } just Runs + runBlockingTest { + val donor = createInstance() + val contribution = donor.beginDonation(request) + contribution.injectData(ppaData) + coVerify { ppaData.addKeySubmissionMetadataSet(any<PpaData.PPAKeySubmissionMetadata.Builder>()) } + contribution.finishDonation(false) + verify(exactly = 0) { repository.reset() } + contribution.finishDonation(true) + verify(exactly = 1) { repository.reset() } + } + } + + @Test + fun `submit contribution after enough time has passed`() { + every { repository.testResultReceivedAt } returns now.minus(Duration.standardHours(4)).millis + every { repository.submitted } returns true + val minTimePassedToSubmit = Duration.standardHours(3) + runBlockingTest { + val donor = createInstance() + donor.enoughTimeHasPassedSinceResult(Duration.standardHours(3)) shouldBe true + donor.shouldSubmitData(minTimePassedToSubmit) shouldBe true + } + } + + fun createInstance() = AnalyticsKeySubmissionDonor(repository, timeStamper) +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/keysubmission/AnalyticsKeySubmissionRepositoryTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/keysubmission/AnalyticsKeySubmissionRepositoryTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..136eaae38cf3cd1b3a7f1955e16bc2d6964e11f4 --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/keysubmission/AnalyticsKeySubmissionRepositoryTest.kt @@ -0,0 +1,116 @@ +package de.rki.coronawarnapp.datadonation.analytics.modules.keysubmission + +import de.rki.coronawarnapp.risk.RiskLevelSettings +import io.kotest.matchers.shouldBe +import io.mockk.MockKAnnotations +import io.mockk.coEvery +import io.mockk.impl.annotations.MockK +import org.joda.time.Days +import org.joda.time.Hours +import org.joda.time.Instant +import org.joda.time.LocalTime +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testhelpers.BaseTest + +class AnalyticsKeySubmissionRepositoryTest : BaseTest() { + + @MockK lateinit var storage: AnalyticsKeySubmissionStorage + @MockK lateinit var riskLevelSettings: RiskLevelSettings + + private val now = Instant.now() + + @BeforeEach + fun setup() { + MockKAnnotations.init(this) + } + + private fun createInstance() = AnalyticsKeySubmissionRepository( + storage, riskLevelSettings + ) + + @Test + fun `hours since test result are calculated correctly`() { + coEvery { storage.submittedAt.value } returns now.millis + coEvery { storage.testResultReceivedAt.value } returns now.minus(Hours.hours(5).toStandardDuration()).millis + val repository = createInstance() + repository.hoursSinceTestResult shouldBe 5 + } + + @Test + fun `hours since test result when not submitted should be 0`() { + coEvery { storage.submittedAt.value } returns -1 + coEvery { storage.testResultReceivedAt.value } returns now.minus(Hours.hours(5).toStandardDuration()).millis + val repository = createInstance() + repository.hoursSinceTestResult shouldBe 0 + } + + @Test + fun `hours since test result when not received or submitted should be 0`() { + coEvery { storage.submittedAt.value } returns -1 + coEvery { storage.testResultReceivedAt.value } returns -1 + val repository = createInstance() + repository.hoursSinceTestResult shouldBe 0 + } + + @Test + fun `hours since test result should be 0 when dates have been manipulated`() { + coEvery { storage.submittedAt.value } returns now.minus(Hours.hours(5).toStandardDuration()).millis + coEvery { storage.testResultReceivedAt.value } returns now.millis + val repository = createInstance() + repository.hoursSinceTestResult shouldBe 0 + } + + @Test + fun `hours since test registration are calculated correctly`() { + coEvery { storage.submittedAt.value } returns now.millis + coEvery { storage.testRegisteredAt.value } returns now.minus(Hours.hours(5).toStandardDuration()).millis + val repository = createInstance() + repository.hoursSinceTestRegistration shouldBe 5 + } + + @Test + fun `hours since test registration should be 0 if not submitted`() { + coEvery { storage.submittedAt.value } returns -1 + coEvery { storage.testRegisteredAt.value } returns now.minus(Hours.hours(5).toStandardDuration()).millis + val repository = createInstance() + repository.hoursSinceTestRegistration shouldBe 0 + } + + @Test + fun `days since most recent date at risk level at test registration are calculated correctly`() { + coEvery { + riskLevelSettings.lastChangeCheckedRiskLevelTimestamp + } returns now + .minus(Days.days(2).toStandardDuration()).toDateTime().toLocalDate() + .toDateTime(LocalTime(22, 0)).toInstant() + coEvery { storage.testRegisteredAt.value } returns + now.toDateTime().toLocalDate().toDateTime(LocalTime(5, 0)).millis + val repository = createInstance() + repository.daysSinceMostRecentDateAtRiskLevelAtTestRegistration shouldBe 2 + } + + @Test + fun `days between most recent risk level change and test registration should be 0 if on same day`() { + coEvery { + riskLevelSettings.lastChangeCheckedRiskLevelTimestamp + } returns now + .toDateTime().toLocalDate() + .toDateTime(LocalTime(13, 0)).toInstant() + coEvery { storage.testRegisteredAt.value } returns + now.toDateTime().toLocalDate().toDateTime(LocalTime(14, 0)).millis + val repository = createInstance() + repository.daysSinceMostRecentDateAtRiskLevelAtTestRegistration shouldBe 0 + } + + @Test + fun `days should be 0 if lastChangeCheckedRiskLevelTimestamp is null`() { + coEvery { + riskLevelSettings.lastChangeCheckedRiskLevelTimestamp + } returns null + coEvery { storage.testRegisteredAt.value } returns + now.toDateTime().toLocalDate().toDateTime(LocalTime(14, 0)).millis + val repository = createInstance() + repository.daysSinceMostRecentDateAtRiskLevelAtTestRegistration shouldBe 0 + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/registeredtest/TestResultDataCollectorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/registeredtest/TestResultDataCollectorTest.kt index 104a2d06deaafc25023c3edac0582567f65e10c4..a0a8ba370dda50e7c7e3a73c55339af02f6af696 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/registeredtest/TestResultDataCollectorTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/datadonation/analytics/modules/registeredtest/TestResultDataCollectorTest.kt @@ -5,6 +5,7 @@ import de.rki.coronawarnapp.datadonation.analytics.storage.TestResultDonorSettin import de.rki.coronawarnapp.risk.RiskLevelResult import de.rki.coronawarnapp.risk.storage.RiskLevelStorage import de.rki.coronawarnapp.util.formatter.TestResult +import io.mockk.Called import io.mockk.MockKAnnotations import io.mockk.Runs import io.mockk.every @@ -66,4 +67,24 @@ class TestResultDataCollectorTest : BaseTest() { testResultDonorSettings.saveTestResultDonorDataAtRegistration(any(), any()) } } + + @Test + fun `saveTestResultAnalyticsSettings does not save data when TestResult is INVALID`() = runBlockingTest { + every { analyticsSettings.analyticsEnabled } returns mockFlowPreference(false) + testResultDataCollector.saveTestResultAnalyticsSettings(TestResult.INVALID) + + verify { + analyticsSettings.analyticsEnabled wasNot Called + } + } + + @Test + fun `saveTestResultAnalyticsSettings does not save data when TestResult is REDEEMED`() = runBlockingTest { + every { analyticsSettings.analyticsEnabled } returns mockFlowPreference(false) + testResultDataCollector.saveTestResultAnalyticsSettings(TestResult.REDEEMED) + + verify { + analyticsSettings.analyticsEnabled wasNot Called + } + } } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/tekhistory/DefaultTEKHistoryProviderTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/tekhistory/DefaultTEKHistoryProviderTest.kt index 3202a9622b856686646335c54ddb2552484385d2..129e488001b32d78090f9dd151e81879b9a9aa07 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/tekhistory/DefaultTEKHistoryProviderTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/tekhistory/DefaultTEKHistoryProviderTest.kt @@ -185,7 +185,7 @@ class DefaultTEKHistoryProviderTest : BaseTest() { every { status.hasResolution() } returns true every { printStackTrace(any<PrintWriter>()) } just Runs } - every { client.requestPreAuthorizedTemporaryExposureKeyHistory() } answers { MockGMSTask.forError(error) } + every { client.requestPreAuthorizedTemporaryExposureKeyRelease() } answers { MockGMSTask.forError(error) } shouldThrow<ApiException> { createInstance().getTEKHistory() @@ -195,13 +195,25 @@ class DefaultTEKHistoryProviderTest : BaseTest() { @Test fun `ENFV1_8 getTEKHistory request keys from new Api fallback to old Api on error`() = runBlockingTest { coEvery { enfVersion.isAtLeast(ENFVersion.V1_8) } returns true - every { client.requestPreAuthorizedTemporaryExposureKeyHistory() } answers { MockGMSTask.forError(Exception()) } + every { client.requestPreAuthorizedTemporaryExposureKeyRelease() } answers { MockGMSTask.forError(Exception()) } val mockTEK = mockk<TemporaryExposureKey>() every { client.temporaryExposureKeyHistory } answers { MockGMSTask.forValue(listOf(mockTEK)) } createInstance().getTEKHistory() shouldBe listOf(mockTEK) verify(exactly = 1) { client.temporaryExposureKeyHistory } + verify { client.requestPreAuthorizedTemporaryExposureKeyHistory() wasNot Called } + } + + @Test + fun `ENFV1_8 getTEKHistory request keys from new Api does not check for preAuth`() = runBlockingTest { + coEvery { enfVersion.isAtLeast(ENFVersion.V1_8) } returns true + every { client.requestPreAuthorizedTemporaryExposureKeyRelease() } answers { MockGMSTask.forValue(null) } + + createInstance().getTEKHistory() + + verify(exactly = 1) { client.requestPreAuthorizedTemporaryExposureKeyRelease() } + verify { client.requestPreAuthorizedTemporaryExposureKeyHistory() wasNot Called } } @Test @@ -265,7 +277,7 @@ class DefaultTEKHistoryProviderTest : BaseTest() { @Test fun `ENFV1_8 getTEKHistoryOrRequestPermission - if not preauthorized and no resolution then use the old API`() { coEvery { enfVersion.isAtLeast(ENFVersion.V1_8) } returns true - every { client.requestPreAuthorizedTemporaryExposureKeyHistory() } returns MockGMSTask.forError(Exception()) + every { client.requestPreAuthorizedTemporaryExposureKeyRelease() } returns MockGMSTask.forError(Exception()) val onTEKHistoryAvailable = mockk<(List<TemporaryExposureKey>) -> Unit>(relaxed = true) val onPermissionRequired = mockk<(Status) -> Unit>(relaxed = true) @@ -320,7 +332,6 @@ class DefaultTEKHistoryProviderTest : BaseTest() { onPermissionRequired wasNot Called } verifyOrder { - client.requestPreAuthorizedTemporaryExposureKeyHistory() client.requestPreAuthorizedTemporaryExposureKeyRelease() client.temporaryExposureKeyHistory } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/storage/SubmissionRepositoryTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/storage/SubmissionRepositoryTest.kt index e78e650721b97d777d8d9409d12eca30d09271ea..31d2aaa7c6d0775833f853d5d30f53f923de3dfe 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/storage/SubmissionRepositoryTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/storage/SubmissionRepositoryTest.kt @@ -133,7 +133,7 @@ class SubmissionRepositoryTest : BaseTest() { submissionRepository.asyncRegisterDeviceViaGUID(guid) - verify(exactly = 1) { + verify { LocalData.devicePairingSuccessfulTimestamp(any()) LocalData.registrationToken(registrationToken) backgroundNoise.scheduleDummyPattern() @@ -151,7 +151,7 @@ class SubmissionRepositoryTest : BaseTest() { submissionRepository.asyncRegisterDeviceViaTAN(tan) - coVerify(exactly = 1) { + coVerify { LocalData.devicePairingSuccessfulTimestamp(any()) LocalData.registrationToken(registrationToken) backgroundNoise.scheduleDummyPattern()