From d38c1067186426684057d2a1243fb6c8f70a21b9 Mon Sep 17 00:00:00 2001 From: Matthias Urhahn <matthias.urhahn@sap.com> Date: Wed, 18 Nov 2020 14:44:42 +0100 Subject: [PATCH] Fix config default values not being used if protobuf is missing the data structures (EXPOSUREAPP-3856) (#1649) * Improve logging. * Fix exposure detection config not using default values if protobuf structures are null. * Fix key download config not using default values if protobuf structures are null. Co-authored-by: Ralf Gehrer <ralfgehrer@users.noreply.github.com> --- .../appconfig/ExposureDetectionConfig.kt | 2 +- .../appconfig/internal/AppConfigSource.kt | 2 + .../mapping/ExposureDetectionConfigMapper.kt | 34 ++++++++------- .../mapping/KeyDownloadParametersMapper.kt | 42 ++++++++++++------- .../coronawarnapp/risk/DefaultRiskLevels.kt | 3 -- .../mapping/DownloadConfigMapperTest.kt | 14 +++++++ .../ExposureDetectionConfigMapperTest.kt | 15 ++++++- 7 files changed, 78 insertions(+), 34 deletions(-) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/ExposureDetectionConfig.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/ExposureDetectionConfig.kt index be47c2f17..7f44f8f89 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/ExposureDetectionConfig.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/ExposureDetectionConfig.kt @@ -12,7 +12,7 @@ interface ExposureDetectionConfig { val overallDetectionTimeout: Duration val exposureDetectionConfiguration: ExposureConfiguration - val exposureDetectionParameters: ExposureDetectionParameters.ExposureDetectionParametersAndroid + val exposureDetectionParameters: ExposureDetectionParameters.ExposureDetectionParametersAndroid? interface Mapper : ConfigMapper<ExposureDetectionConfig> } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/internal/AppConfigSource.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/internal/AppConfigSource.kt index 4ea21f387..1e5cc4959 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/internal/AppConfigSource.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/internal/AppConfigSource.kt @@ -24,6 +24,8 @@ class AppConfigSource @Inject constructor( if (localConfig != null && localConfig.isValid(timeStamper.nowUTC)) { Timber.tag(TAG).d("Returning local config, still valid.") return localConfig + } else { + Timber.tag(TAG).d("Local app config was unavailable(${localConfig == null} or invalid.") } val remoteConfig = remoteAppConfigSource.getConfigData() diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/mapping/ExposureDetectionConfigMapper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/mapping/ExposureDetectionConfigMapper.kt index 92473af00..841ecadb2 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/mapping/ExposureDetectionConfigMapper.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/mapping/ExposureDetectionConfigMapper.kt @@ -12,7 +12,11 @@ import javax.inject.Inject @Reusable class ExposureDetectionConfigMapper @Inject constructor() : ExposureDetectionConfig.Mapper { override fun map(rawConfig: AppConfig.ApplicationConfiguration): ExposureDetectionConfig { - val exposureParams = rawConfig.androidExposureDetectionParameters + val exposureParams = if (rawConfig.hasAndroidExposureDetectionParameters()) { + rawConfig.androidExposureDetectionParameters + } else { + null + } return ExposureDetectionConfigContainer( exposureDetectionConfiguration = rawConfig.mapRiskScoreToExposureConfiguration(), exposureDetectionParameters = exposureParams, @@ -24,7 +28,7 @@ class ExposureDetectionConfigMapper @Inject constructor() : ExposureDetectionCon data class ExposureDetectionConfigContainer( override val exposureDetectionConfiguration: ExposureConfiguration, - override val exposureDetectionParameters: ExposureDetectionParametersAndroid, + override val exposureDetectionParameters: ExposureDetectionParametersAndroid?, override val maxExposureDetectionsPerUTCDay: Int, override val minTimeBetweenDetections: Duration, override val overallDetectionTimeout: Duration @@ -33,23 +37,25 @@ class ExposureDetectionConfigMapper @Inject constructor() : ExposureDetectionCon // If we are outside the valid data range, fallback to default value. @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) -fun ExposureDetectionParametersAndroid.overAllDetectionTimeout(): Duration = when { - overallTimeoutInSeconds > 3600 -> Duration.standardMinutes(15) - overallTimeoutInSeconds <= 0 -> Duration.standardMinutes(15) - else -> Duration.standardSeconds(overallTimeoutInSeconds.toLong()) -} +fun ExposureDetectionParametersAndroid?.overAllDetectionTimeout(): Duration = + if (this == null || overallTimeoutInSeconds > 3600 || overallTimeoutInSeconds <= 0) { + Duration.standardMinutes(15) + } else { + Duration.standardSeconds(overallTimeoutInSeconds.toLong()) + } // If we are outside the valid data range, fallback to default value. @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) -fun ExposureDetectionParametersAndroid.maxExposureDetectionsPerDay(): Int = when { - maxExposureDetectionsPerInterval > 6 -> 6 - maxExposureDetectionsPerInterval < 0 -> 6 - else -> maxExposureDetectionsPerInterval -} +fun ExposureDetectionParametersAndroid?.maxExposureDetectionsPerDay(): Int = + if (this == null || maxExposureDetectionsPerInterval > 6 || maxExposureDetectionsPerInterval < 0) { + 6 + } else { + maxExposureDetectionsPerInterval + } @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) -fun ExposureDetectionParametersAndroid.minTimeBetweenExposureDetections(): Duration { - val detectionsPerDay = maxExposureDetectionsPerDay() +fun ExposureDetectionParametersAndroid?.minTimeBetweenExposureDetections(): Duration { + val detectionsPerDay = this.maxExposureDetectionsPerDay() return if (detectionsPerDay == 0) { Duration.standardDays(99) } else { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/mapping/KeyDownloadParametersMapper.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/mapping/KeyDownloadParametersMapper.kt index 4c55393ec..80a6ddc68 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/mapping/KeyDownloadParametersMapper.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/mapping/KeyDownloadParametersMapper.kt @@ -16,7 +16,11 @@ import javax.inject.Inject @Reusable class KeyDownloadParametersMapper @Inject constructor() : KeyDownloadConfig.Mapper { override fun map(rawConfig: AppConfig.ApplicationConfiguration): KeyDownloadConfig { - val rawParameters = rawConfig.androidKeyDownloadParameters + val rawParameters = if (rawConfig.hasAndroidKeyDownloadParameters()) { + rawConfig.androidKeyDownloadParameters + } else { + null + } return KeyDownloadConfigContainer( individualDownloadTimeout = rawParameters.individualTimeout(), @@ -27,21 +31,25 @@ class KeyDownloadParametersMapper @Inject constructor() : KeyDownloadConfig.Mapp } // If we are outside the valid data range, fallback to default value. - private fun KeyDownloadParametersAndroid.individualTimeout(): Duration = when { - downloadTimeoutInSeconds > 1800 -> Duration.standardSeconds(60) - downloadTimeoutInSeconds <= 0 -> Duration.standardSeconds(60) - else -> Duration.standardSeconds(downloadTimeoutInSeconds.toLong()) - } + private fun KeyDownloadParametersAndroid?.individualTimeout(): Duration = + if (this == null || downloadTimeoutInSeconds > 1800 || downloadTimeoutInSeconds <= 0) { + Duration.standardSeconds(60) + } else { + Duration.standardSeconds(downloadTimeoutInSeconds.toLong()) + } // If we are outside the valid data range, fallback to default value. - private fun KeyDownloadParametersAndroid.overAllTimeout(): Duration = when { - overallTimeoutInSeconds > 1800 -> Duration.standardMinutes(8) - overallTimeoutInSeconds <= 0 -> Duration.standardMinutes(8) - else -> Duration.standardSeconds(overallTimeoutInSeconds.toLong()) - } + private fun KeyDownloadParametersAndroid?.overAllTimeout(): Duration = + if (this == null || overallTimeoutInSeconds > 1800 || overallTimeoutInSeconds <= 0) { + Duration.standardMinutes(8) + } else { + Duration.standardSeconds(overallTimeoutInSeconds.toLong()) + } - private fun KeyDownloadParametersAndroid.mapDayEtags(): List<RevokedKeyPackage.Day> = - this.revokedDayPackagesList.mapNotNull { + private fun KeyDownloadParametersAndroid?.mapDayEtags(): List<RevokedKeyPackage.Day> { + if (this == null) return emptyList() + + return this.revokedDayPackagesList.mapNotNull { try { RevokedKeyPackage.Day( etag = it.etag, @@ -53,9 +61,12 @@ class KeyDownloadParametersMapper @Inject constructor() : KeyDownloadConfig.Mapp null } } + } - private fun KeyDownloadParametersAndroid.mapHourEtags(): List<RevokedKeyPackage.Hour> = - this.revokedHourPackagesList.mapNotNull { + private fun KeyDownloadParametersAndroid?.mapHourEtags(): List<RevokedKeyPackage.Hour> { + if (this == null) return emptyList() + + return this.revokedHourPackagesList.mapNotNull { try { RevokedKeyPackage.Hour( etag = it.etag, @@ -68,6 +79,7 @@ class KeyDownloadParametersMapper @Inject constructor() : KeyDownloadConfig.Mapp null } } + } data class KeyDownloadConfigContainer( override val individualDownloadTimeout: Duration, diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/DefaultRiskLevels.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/DefaultRiskLevels.kt index d0ca47e3b..37bb5130c 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/DefaultRiskLevels.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/DefaultRiskLevels.kt @@ -132,9 +132,6 @@ class DefaultRiskLevels @Inject constructor() : RiskLevels { "Active tracing time ($activeTracingDurationInHours h) is above threshold " + "($durationTracingIsActiveThreshold h): $it" ) - if (it) { - Timber.tag(TAG).v("Active tracing time is not enough") - } } } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/appconfig/mapping/DownloadConfigMapperTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/appconfig/mapping/DownloadConfigMapperTest.kt index 2d0ab66e1..7de0f9e96 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/appconfig/mapping/DownloadConfigMapperTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/appconfig/mapping/DownloadConfigMapperTest.kt @@ -4,6 +4,7 @@ import de.rki.coronawarnapp.diagnosiskeys.server.LocationCode import de.rki.coronawarnapp.server.protocols.internal.AppConfig import de.rki.coronawarnapp.server.protocols.internal.KeyDownloadParameters import io.kotest.matchers.shouldBe +import org.joda.time.Duration import org.joda.time.LocalDate import org.joda.time.LocalTime import org.junit.jupiter.api.Test @@ -59,4 +60,17 @@ class DownloadConfigMapperTest : BaseTest() { } } } + + @Test + fun `if the protobuf data structures are null we return defaults`() { + val rawConfig = AppConfig.ApplicationConfiguration.newBuilder() + .build() + + createInstance().map(rawConfig).apply { + revokedDayPackages shouldBe emptyList() + revokedHourPackages shouldBe emptyList() + overallDownloadTimeout shouldBe Duration.standardMinutes(8) + individualDownloadTimeout shouldBe Duration.standardSeconds(60) + } + } } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/appconfig/mapping/ExposureDetectionConfigMapperTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/appconfig/mapping/ExposureDetectionConfigMapperTest.kt index 7812c23ab..96fcb7387 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/appconfig/mapping/ExposureDetectionConfigMapperTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/appconfig/mapping/ExposureDetectionConfigMapperTest.kt @@ -17,8 +17,9 @@ class ExposureDetectionConfigMapperTest : BaseTest() { .setMinRiskScore(1) .build() createInstance().map(rawConfig).apply { + // This is basically the old legacy config without the new hourly related data structures exposureDetectionConfiguration shouldBe rawConfig.mapRiskScoreToExposureConfiguration() - exposureDetectionParameters shouldBe rawConfig.androidExposureDetectionParameters + exposureDetectionParameters shouldBe null } } @@ -77,4 +78,16 @@ class ExposureDetectionConfigMapperTest : BaseTest() { overallDetectionTimeout shouldBe Duration.standardMinutes(15) } } + + @Test + fun `if protobuf is missing the datastructure we return defaults`() { + val rawConfig = AppConfig.ApplicationConfiguration.newBuilder() + .setMinRiskScore(1) + .build() + createInstance().map(rawConfig).apply { + overallDetectionTimeout shouldBe Duration.standardMinutes(15) + minTimeBetweenDetections shouldBe Duration.standardHours(24 / 6) + maxExposureDetectionsPerUTCDay shouldBe 6 + } + } } -- GitLab