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 eb822b0b81893213e63164021849cdac5aa6d8d5..38edfe9df56b54a02f9e8f0f580a80090e5a8b34 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 @@ -165,6 +165,16 @@ class SubmissionRepository @Inject constructor( deadmanNotificationScheduler.cancelScheduledWork() } + // https://jira-ibs.wbs.net.sap/browse/EXPOSUREAPP-4484 + // User removed a test before 1.11 where due to a bug the timestamp was not removed. + if (submissionSettings.initialTestResultReceivedAt != null && + submissionSettings.registrationToken.value != null && + submissionSettings.devicePairingSuccessfulAt == null + ) { + Timber.tag(TAG).w("User has stale initialTestResultReceivedAt, fixing EXPOSUREAPP-4484.") + submissionSettings.initialTestResultReceivedAt = null + } + val initialTestResultReceivedTimestamp = submissionSettings.initialTestResultReceivedAt if (initialTestResultReceivedTimestamp == null) { 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 8744d3d5adb28bf7677d14dd88288d342a0b5c4f..119b38c92ecfddec8871cc31c2bd86136e767960 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 @@ -80,12 +80,15 @@ class SubmissionRepositoryTest : BaseTest() { every { submissionSettings.devicePairingSuccessfulAt = any() } just Runs every { submissionSettings.initialTestResultReceivedAt } returns resultReceivedTimeStamp + every { submissionSettings.initialTestResultReceivedAt = any() } just Runs every { submissionSettings.hasGivenConsent } returns mockFlowPreference(false) every { submissionSettings.hasViewedTestResult } returns mockFlowPreference(false) every { submissionSettings.symptoms } returns mockFlowPreference(Symptoms.NO_INFO_GIVEN) every { submissionSettings.clear() } just Runs + every { submissionSettings.devicePairingSuccessfulAt } returns null + every { taskController.tasks } returns emptyFlow() coEvery { tekHistoryStorage.clear() } just Runs @@ -118,7 +121,6 @@ class SubmissionRepositoryTest : BaseTest() { tracingSettings.isTestResultAvailableNotificationSent = capture(isTestResultAvailableNotificationSent) } answers {} - every { submissionSettings.initialTestResultReceivedAt = any() } just Runs every { submissionSettings.isAllowedToSubmitKeys = any() } just Runs every { submissionSettings.isSubmissionSuccessful = any() } just Runs @@ -277,4 +279,55 @@ class SubmissionRepositoryTest : BaseTest() { coVerify(exactly = 0) { submissionService.asyncRequestTestResult(any()) } } + + @Test + fun `EXPOSUREAPP-4484 is fixed`() = runBlockingTest { + every { timeStamper.nowUTC } returns Instant.EPOCH + + var initialTimeStamp = Instant.EPOCH.plus(9999) + every { submissionSettings.initialTestResultReceivedAt } answers { initialTimeStamp } + every { submissionSettings.initialTestResultReceivedAt = any() } answers { initialTimeStamp = arg(0) } + + every { submissionSettings.registrationToken } returns mockFlowPreference("token") + every { submissionSettings.devicePairingSuccessfulAt } returns null + + val submissionRepository = createInstance(scope = this) + + submissionRepository.updateTestResult(TestResult.NEGATIVE) + + verify { + submissionSettings.initialTestResultReceivedAt = null + submissionSettings.initialTestResultReceivedAt = Instant.EPOCH + } + + initialTimeStamp shouldBe Instant.EPOCH + } + + @Test + fun `EXPOSUREAPP-4484 has specific conditions`() = runBlockingTest { + val submissionRepository = createInstance(scope = this) + + every { submissionSettings.initialTestResultReceivedAt } returns Instant.ofEpochMilli(1234) + every { submissionSettings.registrationToken } returns mockFlowPreference("token") + // This needs to be null to trigger the fix + every { submissionSettings.devicePairingSuccessfulAt } returns Instant.ofEpochMilli(5678) + + submissionRepository.updateTestResult(TestResult.NEGATIVE) + + every { submissionSettings.initialTestResultReceivedAt } returns Instant.ofEpochMilli(1234) + // This needs to be non null to trigger the fix + every { submissionSettings.registrationToken } returns mockFlowPreference(null) + every { submissionSettings.devicePairingSuccessfulAt } returns null + + submissionRepository.updateTestResult(TestResult.NEGATIVE) + + // This needs to be non null to trigger the fix + every { submissionSettings.initialTestResultReceivedAt } returns null + every { submissionSettings.registrationToken } returns mockFlowPreference("token") + every { submissionSettings.devicePairingSuccessfulAt } returns null + + submissionRepository.updateTestResult(TestResult.NEGATIVE) + + verify(exactly = 0) { submissionSettings.initialTestResultReceivedAt = null } + } }