Skip to content
Snippets Groups Projects
Unverified Commit 66206efd authored by Kolya Opahle's avatar Kolya Opahle Committed by GitHub
Browse files

Risk Calculation does not work because DiagnosisKeysDataMapping is not applied...

Risk Calculation does not work because DiagnosisKeysDataMapping is not applied (EXPOSUREAPP-3895) (#1690)

* We now check for the DiagnosisKeyDataMapping and apply it to the ENFClient if changed

Signed-off-by: default avatarKolya Opahle <k.opahle@sap.com>

* Moved diagnosisKeysDataMapping to windowProvider

Signed-off-by: default avatarKolya Opahle <k.opahle@sap.com>

* Renaming and linting

Signed-off-by: default avatarKolya Opahle <k.opahle@sap.com>

* Moved app config fetch to key provide task, added error handling, added logging to config replace

Signed-off-by: default avatarKolya Opahle <k.opahle@sap.com>

* Fixed old unit tests and implemented tests for config comparison,
TestForAPIFragment is currently broken

Signed-off-by: default avatarKolya Opahle <k.opahle@sap.com>

* Linting

* Added more unit testing for DefaultDiagnosisKeysDataMapper and fixed TestForAPIFragment

Signed-off-by: default avatarKolya Opahle <k.opahle@sap.com>

* Update default app config to latest version

This includes a change for the default for reportTypeWhenMissing from
0 to 1, as 0 is not accepted by setDiagnosisKeysDataMapping.

https://github.com/corona-warn-app/cwa-app-tech-spec/pull/10/commits/090801921f4a8581543a9f716fd0572c12901c71
https://github.com/corona-warn-app/cwa-protocol-buffers/commit/38a641e2a808c41d225e9fd09d27ec7959551412



* Fixed Unittests

Co-authored-by: default avatarMaximilian Lenkeit <maximilian.lenkeit@sap.com>
Co-authored-by: default avatarharambasicluka <64483219+harambasicluka@users.noreply.github.com>
Co-authored-by: default avatarRalf Gehrer <ralfgehrer@users.noreply.github.com>
parent ec88c722
No related branches found
No related tags found
No related merge requests found
Showing
with 302 additions and 27 deletions
......@@ -26,6 +26,7 @@ import com.google.zxing.integration.android.IntentIntegrator
import com.google.zxing.integration.android.IntentResult
import com.google.zxing.qrcode.QRCodeWriter
import de.rki.coronawarnapp.R
import de.rki.coronawarnapp.appconfig.AppConfigProvider
import de.rki.coronawarnapp.databinding.FragmentTestForAPIBinding
import de.rki.coronawarnapp.exception.ExceptionCategory
import de.rki.coronawarnapp.exception.ExceptionCategory.INTERNAL
......@@ -65,6 +66,9 @@ class TestForAPIFragment : Fragment(R.layout.fragment_test_for_a_p_i),
@Inject lateinit var viewModelFactory: CWAViewModelFactoryProvider.Factory
@Inject lateinit var enfClient: ENFClient
// TODO: This is ugly, remove when refactoring the fragment
@Inject lateinit var appConfigProvider: AppConfigProvider
@Inject lateinit var riskLevelStorage: RiskLevelStorage
private val vm: TestForApiFragmentViewModel by cwaViewModels { viewModelFactory }
......@@ -291,7 +295,8 @@ class TestForAPIFragment : Fragment(R.layout.fragment_test_for_a_p_i),
try {
// only testing implementation: this is used to wait for the broadcastreceiver of the OS / EN API
enfClient.provideDiagnosisKeys(
googleFileList
googleFileList,
appConfigProvider.getAppConfig().diagnosisKeysDataMapping
)
showToast("Provided ${appleKeyList.size} keys to Google API")
} catch (e: Exception) {
......
No preview for this file type
3713298c705ee867f0b12cd2a05bc6209442baa156d8e38e19856a3a6b91a48e
\ No newline at end of file
665e82fa8d333eea36c5bda14f22f4519dc7d1a9dc890872ce8bc07880030bf1
\ No newline at end of file
package de.rki.coronawarnapp.appconfig
import com.google.android.gms.nearby.exposurenotification.DiagnosisKeysDataMapping
import de.rki.coronawarnapp.server.protocols.internal.v2.AppConfigAndroid
import de.rki.coronawarnapp.server.protocols.internal.v2.RiskCalculationParametersOuterClass
......@@ -13,6 +14,7 @@ interface ExposureWindowRiskCalculationConfig {
List<RiskCalculationParametersOuterClass.NormalizedTimeToRiskLevelMapping>
val normalizedTimePerDayToRiskLevelMappingList:
List<RiskCalculationParametersOuterClass.NormalizedTimeToRiskLevelMapping>
val diagnosisKeysDataMapping: DiagnosisKeysDataMapping
interface Mapper {
fun map(rawConfig: AppConfigAndroid.ApplicationConfigurationAndroid): ExposureWindowRiskCalculationConfig
......
package de.rki.coronawarnapp.appconfig.mapping
import com.google.android.gms.nearby.exposurenotification.DiagnosisKeysDataMapping
import dagger.Reusable
import de.rki.coronawarnapp.appconfig.ExposureWindowRiskCalculationConfig
import de.rki.coronawarnapp.appconfig.internal.ApplicationConfigurationInvalidException
......@@ -18,6 +19,12 @@ class ExposureWindowRiskCalculationConfigMapper @Inject constructor() :
)
}
if (!rawConfig.hasDiagnosisKeysDataMapping()) {
throw ApplicationConfigurationInvalidException(
message = "Diagnosis Keys Data Mapping is missing"
)
}
val riskCalculationParameters = rawConfig.riskCalculationParameters
return ExposureWindowRiskCalculationContainer(
......@@ -34,10 +41,24 @@ class ExposureWindowRiskCalculationConfigMapper @Inject constructor() :
normalizedTimePerExposureWindowToRiskLevelMapping = riskCalculationParameters
.normalizedTimePerEWToRiskLevelMappingList,
normalizedTimePerDayToRiskLevelMappingList = riskCalculationParameters
.normalizedTimePerDayToRiskLevelMappingList
.normalizedTimePerDayToRiskLevelMappingList,
diagnosisKeysDataMapping = rawConfig.diagnosisKeysDataMapping()
)
}
private fun AppConfigAndroid.ApplicationConfigurationAndroid.diagnosisKeysDataMapping():
DiagnosisKeysDataMapping {
val diagnosisKeyDataMapping = this.diagnosisKeysDataMapping
return DiagnosisKeysDataMapping.DiagnosisKeysDataMappingBuilder()
.apply {
setDaysSinceOnsetToInfectiousness(diagnosisKeyDataMapping.daysSinceOnsetToInfectiousnessMap)
setInfectiousnessWhenDaysSinceOnsetMissing(
diagnosisKeysDataMapping.infectiousnessWhenDaysSinceOnsetMissing
)
setReportTypeWhenMissing(diagnosisKeysDataMapping.reportTypeWhenMissing)
}.build()
}
data class ExposureWindowRiskCalculationContainer(
override val minutesAtAttenuationFilters: List<RiskCalculationParametersOuterClass.MinutesAtAttenuationFilter>,
override val minutesAtAttenuationWeights: List<RiskCalculationParametersOuterClass.MinutesAtAttenuationWeight>,
......@@ -47,6 +68,7 @@ class ExposureWindowRiskCalculationConfigMapper @Inject constructor() :
override val normalizedTimePerExposureWindowToRiskLevelMapping:
List<RiskCalculationParametersOuterClass.NormalizedTimeToRiskLevelMapping>,
override val normalizedTimePerDayToRiskLevelMappingList:
List<RiskCalculationParametersOuterClass.NormalizedTimeToRiskLevelMapping>
List<RiskCalculationParametersOuterClass.NormalizedTimeToRiskLevelMapping>,
override val diagnosisKeysDataMapping: DiagnosisKeysDataMapping
) : ExposureWindowRiskCalculationConfig
}
package de.rki.coronawarnapp.diagnosiskeys.download
import de.rki.coronawarnapp.appconfig.AppConfigProvider
import de.rki.coronawarnapp.appconfig.ConfigData
import de.rki.coronawarnapp.appconfig.ExposureDetectionConfig
import de.rki.coronawarnapp.diagnosiskeys.server.LocationCode
import de.rki.coronawarnapp.environment.EnvironmentSetup
......@@ -63,7 +64,7 @@ class DownloadDiagnosisKeysTask @Inject constructor(
throwIfCancelled()
// RETRIEVE RISK SCORE PARAMETERS
val exposureConfig: ExposureDetectionConfig = appConfigProvider.getAppConfig()
val exposureConfig: ConfigData = appConfigProvider.getAppConfig()
internalProgress.send(Progress.ApiSubmissionStarted)
internalProgress.send(Progress.KeyFilesDownloadStarted)
......@@ -102,7 +103,10 @@ class DownloadDiagnosisKeysTask @Inject constructor(
)
Timber.tag(TAG).d("Attempting submission to ENF")
val isSubmissionSuccessful = enfClient.provideDiagnosisKeys(availableKeyFiles)
val isSubmissionSuccessful = enfClient.provideDiagnosisKeys(
availableKeyFiles,
exposureConfig.diagnosisKeysDataMapping
)
Timber.tag(TAG).d("Diagnosis Keys provided (success=%s)", isSubmissionSuccessful)
// EXPOSUREAPP-3878 write timestamp immediately after submission,
......
......@@ -2,6 +2,7 @@
package de.rki.coronawarnapp.nearby
import com.google.android.gms.nearby.exposurenotification.DiagnosisKeysDataMapping
import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient
import com.google.android.gms.nearby.exposurenotification.ExposureWindow
import de.rki.coronawarnapp.nearby.modules.detectiontracker.ExposureDetectionTracker
......@@ -36,7 +37,10 @@ class ENFClient @Inject constructor(
internal val internalClient: ExposureNotificationClient
get() = googleENFClient
override suspend fun provideDiagnosisKeys(keyFiles: Collection<File>): Boolean {
override suspend fun provideDiagnosisKeys(
keyFiles: Collection<File>,
newDiagnosisKeysDataMapping: DiagnosisKeysDataMapping
): Boolean {
Timber.d("asyncProvideDiagnosisKeys(keyFiles=$keyFiles)")
return if (keyFiles.isEmpty()) {
......@@ -45,7 +49,7 @@ class ENFClient @Inject constructor(
} else {
Timber.d("Forwarding %d key files to our DiagnosisKeyProvider.", keyFiles.size)
exposureDetectionTracker.trackNewExposureDetection(UUID.randomUUID().toString())
diagnosisKeyProvider.provideDiagnosisKeys(keyFiles)
diagnosisKeyProvider.provideDiagnosisKeys(keyFiles, newDiagnosisKeysDataMapping)
}
}
......
......@@ -9,6 +9,8 @@ import de.rki.coronawarnapp.nearby.modules.detectiontracker.DefaultExposureDetec
import de.rki.coronawarnapp.nearby.modules.detectiontracker.ExposureDetectionTracker
import de.rki.coronawarnapp.nearby.modules.diagnosiskeyprovider.DefaultDiagnosisKeyProvider
import de.rki.coronawarnapp.nearby.modules.diagnosiskeyprovider.DiagnosisKeyProvider
import de.rki.coronawarnapp.nearby.modules.diagnosiskeysdatamapper.DefaultDiagnosisKeysDataMapper
import de.rki.coronawarnapp.nearby.modules.diagnosiskeysdatamapper.DiagnosisKeysDataMapper
import de.rki.coronawarnapp.nearby.modules.exposurewindow.DefaultExposureWindowProvider
import de.rki.coronawarnapp.nearby.modules.exposurewindow.ExposureWindowProvider
import de.rki.coronawarnapp.nearby.modules.locationless.DefaultScanningSupport
......@@ -48,6 +50,11 @@ class ENFModule {
fun exposureWindowProvider(exposureWindowProvider: DefaultExposureWindowProvider): ExposureWindowProvider =
exposureWindowProvider
@Singleton
@Provides
fun diagnosisKeysDataMapper(diagnosisKeysDataMapper: DefaultDiagnosisKeysDataMapper):
DiagnosisKeysDataMapper = diagnosisKeysDataMapper
@Singleton
@Provides
fun calculationTracker(exposureDetectionTracker: DefaultExposureDetectionTracker): ExposureDetectionTracker =
......
package de.rki.coronawarnapp.nearby.modules.diagnosiskeyprovider
import com.google.android.gms.common.api.ApiException
import com.google.android.gms.nearby.exposurenotification.DiagnosisKeysDataMapping
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.diagnosiskeysdatamapper.DiagnosisKeysDataMapper
import de.rki.coronawarnapp.nearby.modules.version.ENFVersion
import timber.log.Timber
import java.io.File
......@@ -17,10 +19,16 @@ import kotlin.coroutines.suspendCoroutine
class DefaultDiagnosisKeyProvider @Inject constructor(
private val enfVersion: ENFVersion,
private val submissionQuota: SubmissionQuota,
private val enfClient: ExposureNotificationClient
private val enfClient: ExposureNotificationClient,
private val diagnosisKeysDataMapper: DiagnosisKeysDataMapper
) : DiagnosisKeyProvider {
override suspend fun provideDiagnosisKeys(keyFiles: Collection<File>): Boolean {
override suspend fun provideDiagnosisKeys(
keyFiles: Collection<File>,
newDiagnosisKeysDataMapping: DiagnosisKeysDataMapping
): Boolean {
diagnosisKeysDataMapper.updateDiagnosisKeysDataMapping(newDiagnosisKeysDataMapping)
if (keyFiles.isEmpty()) {
Timber.d("No key files submitted, returning early.")
return true
......
package de.rki.coronawarnapp.nearby.modules.diagnosiskeyprovider
import com.google.android.gms.nearby.exposurenotification.DiagnosisKeysDataMapping
import java.io.File
interface DiagnosisKeyProvider {
......@@ -15,5 +16,8 @@ interface DiagnosisKeyProvider {
* @return
*/
suspend fun provideDiagnosisKeys(keyFiles: Collection<File>): Boolean
suspend fun provideDiagnosisKeys(
keyFiles: Collection<File>,
newDiagnosisKeysDataMapping: DiagnosisKeysDataMapping
): Boolean
}
package de.rki.coronawarnapp.nearby.modules.diagnosiskeysdatamapper
import com.google.android.gms.common.api.ApiException
import com.google.android.gms.nearby.exposurenotification.DiagnosisKeysDataMapping
import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient
import com.google.android.gms.nearby.exposurenotification.ExposureNotificationStatusCodes.FAILED_RATE_LIMITED
import timber.log.Timber
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine
@Singleton
class DefaultDiagnosisKeysDataMapper @Inject constructor(
private val client: ExposureNotificationClient
) : DiagnosisKeysDataMapper {
private suspend fun getDiagnosisKeysDataMapping(): DiagnosisKeysDataMapping? =
suspendCoroutine { cont ->
client.diagnosisKeysDataMapping
.addOnSuccessListener { cont.resume(it) }
.addOnFailureListener { cont.resumeWithException(it) }
}
private suspend fun setDiagnosisKeysDataMapping(diagnosisKeysDataMapping: DiagnosisKeysDataMapping) =
suspendCoroutine<Unit> { cont ->
client.setDiagnosisKeysDataMapping(diagnosisKeysDataMapping)
.addOnSuccessListener { cont.resume(Unit) }
.addOnFailureListener { cont.resumeWithException(it) }
}
override suspend fun updateDiagnosisKeysDataMapping(newDiagnosisKeysDataMapping: DiagnosisKeysDataMapping) {
val currentDiagnosisKeysDataMapping =
try {
getDiagnosisKeysDataMapping()
} catch (e: Exception) {
Timber.e("Failed to get the current DiagnosisKeysDataMapping assuming none present")
null
}
if (newDiagnosisKeysDataMapping.hasChanged(currentDiagnosisKeysDataMapping)) {
try {
Timber.i(
"Current DiagnosisKeysDataMapping: %s vs new: %s, applying new version.",
currentDiagnosisKeysDataMapping,
newDiagnosisKeysDataMapping
)
setDiagnosisKeysDataMapping(newDiagnosisKeysDataMapping)
} catch (e: ApiException) {
if (e.statusCode == FAILED_RATE_LIMITED) {
Timber.e(e, "Failed to setDiagnosisKeysDataMapping due to rate limit ")
} else {
throw e
}
}
}
}
companion object {
fun DiagnosisKeysDataMapping?.hasChanged(old: DiagnosisKeysDataMapping?): Boolean {
return old == null || old.hashCode() != hashCode()
}
}
}
package de.rki.coronawarnapp.nearby.modules.diagnosiskeysdatamapper
import com.google.android.gms.nearby.exposurenotification.DiagnosisKeysDataMapping
interface DiagnosisKeysDataMapper {
suspend fun updateDiagnosisKeysDataMapping(newDiagnosisKeysDataMapping: DiagnosisKeysDataMapping)
}
......@@ -47,7 +47,7 @@ class DefaultAppConfigSanityCheck : BaseTest() {
fun `current default matches checksum`() {
val config = context.assets.open(configName).readBytes()
val sha256 = context.assets.open(checkSumName).readBytes().toString(Charsets.UTF_8)
sha256 shouldBe "3713298c705ee867f0b12cd2a05bc6209442baa156d8e38e19856a3a6b91a48e"
sha256 shouldBe "665e82fa8d333eea36c5bda14f22f4519dc7d1a9dc890872ce8bc07880030bf1"
config.toSHA256() shouldBe sha256
}
......
......@@ -19,6 +19,7 @@ import io.mockk.coVerifySequence
import io.mockk.every
import io.mockk.impl.annotations.MockK
import io.mockk.just
import io.mockk.mockk
import io.mockk.verifySequence
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flowOf
......@@ -45,7 +46,7 @@ class ENFClientTest : BaseTest() {
@BeforeEach
fun setup() {
MockKAnnotations.init(this)
coEvery { diagnosisKeyProvider.provideDiagnosisKeys(any()) } returns true
coEvery { diagnosisKeyProvider.provideDiagnosisKeys(any(), any()) } returns true
every { exposureDetectionTracker.trackNewExposureDetection(any()) } just Runs
}
......@@ -75,19 +76,20 @@ class ENFClientTest : BaseTest() {
val client = createClient()
val keyFiles = listOf(File("test"))
coEvery { diagnosisKeyProvider.provideDiagnosisKeys(any()) } returns true
coEvery { diagnosisKeyProvider.provideDiagnosisKeys(any(), any()) } returns true
runBlocking {
client.provideDiagnosisKeys(keyFiles) shouldBe true
client.provideDiagnosisKeys(keyFiles, mockk()) shouldBe true
}
coEvery { diagnosisKeyProvider.provideDiagnosisKeys(any()) } returns false
coEvery { diagnosisKeyProvider.provideDiagnosisKeys(any(), any()) } returns false
runBlocking {
client.provideDiagnosisKeys(keyFiles) shouldBe false
client.provideDiagnosisKeys(keyFiles, mockk()) shouldBe false
}
coVerify(exactly = 2) {
diagnosisKeyProvider.provideDiagnosisKeys(
keyFiles
keyFiles,
any()
)
}
}
......@@ -97,13 +99,13 @@ class ENFClientTest : BaseTest() {
val client = createClient()
val keyFiles = emptyList<File>()
coEvery { diagnosisKeyProvider.provideDiagnosisKeys(any()) } returns true
coEvery { diagnosisKeyProvider.provideDiagnosisKeys(any(), any()) } returns true
runBlocking {
client.provideDiagnosisKeys(keyFiles) shouldBe true
client.provideDiagnosisKeys(keyFiles, mockk()) shouldBe true
}
coVerify(exactly = 0) {
diagnosisKeyProvider.provideDiagnosisKeys(any())
diagnosisKeyProvider.provideDiagnosisKeys(any(), any())
}
}
......
......@@ -2,16 +2,20 @@ 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.diagnosiskeysdatamapper.DiagnosisKeysDataMapper
import de.rki.coronawarnapp.nearby.modules.version.ENFVersion
import de.rki.coronawarnapp.nearby.modules.version.OutdatedENFVersionException
import io.kotest.matchers.shouldBe
import io.mockk.Called
import io.mockk.MockKAnnotations
import io.mockk.Runs
import io.mockk.clearAllMocks
import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.coVerifySequence
import io.mockk.impl.annotations.MockK
import io.mockk.just
import io.mockk.mockk
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.runBlockingTest
import org.junit.jupiter.api.AfterEach
......@@ -26,6 +30,7 @@ class DefaultDiagnosisKeyProviderTest : BaseTest() {
@MockK lateinit var googleENFClient: ExposureNotificationClient
@MockK lateinit var enfVersion: ENFVersion
@MockK lateinit var submissionQuota: SubmissionQuota
@MockK lateinit var diagnosisKeysDataMapper: DiagnosisKeysDataMapper
private val exampleKeyFiles = listOf(File("file1"), File("file2"))
......@@ -33,6 +38,8 @@ class DefaultDiagnosisKeyProviderTest : BaseTest() {
fun setup() {
MockKAnnotations.init(this)
coEvery { diagnosisKeysDataMapper.updateDiagnosisKeysDataMapping(any()) } just Runs
coEvery { submissionQuota.consumeQuota(any()) } returns true
coEvery { googleENFClient.provideDiagnosisKeys(any<List<File>>()) } returns MockGMSTask.forValue(null)
......@@ -50,7 +57,8 @@ class DefaultDiagnosisKeyProviderTest : BaseTest() {
private fun createProvider() = DefaultDiagnosisKeyProvider(
enfVersion = enfVersion,
submissionQuota = submissionQuota,
enfClient = googleENFClient
enfClient = googleENFClient,
diagnosisKeysDataMapper = diagnosisKeysDataMapper
)
@Test
......@@ -63,7 +71,7 @@ class DefaultDiagnosisKeyProviderTest : BaseTest() {
val provider = createProvider()
assertThrows<OutdatedENFVersionException> {
runBlockingTest { provider.provideDiagnosisKeys(exampleKeyFiles) } shouldBe false
runBlockingTest { provider.provideDiagnosisKeys(exampleKeyFiles, mockk()) } shouldBe false
}
coVerify {
......@@ -78,7 +86,7 @@ class DefaultDiagnosisKeyProviderTest : BaseTest() {
val provider = createProvider()
runBlocking { provider.provideDiagnosisKeys(exampleKeyFiles) } shouldBe true
runBlocking { provider.provideDiagnosisKeys(exampleKeyFiles, mockk()) } shouldBe true
coVerifySequence {
submissionQuota.consumeQuota(1)
......@@ -92,7 +100,7 @@ class DefaultDiagnosisKeyProviderTest : BaseTest() {
val provider = createProvider()
runBlocking { provider.provideDiagnosisKeys(exampleKeyFiles) } shouldBe true
runBlocking { provider.provideDiagnosisKeys(exampleKeyFiles, mockk()) } shouldBe true
coVerifySequence {
submissionQuota.consumeQuota(1)
......@@ -107,7 +115,7 @@ class DefaultDiagnosisKeyProviderTest : BaseTest() {
val provider = createProvider()
runBlocking { provider.provideDiagnosisKeys(exampleKeyFiles) } shouldBe true
runBlocking { provider.provideDiagnosisKeys(exampleKeyFiles, mockk()) } shouldBe true
coVerifySequence {
submissionQuota.consumeQuota(1)
......@@ -119,7 +127,7 @@ class DefaultDiagnosisKeyProviderTest : BaseTest() {
fun `provide empty key list`() {
val provider = createProvider()
runBlocking { provider.provideDiagnosisKeys(emptyList()) } shouldBe true
runBlocking { provider.provideDiagnosisKeys(emptyList(), mockk()) } shouldBe true
coVerify {
googleENFClient wasNot Called
......
package de.rki.coronawarnapp.nearby.modules.diagnosiskeysdatamapper
import com.google.android.gms.nearby.exposurenotification.DiagnosisKeysDataMapping
import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient
import com.google.android.gms.nearby.exposurenotification.Infectiousness
import com.google.android.gms.nearby.exposurenotification.ReportType
import de.rki.coronawarnapp.nearby.modules.diagnosiskeysdatamapper.DefaultDiagnosisKeysDataMapper.Companion.hasChanged
import io.kotest.matchers.shouldBe
import io.mockk.MockKAnnotations
import io.mockk.clearAllMocks
import io.mockk.coEvery
import io.mockk.impl.annotations.MockK
import io.mockk.verify
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import testhelpers.BaseTest
import testhelpers.coroutines.runBlockingTest2
import testhelpers.gms.MockGMSTask
class DefaultDiagnosisKeysDataMapperTest : BaseTest() {
@MockK lateinit var googleENFClient: ExposureNotificationClient
@BeforeEach
fun setup() {
MockKAnnotations.init(this)
}
@AfterEach
fun teardown() {
clearAllMocks()
}
private fun createMapper() = DefaultDiagnosisKeysDataMapper(
client = googleENFClient
)
@Test
fun `set mapping is invoked`() {
val firstMapping = DiagnosisKeysDataMapping.DiagnosisKeysDataMappingBuilder().apply {
setReportTypeWhenMissing(ReportType.CONFIRMED_TEST)
setInfectiousnessWhenDaysSinceOnsetMissing(Infectiousness.HIGH)
setDaysSinceOnsetToInfectiousness(mapOf(0 to Infectiousness.STANDARD, 1 to Infectiousness.HIGH))
}.build()
val secondMapping = DiagnosisKeysDataMapping.DiagnosisKeysDataMappingBuilder().apply {
setReportTypeWhenMissing(ReportType.CONFIRMED_TEST)
setInfectiousnessWhenDaysSinceOnsetMissing(Infectiousness.HIGH)
setDaysSinceOnsetToInfectiousness(mapOf(0 to Infectiousness.HIGH, 1 to Infectiousness.STANDARD))
}.build()
coEvery { googleENFClient.diagnosisKeysDataMapping } returns MockGMSTask.forValue(firstMapping)
coEvery { googleENFClient.setDiagnosisKeysDataMapping(any()) } returns MockGMSTask.forValue(null)
val mapper = createMapper()
runBlockingTest2 {
mapper.updateDiagnosisKeysDataMapping(secondMapping)
}
verify {
googleENFClient.setDiagnosisKeysDataMapping(secondMapping)
}
}
@Test
fun `set mapping is not invoked`() {
val firstMapping = DiagnosisKeysDataMapping.DiagnosisKeysDataMappingBuilder().apply {
setReportTypeWhenMissing(ReportType.CONFIRMED_TEST)
setInfectiousnessWhenDaysSinceOnsetMissing(Infectiousness.HIGH)
setDaysSinceOnsetToInfectiousness(mapOf(0 to Infectiousness.STANDARD, 1 to Infectiousness.HIGH))
}.build()
val secondMapping = DiagnosisKeysDataMapping.DiagnosisKeysDataMappingBuilder().apply {
setReportTypeWhenMissing(ReportType.CONFIRMED_TEST)
setInfectiousnessWhenDaysSinceOnsetMissing(Infectiousness.HIGH)
setDaysSinceOnsetToInfectiousness(mapOf(0 to Infectiousness.STANDARD, 1 to Infectiousness.HIGH))
}.build()
coEvery { googleENFClient.diagnosisKeysDataMapping } returns MockGMSTask.forValue(firstMapping)
coEvery { googleENFClient.setDiagnosisKeysDataMapping(any()) } returns MockGMSTask.forValue(null)
val mapper = createMapper()
runBlockingTest2 {
mapper.updateDiagnosisKeysDataMapping(secondMapping)
}
verify(exactly = 0) {
googleENFClient.setDiagnosisKeysDataMapping(secondMapping)
}
}
@Test
fun `mapping change detection works`() {
// Note that we cant create an empty mapping as the DiagnosisKeysDataMappingBuilder
// throws a IllegalArgumentException if one of the properties is missing
val nullMapping: DiagnosisKeysDataMapping? = null
val firstMapping = DiagnosisKeysDataMapping.DiagnosisKeysDataMappingBuilder().apply {
setReportTypeWhenMissing(ReportType.CONFIRMED_TEST)
setInfectiousnessWhenDaysSinceOnsetMissing(Infectiousness.HIGH)
setDaysSinceOnsetToInfectiousness(mapOf(0 to Infectiousness.STANDARD, 1 to Infectiousness.HIGH))
}.build()
val secondMapping = DiagnosisKeysDataMapping.DiagnosisKeysDataMappingBuilder().apply {
setReportTypeWhenMissing(ReportType.CONFIRMED_TEST)
setInfectiousnessWhenDaysSinceOnsetMissing(Infectiousness.HIGH)
setDaysSinceOnsetToInfectiousness(mapOf(0 to Infectiousness.HIGH, 1 to Infectiousness.STANDARD))
}.build()
val thirdMapping = DiagnosisKeysDataMapping.DiagnosisKeysDataMappingBuilder().apply {
setReportTypeWhenMissing(ReportType.CONFIRMED_TEST)
setInfectiousnessWhenDaysSinceOnsetMissing(Infectiousness.HIGH)
setDaysSinceOnsetToInfectiousness(mapOf())
}.build()
val fourthMapping = DiagnosisKeysDataMapping.DiagnosisKeysDataMappingBuilder().apply {
setReportTypeWhenMissing(ReportType.CONFIRMED_TEST)
setInfectiousnessWhenDaysSinceOnsetMissing(Infectiousness.HIGH)
setDaysSinceOnsetToInfectiousness(mapOf())
}.build()
firstMapping.hasChanged(nullMapping) shouldBe true
firstMapping.hasChanged(secondMapping) shouldBe true
firstMapping.hasChanged(thirdMapping) shouldBe true
secondMapping.hasChanged(nullMapping) shouldBe true
secondMapping.hasChanged(firstMapping) shouldBe true
secondMapping.hasChanged(thirdMapping) shouldBe true
thirdMapping.hasChanged(nullMapping) shouldBe true
thirdMapping.hasChanged(firstMapping) shouldBe true
thirdMapping.hasChanged(secondMapping) shouldBe true
nullMapping.hasChanged(nullMapping) shouldBe true
firstMapping.hasChanged(firstMapping) shouldBe false
secondMapping.hasChanged(secondMapping) shouldBe false
thirdMapping.hasChanged(thirdMapping) shouldBe false
thirdMapping.hasChanged(fourthMapping) 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