Skip to content
Snippets Groups Projects
Unverified Commit 86f793a1 authored by Jakob Möller's avatar Jakob Möller Committed by GitHub
Browse files

Version Checker with Branching for Checks on provideDiagnosisKeys below v16 of...

Version Checker with Branching for Checks on provideDiagnosisKeys below v16 of ENF (EXPOSUREAPP-2213) (#1150)

* Add Version Check

Signed-off-by: default avatard067928 <jakob.moeller@sap.com>

* Version Checker Update

Signed-off-by: default avatard067928 <jakob.moeller@sap.com>

* Testing for Version Check

Signed-off-by: default avatard067928 <jakob.moeller@sap.com>

* Remove Expiremental Annotation for method and add on Class and pull tearDown below setUp

Signed-off-by: default avatard067928 <jakob.moeller@sap.com>

* add GoogleAPIVersion via DI

Signed-off-by: default avatard067928 <jakob.moeller@sap.com>

Co-authored-by: default avatarMatthias Urhahn <matthias.urhahn@sap.com>
parent 7ab2b2d7
No related branches found
No related tags found
No related merge requests found
...@@ -92,6 +92,15 @@ object InternalExposureNotificationClient { ...@@ -92,6 +92,15 @@ object InternalExposureNotificationClient {
} }
} }
suspend fun getVersion(): Long = suspendCoroutine { cont ->
exposureNotificationClient.version
.addOnSuccessListener {
cont.resume(it)
}.addOnFailureListener {
cont.resumeWithException(it)
}
}
/** /**
* Takes an ExposureConfiguration object. Inserts a list of files that contain key * Takes an ExposureConfiguration object. Inserts a list of files that contain key
* information into the on-device database. Provide the keys of confirmed cases retrieved * information into the on-device database. Provide the keys of confirmed cases retrieved
......
package de.rki.coronawarnapp.transaction package de.rki.coronawarnapp.transaction
import de.rki.coronawarnapp.util.GoogleAPIVersion
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
// TODO Remove once we have refactored the transaction and it's no longer a singleton // TODO Remove once we have refactored the transaction and it's no longer a singleton
@Singleton @Singleton
data class RetrieveDiagnosisInjectionHelper @Inject constructor( data class RetrieveDiagnosisInjectionHelper @Inject constructor(
val transactionScope: TransactionCoroutineScope val transactionScope: TransactionCoroutineScope,
val googleAPIVersion: GoogleAPIVersion
) )
...@@ -35,6 +35,7 @@ import de.rki.coronawarnapp.transaction.RetrieveDiagnosisKeysTransaction.Retriev ...@@ -35,6 +35,7 @@ import de.rki.coronawarnapp.transaction.RetrieveDiagnosisKeysTransaction.Retriev
import de.rki.coronawarnapp.transaction.RetrieveDiagnosisKeysTransaction.rollback import de.rki.coronawarnapp.transaction.RetrieveDiagnosisKeysTransaction.rollback
import de.rki.coronawarnapp.transaction.RetrieveDiagnosisKeysTransaction.start import de.rki.coronawarnapp.transaction.RetrieveDiagnosisKeysTransaction.start
import de.rki.coronawarnapp.util.CachedKeyFileHolder import de.rki.coronawarnapp.util.CachedKeyFileHolder
import de.rki.coronawarnapp.util.GoogleAPIVersion
import de.rki.coronawarnapp.util.GoogleQuotaCalculator import de.rki.coronawarnapp.util.GoogleQuotaCalculator
import de.rki.coronawarnapp.util.QuotaCalculator import de.rki.coronawarnapp.util.QuotaCalculator
import de.rki.coronawarnapp.util.di.AppInjector import de.rki.coronawarnapp.util.di.AppInjector
...@@ -141,6 +142,10 @@ object RetrieveDiagnosisKeysTransaction : Transaction() { ...@@ -141,6 +142,10 @@ object RetrieveDiagnosisKeysTransaction : Transaction() {
quotaChronology = GJChronology.getInstanceUTC() quotaChronology = GJChronology.getInstanceUTC()
) )
private val googleAPIVersion: GoogleAPIVersion by lazy {
AppInjector.component.transRetrieveKeysInjection.googleAPIVersion
}
suspend fun startWithConstraints() { suspend fun startWithConstraints() {
val currentDate = DateTime(Instant.now(), DateTimeZone.UTC) val currentDate = DateTime(Instant.now(), DateTimeZone.UTC)
val lastFetch = DateTime( val lastFetch = DateTime(
...@@ -316,11 +321,21 @@ object RetrieveDiagnosisKeysTransaction : Transaction() { ...@@ -316,11 +321,21 @@ object RetrieveDiagnosisKeysTransaction : Transaction() {
exportFiles: Collection<File>, exportFiles: Collection<File>,
exposureConfiguration: ExposureConfiguration? exposureConfiguration: ExposureConfiguration?
) = executeState(API_SUBMISSION) { ) = executeState(API_SUBMISSION) {
InternalExposureNotificationClient.asyncProvideDiagnosisKeys( if (googleAPIVersion.isAbove(GoogleAPIVersion.V16)) {
exportFiles, InternalExposureNotificationClient.asyncProvideDiagnosisKeys(
exposureConfiguration, exportFiles,
token exposureConfiguration,
) token
)
} else {
exportFiles.forEach { batch ->
InternalExposureNotificationClient.asyncProvideDiagnosisKeys(
listOf(batch),
exposureConfiguration,
token
)
}
}
Timber.tag(TAG).d("Diagnosis Keys provided successfully, Token: $token") Timber.tag(TAG).d("Diagnosis Keys provided successfully, Token: $token")
} }
......
package de.rki.coronawarnapp.util
import com.google.android.gms.common.api.ApiException
import com.google.android.gms.common.api.CommonStatusCodes
import dagger.Reusable
import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient
import javax.inject.Inject
import kotlin.math.abs
@Reusable
class GoogleAPIVersion @Inject constructor() {
/**
* Indicates if the client runs above a certain version
*
* @return isAboveVersion, if connected to an old unsupported version, return false
*/
suspend fun isAbove(compareVersion: Long): Boolean {
if (!compareVersion.isCorrectVersionLength) {
throw IllegalArgumentException("given version has incorrect length")
}
return try {
val currentVersion = InternalExposureNotificationClient.getVersion()
currentVersion >= compareVersion
} catch (apiException: ApiException) {
if (apiException.statusCode == CommonStatusCodes.API_NOT_CONNECTED) false
else throw apiException
}
}
// 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
const val V16 = 16000000L
}
}
...@@ -4,6 +4,7 @@ import com.google.android.gms.nearby.exposurenotification.ExposureConfiguration ...@@ -4,6 +4,7 @@ import com.google.android.gms.nearby.exposurenotification.ExposureConfiguration
import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient
import de.rki.coronawarnapp.service.applicationconfiguration.ApplicationConfigurationService import de.rki.coronawarnapp.service.applicationconfiguration.ApplicationConfigurationService
import de.rki.coronawarnapp.storage.LocalData import de.rki.coronawarnapp.storage.LocalData
import de.rki.coronawarnapp.util.GoogleAPIVersion
import de.rki.coronawarnapp.util.di.AppInjector import de.rki.coronawarnapp.util.di.AppInjector
import de.rki.coronawarnapp.util.di.ApplicationComponent import de.rki.coronawarnapp.util.di.ApplicationComponent
import io.mockk.Runs import io.mockk.Runs
...@@ -34,7 +35,8 @@ class RetrieveDiagnosisKeysTransactionTest { ...@@ -34,7 +35,8 @@ class RetrieveDiagnosisKeysTransactionTest {
mockkObject(AppInjector) mockkObject(AppInjector)
val appComponent = mockk<ApplicationComponent>().apply { val appComponent = mockk<ApplicationComponent>().apply {
every { transRetrieveKeysInjection } returns RetrieveDiagnosisInjectionHelper( every { transRetrieveKeysInjection } returns RetrieveDiagnosisInjectionHelper(
TransactionCoroutineScope() TransactionCoroutineScope(),
GoogleAPIVersion()
) )
} }
every { AppInjector.component } returns appComponent every { AppInjector.component } returns appComponent
...@@ -52,6 +54,9 @@ class RetrieveDiagnosisKeysTransactionTest { ...@@ -52,6 +54,9 @@ class RetrieveDiagnosisKeysTransactionTest {
any() any()
) )
} returns mockk() } returns mockk()
coEvery {
InternalExposureNotificationClient.getVersion()
} returns 17000000L
coEvery { ApplicationConfigurationService.asyncRetrieveExposureConfiguration() } returns mockk() coEvery { ApplicationConfigurationService.asyncRetrieveExposureConfiguration() } returns mockk()
every { LocalData.googleApiToken(any()) } just Runs every { LocalData.googleApiToken(any()) } just Runs
every { LocalData.lastTimeDiagnosisKeysFromServerFetch() } returns Date() every { LocalData.lastTimeDiagnosisKeysFromServerFetch() } returns Date()
......
package de.rki.coronawarnapp.util
import com.google.android.gms.common.api.ApiException
import com.google.android.gms.common.api.CommonStatusCodes.API_NOT_CONNECTED
import com.google.android.gms.common.api.Status
import de.rki.coronawarnapp.nearby.InternalExposureNotificationClient
import io.kotest.matchers.shouldBe
import io.mockk.Called
import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.mockkObject
import io.mockk.unmockkObject
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runBlockingTest
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
@ExperimentalCoroutinesApi
internal class GoogleAPIVersionTest {
private lateinit var classUnderTest: GoogleAPIVersion
@BeforeEach
fun setUp() {
mockkObject(InternalExposureNotificationClient)
classUnderTest = GoogleAPIVersion()
}
@AfterEach
fun tearDown() {
unmockkObject(InternalExposureNotificationClient)
}
@Test
fun `isAbove API v16 is true for v17`() {
coEvery { InternalExposureNotificationClient.getVersion() } returns 17000000L
runBlockingTest {
classUnderTest.isAbove(GoogleAPIVersion.V16) shouldBe true
}
}
@Test
fun `isAbove API v16 is false for v15`() {
coEvery { InternalExposureNotificationClient.getVersion() } returns 15000000L
runBlockingTest {
classUnderTest.isAbove(GoogleAPIVersion.V16) shouldBe false
}
}
@Test
fun `isAbove API v16 throws IllegalArgument for invalid version`() {
assertThrows<IllegalArgumentException> {
runBlockingTest {
classUnderTest.isAbove(1L)
}
coVerify {
InternalExposureNotificationClient.getVersion() wasNot Called
}
}
}
@Test
fun `isAbove API v16 false when APIException for too low version`() {
coEvery { InternalExposureNotificationClient.getVersion() } throws
ApiException(Status(API_NOT_CONNECTED))
runBlockingTest {
classUnderTest.isAbove(GoogleAPIVersion.V16) shouldBe false
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment