From 37c1fbcc04f45948508aeabb5eea550ae045b681 Mon Sep 17 00:00:00 2001 From: Chilja Gossow <49635654+chiljamgossow@users.noreply.github.com> Date: Wed, 28 Apr 2021 16:32:09 +0200 Subject: [PATCH] Fix missing line in red warning card (EXPOSUREAPP-6775) (#2976) * provide data * fix test * klint * make sure only last 14 days are counted * fix test Co-authored-by: harambasicluka <64483219+harambasicluka@users.noreply.github.com> --- .../risk/storage/DefaultRiskLevelStorage.kt | 5 ++- .../risk/storage/DefaultRiskLevelStorage.kt | 3 ++ .../coronawarnapp/risk/CombinedEwPtRisk.kt | 21 +++++++-- .../coronawarnapp/risk/EwRiskLevelResult.kt | 11 ----- .../risk/storage/BaseRiskLevelStorage.kt | 22 ++++++++-- .../PersistedAggregatedRiskPerDateResult.kt | 2 +- .../risk/CombinedEwPtRiskTest.kt | 43 +++++++++++++++++-- .../risk/EwRiskLevelResultTest.kt | 37 ---------------- .../risk/storage/BaseRiskLevelStorageTest.kt | 3 +- .../storage/DefaultRiskLevelStorageTest.kt | 2 + .../storage/DefaultRiskLevelStorageTest.kt | 3 +- 11 files changed, 90 insertions(+), 62 deletions(-) diff --git a/Corona-Warn-App/src/device/java/de/rki/coronawarnapp/risk/storage/DefaultRiskLevelStorage.kt b/Corona-Warn-App/src/device/java/de/rki/coronawarnapp/risk/storage/DefaultRiskLevelStorage.kt index 0ab2b436c..014e3d72b 100644 --- a/Corona-Warn-App/src/device/java/de/rki/coronawarnapp/risk/storage/DefaultRiskLevelStorage.kt +++ b/Corona-Warn-App/src/device/java/de/rki/coronawarnapp/risk/storage/DefaultRiskLevelStorage.kt @@ -5,6 +5,7 @@ import de.rki.coronawarnapp.risk.EwRiskLevelResult import de.rki.coronawarnapp.risk.storage.internal.RiskCombinator import de.rki.coronawarnapp.risk.storage.internal.RiskResultDatabase import de.rki.coronawarnapp.util.coroutine.AppScope +import de.rki.coronawarnapp.util.TimeStamper import kotlinx.coroutines.CoroutineScope import timber.log.Timber import javax.inject.Inject @@ -16,11 +17,13 @@ class DefaultRiskLevelStorage @Inject constructor( presenceTracingRiskRepository: PresenceTracingRiskRepository, @AppScope scope: CoroutineScope, riskCombinator: RiskCombinator, + timeStamper: TimeStamper, ) : BaseRiskLevelStorage( riskResultDatabaseFactory, presenceTracingRiskRepository, scope, - riskCombinator + riskCombinator, + timeStamper, ) { // 2 days, 6 times per day, data is considered stale after 48 hours with risk calculation diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/risk/storage/DefaultRiskLevelStorage.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/risk/storage/DefaultRiskLevelStorage.kt index 23a0450fe..545f04c1e 100644 --- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/risk/storage/DefaultRiskLevelStorage.kt +++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/risk/storage/DefaultRiskLevelStorage.kt @@ -7,6 +7,7 @@ import de.rki.coronawarnapp.risk.storage.internal.RiskResultDatabase import de.rki.coronawarnapp.risk.storage.internal.windows.PersistedExposureWindowDao.PersistedScanInstance import de.rki.coronawarnapp.risk.storage.internal.windows.toPersistedExposureWindow import de.rki.coronawarnapp.risk.storage.internal.windows.toPersistedScanInstances +import de.rki.coronawarnapp.util.TimeStamper import de.rki.coronawarnapp.util.coroutine.AppScope import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.firstOrNull @@ -20,11 +21,13 @@ class DefaultRiskLevelStorage @Inject constructor( presenceTracingRiskRepository: PresenceTracingRiskRepository, @AppScope val scope: CoroutineScope, riskCombinator: RiskCombinator, + timeStamper: TimeStamper, ) : BaseRiskLevelStorage( riskResultDatabaseFactory, presenceTracingRiskRepository, scope, riskCombinator, + timeStamper, ) { // 14 days, 6 times per day diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/CombinedEwPtRisk.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/CombinedEwPtRisk.kt index cd5d3699d..e329e38b8 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/CombinedEwPtRisk.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/CombinedEwPtRisk.kt @@ -1,6 +1,8 @@ package de.rki.coronawarnapp.risk +import androidx.annotation.VisibleForTesting import de.rki.coronawarnapp.presencetracing.risk.PtRiskLevelResult +import de.rki.coronawarnapp.risk.result.ExposureWindowDayRisk import de.rki.coronawarnapp.risk.storage.internal.RiskCombinator import de.rki.coronawarnapp.util.TimeAndDateExtensions.toLocalDateUtc import org.joda.time.Instant @@ -13,7 +15,8 @@ data class CombinedEwPtDayRisk( data class CombinedEwPtRiskLevelResult( private val ptRiskLevelResult: PtRiskLevelResult, - private val ewRiskLevelResult: EwRiskLevelResult + private val ewRiskLevelResult: EwRiskLevelResult, + private val exposureWindowDayRisks: List<ExposureWindowDayRisk>? = null ) { val riskState: RiskState by lazy { @@ -31,12 +34,12 @@ data class CombinedEwPtRiskLevelResult( val daysWithEncounters: Int by lazy { when (riskState) { RiskState.INCREASED_RISK -> { - ewRiskLevelResult.daysWithHighRisk + ewDaysWithHighRisk .plus(ptRiskLevelResult.daysWithHighRisk) .distinct().count() } RiskState.LOW_RISK -> { - ewRiskLevelResult.daysWithLowRisk + ewDaysWithLowRisk .plus(ptRiskLevelResult.daysWithLowRisk) .distinct().count() } @@ -66,6 +69,18 @@ data class CombinedEwPtRiskLevelResult( val matchedRiskCount: Int by lazy { ewRiskLevelResult.matchedKeyCount + ptRiskLevelResult.checkInOverlapCount } + + @VisibleForTesting + internal val ewDaysWithHighRisk: List<LocalDate> + get() = exposureWindowDayRisks?.filter { + it.riskLevel.mapToRiskState() == RiskState.INCREASED_RISK + }?.map { it.localDateUtc } ?: emptyList() + + @VisibleForTesting + internal val ewDaysWithLowRisk: List<LocalDate> + get() = exposureWindowDayRisks?.filter { + it.riskLevel.mapToRiskState() == RiskState.LOW_RISK + }?.map { it.localDateUtc } ?: emptyList() } data class LastCombinedRiskResults( diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/EwRiskLevelResult.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/EwRiskLevelResult.kt index daa440e5a..397f47d17 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/EwRiskLevelResult.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/EwRiskLevelResult.kt @@ -3,7 +3,6 @@ package de.rki.coronawarnapp.risk import com.google.android.gms.nearby.exposurenotification.ExposureWindow import de.rki.coronawarnapp.risk.result.EwAggregatedRiskResult import org.joda.time.Instant -import org.joda.time.LocalDate interface EwRiskLevelResult { val calculatedAt: Instant @@ -43,16 +42,6 @@ interface EwRiskLevelResult { ewAggregatedRiskResult?.mostRecentDateWithLowRisk } - val daysWithHighRisk: List<LocalDate> - get() = ewAggregatedRiskResult?.exposureWindowDayRisks?.filter { - it.riskLevel.mapToRiskState() == RiskState.INCREASED_RISK - }?.map { it.localDateUtc } ?: emptyList() - - val daysWithLowRisk: List<LocalDate> - get() = ewAggregatedRiskResult?.exposureWindowDayRisks?.filter { - it.riskLevel.mapToRiskState() == RiskState.LOW_RISK - }?.map { it.localDateUtc } ?: emptyList() - enum class FailureReason(val failureCode: String) { UNKNOWN("unknown"), TRACING_OFF("tracingOff"), diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/storage/BaseRiskLevelStorage.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/storage/BaseRiskLevelStorage.kt index e7891623c..a483530c3 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/storage/BaseRiskLevelStorage.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/storage/BaseRiskLevelStorage.kt @@ -16,12 +16,16 @@ import de.rki.coronawarnapp.risk.storage.internal.riskresults.PersistedRiskLevel import de.rki.coronawarnapp.risk.storage.internal.riskresults.toPersistedAggregatedRiskPerDateResult import de.rki.coronawarnapp.risk.storage.internal.riskresults.toPersistedRiskResult import de.rki.coronawarnapp.risk.storage.internal.windows.PersistedExposureWindowDaoWrapper +import de.rki.coronawarnapp.util.TimeAndDateExtensions.toLocalDateUtc +import de.rki.coronawarnapp.util.TimeStamper import de.rki.coronawarnapp.util.flow.shareLatest import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map +import org.joda.time.Days +import org.joda.time.Instant import timber.log.Timber import de.rki.coronawarnapp.util.flow.combine as flowCombine @@ -30,6 +34,7 @@ abstract class BaseRiskLevelStorage constructor( private val presenceTracingRiskRepository: PresenceTracingRiskRepository, scope: CoroutineScope, private val riskCombinator: RiskCombinator, + private val timeStamper: TimeStamper, ) : RiskLevelStorage { private val database by lazy { riskResultDatabaseFactory.create() } @@ -37,6 +42,9 @@ abstract class BaseRiskLevelStorage constructor( internal val exposureWindowsTables by lazy { database.exposureWindows() } internal val aggregatedRiskPerDateResultTables by lazy { database.aggregatedRiskPerDate() } + private val fifteenDaysAgo: Instant + get() = timeStamper.nowUTC.minus(Days.days(15).toStandardDuration()) + abstract val storedResultLimit: Int private suspend fun List<PersistedRiskLevelResultDao>.combineWithWindows( @@ -131,7 +139,7 @@ abstract class BaseRiskLevelStorage constructor( aggregatedRiskPerDateResultTables.allEntries() .map { it.map { persistedAggregatedRiskPerDateResult -> - persistedAggregatedRiskPerDateResult.toAggregatedRiskPerDateResult() + persistedAggregatedRiskPerDateResult.toExposureWindowDayRisk() } } .shareLatest(tag = TAG, scope = scope) @@ -187,15 +195,21 @@ abstract class BaseRiskLevelStorage constructor( override val latestAndLastSuccessfulCombinedEwPtRiskLevelResult: Flow<LastCombinedRiskResults> get() = combine( allEwRiskLevelResults, - presenceTracingRiskRepository.allEntries() - ) { ewRiskLevelResults, ptRiskLevelResults -> + presenceTracingRiskRepository.allEntries(), + ewDayRiskStates + ) { ewRiskLevelResults, ptRiskLevelResults, ewDayRiskStates -> val combinedResults = riskCombinator .combineEwPtRiskLevelResults(ptRiskLevelResults, ewRiskLevelResults) .sortedByDescending { it.calculatedAt } LastCombinedRiskResults( - lastCalculated = combinedResults.firstOrNull() ?: riskCombinator.latestCombinedResult, + lastCalculated = combinedResults.firstOrNull()?.copy( + // need to provide the data here as they are null in EwAggregatedRiskResult + exposureWindowDayRisks = ewDayRiskStates.filter { ewDayRisk -> + ewDayRisk.localDateUtc.isAfter(fifteenDaysAgo.toLocalDateUtc()) + } + ) ?: riskCombinator.latestCombinedResult, lastSuccessfullyCalculated = combinedResults.find { it.wasSuccessfullyCalculated } ?: riskCombinator.initialCombinedResult diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/storage/internal/riskresults/PersistedAggregatedRiskPerDateResult.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/storage/internal/riskresults/PersistedAggregatedRiskPerDateResult.kt index dcd8a3bca..c12514e22 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/storage/internal/riskresults/PersistedAggregatedRiskPerDateResult.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/risk/storage/internal/riskresults/PersistedAggregatedRiskPerDateResult.kt @@ -14,7 +14,7 @@ data class PersistedAggregatedRiskPerDateResult( @ColumnInfo(name = "minimumDistinctEncountersWithLowRisk") val minimumDistinctEncountersWithLowRisk: Int, @ColumnInfo(name = "minimumDistinctEncountersWithHighRisk") val minimumDistinctEncountersWithHighRisk: Int ) { - fun toAggregatedRiskPerDateResult(): ExposureWindowDayRisk = + fun toExposureWindowDayRisk(): ExposureWindowDayRisk = ExposureWindowDayRisk( dateMillisSinceEpoch = dateMillisSinceEpoch, riskLevel = riskLevel, diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/CombinedEwPtRiskTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/CombinedEwPtRiskTest.kt index 18ec9e4c2..e53e0c16f 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/CombinedEwPtRiskTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/CombinedEwPtRiskTest.kt @@ -90,8 +90,6 @@ class CombinedEwPtRiskTest : BaseTest() { minimumDistinctEncountersWithHighRisk = 0 ) - every { ewAggregatedRiskResult.exposureWindowDayRisks } returns listOf(ewDayRisk, ewDayRisk2) - val ptDayRisk = PresenceTracingDayRisk( riskState = RiskState.LOW_RISK, localDateUtc = Instant.ofEpochMilli(1000).toLocalDateUtc() @@ -114,10 +112,49 @@ class CombinedEwPtRiskTest : BaseTest() { ewRiskLevelResult = createEwRiskLevel( calculatedAt = Instant.ofEpochMilli(1000 + 2 * MILLIS_DAY), ewAggregatedRiskResult - ) + ), + exposureWindowDayRisks = listOf(ewDayRisk, ewDayRisk2) ).daysWithEncounters shouldBe 3 } + @Test + fun `counts days correctly`() { + val dayRisk = ExposureWindowDayRisk( + dateMillisSinceEpoch = 1000, + riskLevel = RiskCalculationParametersOuterClass.NormalizedTimeToRiskLevelMapping.RiskLevel.HIGH, + minimumDistinctEncountersWithLowRisk = 0, + minimumDistinctEncountersWithHighRisk = 1 + ) + val dayRisk2 = ExposureWindowDayRisk( + dateMillisSinceEpoch = 1000 + MILLIS_DAY, + riskLevel = RiskCalculationParametersOuterClass.NormalizedTimeToRiskLevelMapping.RiskLevel.LOW, + minimumDistinctEncountersWithLowRisk = 1, + minimumDistinctEncountersWithHighRisk = 0 + ) + val dayRisk3 = ExposureWindowDayRisk( + dateMillisSinceEpoch = 1000 + 2 * MILLIS_DAY, + riskLevel = RiskCalculationParametersOuterClass.NormalizedTimeToRiskLevelMapping.RiskLevel.HIGH, + minimumDistinctEncountersWithLowRisk = 1, + minimumDistinctEncountersWithHighRisk = 2 + ) + + val result = CombinedEwPtRiskLevelResult( + ptRiskLevelResult = createPtRiskLevelResult( + calculatedAt = Instant.ofEpochMilli(1000 + 2 * MILLIS_DAY), + riskState = RiskState.LOW_RISK, + presenceTracingDayRisk = listOf() + ), + ewRiskLevelResult = createEwRiskLevel( + calculatedAt = Instant.ofEpochMilli(1000 + 2 * MILLIS_DAY), + ewAggregatedRiskResult + ), + exposureWindowDayRisks = listOf(dayRisk, dayRisk2, dayRisk3) + ) + + result.ewDaysWithHighRisk.size shouldBe 2 + result.ewDaysWithLowRisk.size shouldBe 1 + } + private fun createPtRiskLevelResult( calculatedAt: Instant, riskState: RiskState, diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/EwRiskLevelResultTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/EwRiskLevelResultTest.kt index c2bb7d546..0a6a80870 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/EwRiskLevelResultTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/EwRiskLevelResultTest.kt @@ -2,12 +2,8 @@ package de.rki.coronawarnapp.risk import com.google.android.gms.nearby.exposurenotification.ExposureWindow import de.rki.coronawarnapp.risk.result.EwAggregatedRiskResult -import de.rki.coronawarnapp.risk.result.ExposureWindowDayRisk -import de.rki.coronawarnapp.server.protocols.internal.v2.RiskCalculationParametersOuterClass.NormalizedTimeToRiskLevelMapping.RiskLevel import io.kotest.matchers.shouldBe import io.mockk.MockKAnnotations -import io.mockk.every -import io.mockk.impl.annotations.MockK import io.mockk.mockk import org.joda.time.Instant import org.junit.jupiter.api.BeforeEach @@ -16,8 +12,6 @@ import testhelpers.BaseTest class EwRiskLevelResultTest : BaseTest() { - @MockK lateinit var ewAggregatedRiskResult1: EwAggregatedRiskResult - @BeforeEach fun setup() { MockKAnnotations.init(this) @@ -36,35 +30,6 @@ class EwRiskLevelResultTest : BaseTest() { ).wasSuccessfullyCalculated shouldBe true } - @Test - fun `counts days correctly`() { - val dayRisk = ExposureWindowDayRisk( - dateMillisSinceEpoch = 1000, - riskLevel = RiskLevel.HIGH, - minimumDistinctEncountersWithLowRisk = 0, - minimumDistinctEncountersWithHighRisk = 1 - ) - val dayRisk2 = ExposureWindowDayRisk( - dateMillisSinceEpoch = 1000 + MILLIS_DAY, - riskLevel = RiskLevel.LOW, - minimumDistinctEncountersWithLowRisk = 1, - minimumDistinctEncountersWithHighRisk = 0 - ) - val dayRisk3 = ExposureWindowDayRisk( - dateMillisSinceEpoch = 1000 + 2 * MILLIS_DAY, - riskLevel = RiskLevel.HIGH, - minimumDistinctEncountersWithLowRisk = 1, - minimumDistinctEncountersWithHighRisk = 2 - ) - every { ewAggregatedRiskResult1.exposureWindowDayRisks } returns listOf(dayRisk, dayRisk2, dayRisk3) - val riskLevel = createRiskLevel( - ewAggregatedRiskResult = ewAggregatedRiskResult1, - failureReason = null - ) - riskLevel.daysWithHighRisk.size shouldBe 2 - riskLevel.daysWithLowRisk.size shouldBe 1 - } - private fun createRiskLevel( ewAggregatedRiskResult: EwAggregatedRiskResult?, failureReason: EwRiskLevelResult.FailureReason? @@ -76,5 +41,3 @@ class EwRiskLevelResultTest : BaseTest() { override val matchedKeyCount: Int = 0 } } - -private const val MILLIS_DAY = (1000 * 60 * 60 * 24).toLong() diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/storage/BaseRiskLevelStorageTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/storage/BaseRiskLevelStorageTest.kt index 4ad2bbd28..ead1de9a9 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/storage/BaseRiskLevelStorageTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/risk/storage/BaseRiskLevelStorageTest.kt @@ -103,6 +103,7 @@ class BaseRiskLevelStorageTest : BaseTest() { riskResultDatabaseFactory = databaseFactory, presenceTracingRiskRepository = presenceTracingRiskRepository, riskCombinator = riskCombinator, + timeStamper = timeStamper, ) { override val storedResultLimit: Int = storedResultLimit @@ -124,7 +125,7 @@ class BaseRiskLevelStorageTest : BaseTest() { val instance = createInstance() val allEntries = instance.aggregatedRiskPerDateResultTables.allEntries() allEntries shouldBe testPersistedAggregatedRiskPerDateResultFlow - allEntries.first().map { it.toAggregatedRiskPerDateResult() } shouldBe listOf( + allEntries.first().map { it.toExposureWindowDayRisk() } shouldBe listOf( testAggregatedRiskPerDateResult ) diff --git a/Corona-Warn-App/src/testDevice/java/de/rki/coronawarnapp/test/risk/storage/DefaultRiskLevelStorageTest.kt b/Corona-Warn-App/src/testDevice/java/de/rki/coronawarnapp/test/risk/storage/DefaultRiskLevelStorageTest.kt index 673ac7b96..da4cf340d 100644 --- a/Corona-Warn-App/src/testDevice/java/de/rki/coronawarnapp/test/risk/storage/DefaultRiskLevelStorageTest.kt +++ b/Corona-Warn-App/src/testDevice/java/de/rki/coronawarnapp/test/risk/storage/DefaultRiskLevelStorageTest.kt @@ -35,6 +35,7 @@ class DefaultRiskLevelStorageTest : BaseTest() { @MockK lateinit var riskResultTables: RiskResultDatabase.RiskResultsDao @MockK lateinit var exposureWindowTables: RiskResultDatabase.ExposureWindowsDao @MockK lateinit var presenceTracingRiskRepository: PresenceTracingRiskRepository + @MockK lateinit var timeStamper: TimeStamper private val testRiskLevelResultDao = PersistedRiskLevelResultDao( id = "riskresult-id", @@ -101,6 +102,7 @@ class DefaultRiskLevelStorageTest : BaseTest() { riskResultDatabaseFactory = databaseFactory, presenceTracingRiskRepository = presenceTracingRiskRepository, riskCombinator = RiskCombinator(TimeStamper()), + timeStamper = timeStamper, ) @Test diff --git a/Corona-Warn-App/src/testDeviceForTesters/java/de/rki/coronawarnapp/test/risk/storage/DefaultRiskLevelStorageTest.kt b/Corona-Warn-App/src/testDeviceForTesters/java/de/rki/coronawarnapp/test/risk/storage/DefaultRiskLevelStorageTest.kt index 5502ead59..75420cce3 100644 --- a/Corona-Warn-App/src/testDeviceForTesters/java/de/rki/coronawarnapp/test/risk/storage/DefaultRiskLevelStorageTest.kt +++ b/Corona-Warn-App/src/testDeviceForTesters/java/de/rki/coronawarnapp/test/risk/storage/DefaultRiskLevelStorageTest.kt @@ -97,7 +97,8 @@ class DefaultRiskLevelStorageTest : BaseTestInstrumentation() { scope = TestCoroutineScope(), riskResultDatabaseFactory = databaseFactory, presenceTracingRiskRepository = presenceTracingRiskRepository, - riskCombinator = RiskCombinator(TimeStamper()) + riskCombinator = RiskCombinator(TimeStamper()), + timeStamper = TimeStamper(), ) @Test -- GitLab