From 44238f01cc113a90db0be71cb0ab56129b27dcae Mon Sep 17 00:00:00 2001 From: BMItter <46747780+BMItter@users.noreply.github.com> Date: Tue, 24 Nov 2020 11:08:28 +0100 Subject: [PATCH] Adjust Diagnosis key file provider to prevent deprecation (EXPOSUREAPP-3896) (#1700) * Added isAtLeast to ENFVersion * Use provideDiagnosisKeys with DiagnosisKeyFileProvider on supported version * better Version of DefaultENFVersion * Added tests for DefaultENFVersion * added missing onSuccessListener * Adjusted tests for new methods --- .../DefaultDiagnosisKeyProvider.kt | 14 +++++- .../modules/version/DefaultENFVersion.kt | 20 ++++++++ .../nearby/modules/version/ENFVersion.kt | 8 +++ .../DefaultDiagnosisKeyProviderTest.kt | 25 +++++++++- .../modules/version/DefaultENFVersionTest.kt | 50 +++++++++++++++++++ 5 files changed, 113 insertions(+), 4 deletions(-) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DefaultDiagnosisKeyProvider.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DefaultDiagnosisKeyProvider.kt index 64f2e75d7..2c5924ec9 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DefaultDiagnosisKeyProvider.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DefaultDiagnosisKeyProvider.kt @@ -1,6 +1,7 @@ package de.rki.coronawarnapp.nearby.modules.diagnosiskeyprovider import com.google.android.gms.common.api.ApiException +import com.google.android.gms.nearby.exposurenotification.DiagnosisKeyFileProvider import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient import de.rki.coronawarnapp.exception.reporting.ReportingConstants import de.rki.coronawarnapp.nearby.modules.version.ENFVersion @@ -35,10 +36,19 @@ class DefaultDiagnosisKeyProvider @Inject constructor( // return false } + val keyFilesList = keyFiles.toList() + val provideDiagnosisKeysTask = if (enfVersion.isAtLeast(ENFVersion.V1_7)) { + Timber.i("Provide diagnosis keys with DiagnosisKeyFileProvider") + val diagnosisKeyFileProvider = DiagnosisKeyFileProvider(keyFilesList) + enfClient.provideDiagnosisKeys(diagnosisKeyFileProvider) + } else { + Timber.i("Provide diagnosis keys as list") + enfClient.provideDiagnosisKeys(keyFilesList) + } + return suspendCoroutine { cont -> Timber.d("Performing key submission.") - enfClient - .provideDiagnosisKeys(keyFiles.toList()) + provideDiagnosisKeysTask .addOnSuccessListener { cont.resume(true) } .addOnFailureListener { val wrappedException = diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/version/DefaultENFVersion.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/version/DefaultENFVersion.kt index 7652fb055..3ce93d482 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/version/DefaultENFVersion.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/version/DefaultENFVersion.kt @@ -9,6 +9,7 @@ import javax.inject.Singleton import kotlin.coroutines.resume import kotlin.coroutines.resumeWithException import kotlin.coroutines.suspendCoroutine +import kotlin.math.abs @Singleton class DefaultENFVersion @Inject constructor( @@ -39,9 +40,28 @@ class DefaultENFVersion @Inject constructor( } } + override suspend fun isAtLeast(compareVersion: Long): Boolean { + if (!compareVersion.isCorrectVersionLength) throw IllegalArgumentException("given version has incorrect length") + + getENFClientVersion()?.let { currentENFClientVersion -> + Timber.i("Comparing current ENF client version $currentENFClientVersion with $compareVersion") + return currentENFClientVersion >= compareVersion + } + + return false + } + private suspend fun internalGetENFClientVersion(): Long = suspendCoroutine { cont -> client.version .addOnSuccessListener { cont.resume(it) } .addOnFailureListener { cont.resumeWithException(it) } } + + // check if a raw long has the correct length to be considered an API version + private val Long.isCorrectVersionLength + get(): Boolean = abs(this).toString().length == GOOGLE_API_VERSION_FIELD_LENGTH + + companion object { + private const val GOOGLE_API_VERSION_FIELD_LENGTH = 8 + } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/version/ENFVersion.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/version/ENFVersion.kt index b7d16994a..7b1b8d830 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/version/ENFVersion.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/nearby/modules/version/ENFVersion.kt @@ -12,7 +12,15 @@ interface ENFVersion { */ suspend fun requireMinimumVersion(required: Long) + /** + * Indicates if the client runs above a certain version + * + * @return isAboveVersion, if connected to an old unsupported version, return false + */ + suspend fun isAtLeast(compareVersion: Long): Boolean + companion object { const val V1_6 = 16000000L + const val V1_7 = 17000000L } } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DefaultDiagnosisKeyProviderTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DefaultDiagnosisKeyProviderTest.kt index da15e5721..d484333fe 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DefaultDiagnosisKeyProviderTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/diagnosiskeyprovider/DefaultDiagnosisKeyProviderTest.kt @@ -1,5 +1,6 @@ package de.rki.coronawarnapp.nearby.modules.diagnosiskeyprovider +import com.google.android.gms.nearby.exposurenotification.DiagnosisKeyFileProvider import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient import de.rki.coronawarnapp.nearby.modules.version.ENFVersion import de.rki.coronawarnapp.nearby.modules.version.OutdatedENFVersionException @@ -36,6 +37,8 @@ class DefaultDiagnosisKeyProviderTest : BaseTest() { coEvery { googleENFClient.provideDiagnosisKeys(any<List<File>>()) } returns MockGMSTask.forValue(null) + coEvery { googleENFClient.provideDiagnosisKeys(any<DiagnosisKeyFileProvider>()) } returns MockGMSTask.forValue(null) + coEvery { enfVersion.requireMinimumVersion(any()) } returns Unit } @@ -70,7 +73,23 @@ class DefaultDiagnosisKeyProviderTest : BaseTest() { } @Test - fun `key provision is used on newer ENF versions`() { + fun `key provision is used with DiagnosisKeyFileProvider on ENF versions from 1_7 upwards`() { + coEvery { enfVersion.isAtLeast(any()) } returns true + + val provider = createProvider() + + runBlocking { provider.provideDiagnosisKeys(exampleKeyFiles) } shouldBe true + + coVerifySequence { + submissionQuota.consumeQuota(1) + googleENFClient.provideDiagnosisKeys(any<DiagnosisKeyFileProvider>()) + } + } + + @Test + fun `key provision is used with key list on ENF versions 1_6`() { + coEvery { enfVersion.isAtLeast(any()) } returns false + val provider = createProvider() runBlocking { provider.provideDiagnosisKeys(exampleKeyFiles) } shouldBe true @@ -81,9 +100,11 @@ class DefaultDiagnosisKeyProviderTest : BaseTest() { } } + @Test fun `quota is just monitored`() { coEvery { submissionQuota.consumeQuota(any()) } returns false + coEvery { enfVersion.isAtLeast(any()) } returns true val provider = createProvider() @@ -91,7 +112,7 @@ class DefaultDiagnosisKeyProviderTest : BaseTest() { coVerifySequence { submissionQuota.consumeQuota(1) - googleENFClient.provideDiagnosisKeys(exampleKeyFiles) + googleENFClient.provideDiagnosisKeys(any<DiagnosisKeyFileProvider>()) } } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/version/DefaultENFVersionTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/version/DefaultENFVersionTest.kt index 6d9e563b9..48a020e44 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/version/DefaultENFVersionTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/nearby/modules/version/DefaultENFVersionTest.kt @@ -109,4 +109,54 @@ internal class DefaultENFVersionTest { } } } + + @Test + fun `isAtLeast is true for newer version`() { + every { client.version } returns MockGMSTask.forValue(ENFVersion.V1_7) + + runBlockingTest { + createInstance().isAtLeast(ENFVersion.V1_6) shouldBe true + } + } + + @Test + fun `isAtLeast is true for equal version`() { + every { client.version } returns MockGMSTask.forValue(ENFVersion.V1_6) + + runBlockingTest { + createInstance().isAtLeast(ENFVersion.V1_6) shouldBe true + } + } + + @Test + fun `isAtLeast is false for older version`() { + every { client.version } returns MockGMSTask.forValue(ENFVersion.V1_6) + + runBlockingTest { + createInstance().isAtLeast(ENFVersion.V1_7) shouldBe false + } + } + + @Test + fun `invalid input for isAtLeast throws IllegalArgumentException`() { + runBlockingTest { + shouldThrow<IllegalArgumentException> { + createInstance().isAtLeast(16) + } + } + } + + @Test + fun `isAtLeast returns false when client not connected`() { + every { client.version } returns MockGMSTask.forError(ApiException(Status(API_NOT_CONNECTED))) + + runBlockingTest { + createInstance().apply { + shouldNotThrowAny { + isAtLeast(ENFVersion.V1_6) shouldBe false + isAtLeast(ENFVersion.V1_7) shouldBe false + } + } + } + } } -- GitLab