diff --git a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/presencetracing/ui/PresenceTracingTestViewModel.kt b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/presencetracing/ui/PresenceTracingTestViewModel.kt
index 7e0e674bcee1e3f48cb962d9a1f286e9ef20f8ba..dfb0d221f958bb44cadceaff6600824147254b68 100644
--- a/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/presencetracing/ui/PresenceTracingTestViewModel.kt
+++ b/Corona-Warn-App/src/deviceForTesters/java/de/rki/coronawarnapp/test/presencetracing/ui/PresenceTracingTestViewModel.kt
@@ -68,7 +68,7 @@ class PresenceTracingTestViewModel @AssistedInject constructor(
         taskRunTime.postValue(duration)
 
         val warningPackages = traceWarningRepository.allMetaData.first()
-        val overlaps = presenceTracingRiskRepository.checkInWarningOverlaps.first()
+        val overlaps = presenceTracingRiskRepository.overlapsOfLast14DaysPlusToday.first()
         val lastResult = presenceTracingRiskRepository.latestEntries(1).first().singleOrNull()
 
         val infoText = when {
@@ -99,7 +99,7 @@ class PresenceTracingTestViewModel @AssistedInject constructor(
                     riskCalculationRuntime.postValue(it)
                 },
                 {
-                    val checkInWarningOverlaps = presenceTracingRiskRepository.checkInWarningOverlaps.first()
+                    val checkInWarningOverlaps = presenceTracingRiskRepository.overlapsOfLast14DaysPlusToday.first()
                     val normalizedTimePerCheckInDayList =
                         presenceTracingRiskCalculator.calculateNormalizedTime(checkInWarningOverlaps)
                     val riskStates =
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/PtRiskLevelResult.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/PtRiskLevelResult.kt
index 541496f3bac86227cc1fe7204d8289961871def4..bc9bb66393317c88172eb6889ec8021d322aaab3 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/PtRiskLevelResult.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/PtRiskLevelResult.kt
@@ -7,44 +7,43 @@ import org.joda.time.Instant
 import org.joda.time.LocalDate
 
 /**
- * @param presenceTracingDayRisk Only available for the last calculation, if successful, otherwise null
- * @param checkInWarningOverlaps Only available for the last calculation, if successful, otherwise null
+ * @param presenceTracingDayRisk Only available for the latest calculation, otherwise null
+ * @param checkInWarningOverlaps Only available for the latest calculation, otherwise null
  */
 data class PtRiskLevelResult(
     val calculatedAt: Instant,
     val riskState: RiskState,
-    val presenceTracingDayRisk: List<PresenceTracingDayRisk>? = null,
+    private val presenceTracingDayRisk: List<PresenceTracingDayRisk>? = null,
     private val checkInWarningOverlaps: List<CheckInWarningOverlap>? = null,
 ) {
 
-    val wasSuccessfullyCalculated: Boolean
-        get() = riskState != RiskState.CALCULATION_FAILED
+    val wasSuccessfullyCalculated: Boolean by lazy {
+        riskState != RiskState.CALCULATION_FAILED
+    }
 
-    val numberOfDaysWithHighRisk: Int
-        get() = presenceTracingDayRisk?.count { it.riskState == RiskState.INCREASED_RISK } ?: 0
+    val numberOfDaysWithHighRisk: Int by lazy {
+        presenceTracingDayRisk?.count { it.riskState == RiskState.INCREASED_RISK } ?: 0
+    }
 
-    val numberOfDaysWithLowRisk: Int
-        get() = presenceTracingDayRisk?.count { it.riskState == RiskState.LOW_RISK } ?: 0
+    val numberOfDaysWithLowRisk: Int by lazy {
+        presenceTracingDayRisk?.count { it.riskState == RiskState.LOW_RISK } ?: 0
+    }
 
-    val mostRecentDateWithHighRisk: LocalDate?
-        get() = presenceTracingDayRisk
+    val mostRecentDateWithHighRisk: LocalDate? by lazy {
+        presenceTracingDayRisk
             ?.filter { it.riskState == RiskState.INCREASED_RISK }
             ?.maxByOrNull { it.localDateUtc }
             ?.localDateUtc
+    }
 
-    val mostRecentDateWithLowRisk: LocalDate?
-        get() = presenceTracingDayRisk
+    val mostRecentDateWithLowRisk: LocalDate? by lazy {
+        presenceTracingDayRisk
             ?.filter { it.riskState == RiskState.LOW_RISK }
             ?.maxByOrNull { it.localDateUtc }
             ?.localDateUtc
+    }
 
-    val daysWithEncounters: Int
-        get() = when (riskState) {
-            RiskState.INCREASED_RISK -> numberOfDaysWithHighRisk
-            RiskState.LOW_RISK -> numberOfDaysWithLowRisk
-            else -> 0
-        }
-
-    val checkInOverlapCount: Int
-        get() = checkInWarningOverlaps?.size ?: 0
+    val checkInOverlapCount: Int by lazy {
+        checkInWarningOverlaps?.size ?: 0
+    }
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/calculation/PresenceTracingRiskCalculator.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/calculation/PresenceTracingRiskCalculator.kt
index 568273ff125bcc1716ec8bc64d9ead1a201bc339..a2f9f0098e99fa5077a23dd43be7f48e11e76246 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/calculation/PresenceTracingRiskCalculator.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/calculation/PresenceTracingRiskCalculator.kt
@@ -38,18 +38,19 @@ class PresenceTracingRiskCalculator @Inject constructor(
         }
     }
 
-    suspend fun calculateAggregatedRiskPerDay(list: List<CheckInNormalizedTime>):
-        List<PresenceTracingDayRisk> {
-            return list.groupBy { it.localDateUtc }.map {
-                val normalizedTimePerDate = it.value.sumByDouble {
-                    it.normalizedTime
-                }
-                PresenceTracingDayRisk(
-                    localDateUtc = it.key,
-                    riskState = presenceTracingRiskMapper.lookupRiskStatePerDay(normalizedTimePerDate)
-                )
+    suspend fun calculateDayRisk(
+        list: List<CheckInNormalizedTime>
+    ): List<PresenceTracingDayRisk> {
+        return list.groupBy { it.localDateUtc }.map {
+            val normalizedTimePerDate = it.value.sumByDouble {
+                it.normalizedTime
             }
+            PresenceTracingDayRisk(
+                localDateUtc = it.key,
+                riskState = presenceTracingRiskMapper.lookupRiskStatePerDay(normalizedTimePerDate)
+            )
         }
+    }
 
     suspend fun calculateTotalRisk(list: List<CheckInNormalizedTime>): RiskState {
         if (list.isEmpty()) return RiskState.LOW_RISK
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/storage/PresenceTracingRiskRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/storage/PresenceTracingRiskRepository.kt
index 9dbccbc3e1b0c6c2a191cccde25f7eff674f2d82..1b356f35b51531d19136a1098fd3706e5b1193d8 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/storage/PresenceTracingRiskRepository.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/presencetracing/risk/storage/PresenceTracingRiskRepository.kt
@@ -46,27 +46,16 @@ class PresenceTracingRiskRepository @Inject constructor(
         database.presenceTracingRiskLevelResultDao()
     }
 
-    private val matchesOfLast14DaysPlusToday = traceTimeIntervalMatchDao.allMatches()
-        .map { timeIntervalMatchEntities ->
-            timeIntervalMatchEntities
-                .map { it.toCheckInWarningOverlap() }
-                .filter { it.localDateUtc.isAfter(fifteenDaysAgo.toLocalDateUtc()) }
-        }
-
-    val checkInWarningOverlaps: Flow<List<CheckInWarningOverlap>> =
-        traceTimeIntervalMatchDao.allMatches().map { matchEntities ->
-            matchEntities.map {
-                it.toCheckInWarningOverlap()
-            }
-        }
+    val overlapsOfLast14DaysPlusToday = traceTimeIntervalMatchDao.allMatches().map { entities ->
+        entities
+            .map { it.toCheckInWarningOverlap() }
+            .filter { it.localDateUtc.isAfter(fifteenDaysAgo.toLocalDateUtc()) }
+    }
 
-    private val normalizedTimeOfLast14DaysPlusToday = matchesOfLast14DaysPlusToday.map {
+    private val normalizedTimeOfLast14DaysPlusToday = overlapsOfLast14DaysPlusToday.map {
         presenceTracingRiskCalculator.calculateNormalizedTime(it)
     }
 
-    private val fifteenDaysAgo: Instant
-        get() = timeStamper.nowUTC.minus(Days.days(15).toStandardDuration())
-
     val traceLocationCheckInRiskStates: Flow<List<TraceLocationCheckInRisk>> =
         normalizedTimeOfLast14DaysPlusToday.map {
             presenceTracingRiskCalculator.calculateCheckInRiskPerDay(it)
@@ -74,7 +63,7 @@ class PresenceTracingRiskRepository @Inject constructor(
 
     val presenceTracingDayRisk: Flow<List<PresenceTracingDayRisk>> =
         normalizedTimeOfLast14DaysPlusToday.map {
-            presenceTracingRiskCalculator.calculateAggregatedRiskPerDay(it)
+            presenceTracingRiskCalculator.calculateDayRisk(it)
         }
 
     /**
@@ -120,39 +109,23 @@ class PresenceTracingRiskRepository @Inject constructor(
     }
 
     fun latestEntries(limit: Int) = riskLevelResultDao.latestEntries(limit).map { list ->
-        var lastSuccessfulFound = false
-        list.sortedByDescending {
-            it.calculatedAtMillis
-        }
-            .map { entity ->
-                if (!lastSuccessfulFound && entity.riskState != RiskState.CALCULATION_FAILED) {
-                    lastSuccessfulFound = true
-                    // add risk per day to the last successful result
-                    entity.toRiskLevelResult(
-                        presenceTracingDayRisks = presenceTracingDayRisk.first(),
-                        checkInWarningOverlaps = checkInWarningOverlaps.first(),
-                    )
-                } else {
-                    entity.toRiskLevelResult(
-                        presenceTracingDayRisks = null,
-                        checkInWarningOverlaps = null,
-                    )
-                }
-            }
+        list.sortAndComplementLatestResult()
     }
 
     fun allEntries() = riskLevelResultDao.allEntries().map { list ->
-        var lastSuccessfulFound = false
-        list.sortedByDescending {
+        list.sortAndComplementLatestResult()
+    }
+
+    private suspend fun List<PresenceTracingRiskLevelResultEntity>.sortAndComplementLatestResult() =
+        sortedByDescending {
             it.calculatedAtMillis
         }
-            .map { entity ->
-                if (!lastSuccessfulFound && entity.riskState != RiskState.CALCULATION_FAILED) {
-                    lastSuccessfulFound = true
-                    // add risk per day to the last successful result
+            .mapIndexed { index, entity ->
+                if (index == 0) {
+                    // add risk per day to the latest result
                     entity.toRiskLevelResult(
                         presenceTracingDayRisks = presenceTracingDayRisk.first(),
-                        checkInWarningOverlaps = checkInWarningOverlaps.first(),
+                        checkInWarningOverlaps = overlapsOfLast14DaysPlusToday.first(),
                     )
                 } else {
                     entity.toRiskLevelResult(
@@ -161,13 +134,15 @@ class PresenceTracingRiskRepository @Inject constructor(
                     )
                 }
             }
-    }
 
     private fun addResult(result: PtRiskLevelResult) {
         Timber.i("Saving risk calculation from ${result.calculatedAt} with result ${result.riskState}.")
         riskLevelResultDao.insert(result.toRiskLevelEntity())
     }
 
+    private val fifteenDaysAgo: Instant
+        get() = timeStamper.nowUTC.minus(Days.days(15).toStandardDuration())
+
     suspend fun clearAllTables() {
         traceTimeIntervalMatchDao.deleteAll()
         riskLevelResultDao.deleteAll()
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/presencetracing/risk/calculation/PresenceTracingRiskCalculatorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/presencetracing/risk/calculation/PresenceTracingRiskCalculatorTest.kt
index f59cd16228473db4a9530fa15857c09c758b048a..b0bfef2136687cb4c6cd327fe96b42c47814a1e3 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/presencetracing/risk/calculation/PresenceTracingRiskCalculatorTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/presencetracing/risk/calculation/PresenceTracingRiskCalculatorTest.kt
@@ -103,7 +103,7 @@ class PresenceTracingRiskCalculatorTest : BaseTest() {
         )
 
         runBlockingTest {
-            val result = createInstance().calculateAggregatedRiskPerDay(listOf(normTime))
+            val result = createInstance().calculateDayRisk(listOf(normTime))
             result.size shouldBe 1
             result[0].riskState shouldBe RiskState.CALCULATION_FAILED
         }
@@ -133,7 +133,7 @@ class PresenceTracingRiskCalculatorTest : BaseTest() {
         )
 
         runBlockingTest {
-            val result = createInstance().calculateAggregatedRiskPerDay(listOf(normTime, normTime2, normTime3))
+            val result = createInstance().calculateDayRisk(listOf(normTime, normTime2, normTime3))
             result.size shouldBe 2
             result.find { it.localDateUtc == localDate }!!.riskState shouldBe RiskState.INCREASED_RISK
             result.find { it.localDateUtc == localDate2 }!!.riskState shouldBe RiskState.LOW_RISK
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/presencetracing/risk/storage/PresenceTracingRiskRepositoryTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/presencetracing/risk/storage/PresenceTracingRiskRepositoryTest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..ab4464a2e41681105bb35eda245bdb5a662ba7dd
--- /dev/null
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/presencetracing/risk/storage/PresenceTracingRiskRepositoryTest.kt
@@ -0,0 +1,255 @@
+package de.rki.coronawarnapp.presencetracing.risk.storage
+
+import de.rki.coronawarnapp.presencetracing.risk.calculation.CheckInNormalizedTime
+import de.rki.coronawarnapp.presencetracing.risk.calculation.CheckInRiskPerDay
+import de.rki.coronawarnapp.presencetracing.risk.calculation.CheckInWarningOverlap
+import de.rki.coronawarnapp.presencetracing.risk.calculation.PresenceTracingDayRisk
+import de.rki.coronawarnapp.presencetracing.risk.calculation.PresenceTracingRiskCalculator
+import de.rki.coronawarnapp.risk.RiskState
+import de.rki.coronawarnapp.util.TimeAndDateExtensions.toLocalDateUtc
+import de.rki.coronawarnapp.util.TimeStamper
+import io.kotest.matchers.shouldBe
+import io.mockk.MockKAnnotations
+import io.mockk.Runs
+import io.mockk.coEvery
+import io.mockk.coVerify
+import io.mockk.every
+import io.mockk.impl.annotations.MockK
+import io.mockk.just
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.test.runBlockingTest
+import org.joda.time.Days
+import org.joda.time.Instant
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import testhelpers.BaseTest
+
+class PresenceTracingRiskRepositoryTest : BaseTest() {
+
+    @MockK lateinit var presenceTracingRiskCalculator: PresenceTracingRiskCalculator
+    @MockK lateinit var databaseFactory: PresenceTracingRiskDatabase.Factory
+    @MockK lateinit var timeStamper: TimeStamper
+    @MockK lateinit var traceTimeIntervalMatchDao: TraceTimeIntervalMatchDao
+    @MockK lateinit var riskLevelResultDao: PresenceTracingRiskLevelResultDao
+    @MockK lateinit var database: PresenceTracingRiskDatabase
+
+    private val now = Instant.ofEpochMilli(9999999)
+    private val fifteenDaysAgo = now.minus(Days.days(15).toStandardDuration())
+
+    @BeforeEach
+    fun setup() {
+        MockKAnnotations.init(this)
+        every { timeStamper.nowUTC } returns now
+
+        every { traceTimeIntervalMatchDao.allMatches() } returns flowOf(emptyList())
+        coEvery { traceTimeIntervalMatchDao.insert(any()) } just Runs
+        coEvery { traceTimeIntervalMatchDao.deleteMatchesForPackage(any()) } just Runs
+        coEvery { traceTimeIntervalMatchDao.deleteAll() } just Runs
+        coEvery { traceTimeIntervalMatchDao.deleteOlderThan(any()) } just Runs
+
+        every { riskLevelResultDao.insert(any()) } just Runs
+        coEvery { riskLevelResultDao.deleteOlderThan(any()) } just Runs
+
+        coEvery { databaseFactory.create() } returns database
+        every { database.traceTimeIntervalMatchDao() } returns traceTimeIntervalMatchDao
+        every { database.presenceTracingRiskLevelResultDao() } returns riskLevelResultDao
+
+        coEvery { presenceTracingRiskCalculator.calculateNormalizedTime(any()) } returns listOf()
+        coEvery { presenceTracingRiskCalculator.calculateTotalRisk(any()) } returns RiskState.LOW_RISK
+    }
+
+    @Test
+    fun `overlapsOfLast14DaysPlusToday works`() {
+        val entity = TraceTimeIntervalMatchEntity(
+            checkInId = 1L,
+            traceWarningPackageId = "traceWarningPackageId",
+            transmissionRiskLevel = 1,
+            startTimeMillis = fifteenDaysAgo.minus(100000).millis,
+            endTimeMillis = fifteenDaysAgo.millis
+        )
+        val entity2 = TraceTimeIntervalMatchEntity(
+            checkInId = 2L,
+            traceWarningPackageId = "traceWarningPackageId",
+            transmissionRiskLevel = 1,
+            startTimeMillis = now.minus(100000).millis,
+            endTimeMillis = now.minus(80000).millis
+        )
+        every { traceTimeIntervalMatchDao.allMatches() } returns flowOf(listOf(entity, entity2))
+        runBlockingTest {
+            val overlaps = createInstance().overlapsOfLast14DaysPlusToday.first()
+            overlaps.size shouldBe 1
+            overlaps[0].checkInId shouldBe 2L
+        }
+    }
+
+    @Test
+    fun `traceLocationCheckInRiskStates works`() {
+        val entity2 = TraceTimeIntervalMatchEntity(
+            checkInId = 2L,
+            traceWarningPackageId = "traceWarningPackageId",
+            transmissionRiskLevel = 1,
+            startTimeMillis = now.minus(100000).millis,
+            endTimeMillis = now.minus(80000).millis
+        )
+        every { traceTimeIntervalMatchDao.allMatches() } returns flowOf(listOf(entity2))
+        val time = CheckInNormalizedTime(
+            checkInId = 2L,
+            localDateUtc = now.minus(100000).toLocalDateUtc(),
+            normalizedTime = 20.0
+        )
+        val riskPerDay = CheckInRiskPerDay(
+            checkInId = 2L,
+            localDateUtc = now.minus(100000).toLocalDateUtc(),
+            riskState = RiskState.LOW_RISK
+        )
+        coEvery { presenceTracingRiskCalculator.calculateNormalizedTime(listOf(entity2.toCheckInWarningOverlap())) } returns listOf(
+            time
+        )
+        coEvery { presenceTracingRiskCalculator.calculateCheckInRiskPerDay(listOf(time)) } returns listOf(riskPerDay)
+        runBlockingTest {
+            val riskStates = createInstance().traceLocationCheckInRiskStates.first()
+            riskStates.size shouldBe 1
+            riskStates[0].checkInId shouldBe 2L
+            riskStates[0].riskState shouldBe RiskState.LOW_RISK
+        }
+    }
+
+    @Test
+    fun `presenceTracingDayRisk works`() {
+        val dayRisk = PresenceTracingDayRisk(
+            localDateUtc = now.minus(100000).toLocalDateUtc(),
+            riskState = RiskState.LOW_RISK
+        )
+        coEvery { presenceTracingRiskCalculator.calculateDayRisk(any()) } returns listOf(dayRisk)
+        runBlockingTest {
+            val risks = createInstance().presenceTracingDayRisk.first()
+            risks.size shouldBe 1
+            risks[0].riskState shouldBe RiskState.LOW_RISK
+        }
+    }
+
+    @Test
+    fun `latestEntries works`() {
+        val resultEntity = PresenceTracingRiskLevelResultEntity(
+            calculatedAtMillis = now.minus(100000).millis,
+            riskState = RiskState.LOW_RISK
+        )
+        val resultEntity2 = PresenceTracingRiskLevelResultEntity(
+            calculatedAtMillis = now.minus(10000).millis,
+            riskState = RiskState.LOW_RISK
+        )
+        coEvery { riskLevelResultDao.latestEntries(2) } returns flowOf(listOf(resultEntity, resultEntity2))
+        val matchEntity = TraceTimeIntervalMatchEntity(
+            checkInId = 1L,
+            traceWarningPackageId = "traceWarningPackageId",
+            transmissionRiskLevel = 1,
+            startTimeMillis = now.minus(100000).millis,
+            endTimeMillis = now.millis
+        )
+        val matchEntity2 = TraceTimeIntervalMatchEntity(
+            checkInId = 2L,
+            traceWarningPackageId = "traceWarningPackageId",
+            transmissionRiskLevel = 1,
+            startTimeMillis = now.minus(100000).millis,
+            endTimeMillis = now.minus(80000).millis
+        )
+        every { traceTimeIntervalMatchDao.allMatches() } returns flowOf(listOf(matchEntity, matchEntity2))
+        val dayRisk = PresenceTracingDayRisk(
+            localDateUtc = now.minus(100000).toLocalDateUtc(),
+            riskState = RiskState.LOW_RISK
+        )
+        coEvery { presenceTracingRiskCalculator.calculateDayRisk(any()) } returns listOf(dayRisk)
+        runBlockingTest {
+            val latest = createInstance().latestEntries(2).first()
+            latest.size shouldBe 2
+            latest[0].calculatedAt shouldBe now.minus(10000)
+            latest[0].checkInOverlapCount shouldBe 2
+            latest[1].calculatedAt shouldBe now.minus(100000)
+            latest[1].checkInOverlapCount shouldBe 0
+        }
+    }
+
+    @Test
+    fun `deleteStaleData works`() {
+        runBlockingTest {
+            createInstance().deleteStaleData()
+            coVerify {
+                traceTimeIntervalMatchDao.deleteOlderThan(fifteenDaysAgo.millis)
+                riskLevelResultDao.deleteOlderThan(fifteenDaysAgo.millis)
+            }
+        }
+    }
+
+    @Test
+    fun `deleteAllMatches works`() {
+        runBlockingTest {
+            createInstance().deleteAllMatches()
+            coVerify { traceTimeIntervalMatchDao.deleteAll() }
+        }
+    }
+
+    @Test
+    fun `report successful calculation works`() {
+        val traceWarningPackageId = "traceWarningPackageId"
+        val overlap = CheckInWarningOverlap(
+            checkInId = 1L,
+            transmissionRiskLevel = 1,
+            traceWarningPackageId = traceWarningPackageId,
+            startTime = Instant.ofEpochMilli(9991000),
+            endTime = Instant.ofEpochMilli(9997000)
+        )
+
+        val result = PresenceTracingRiskLevelResultEntity(
+            calculatedAtMillis = now.millis,
+            riskState = RiskState.LOW_RISK
+        )
+        runBlockingTest {
+            createInstance().reportCalculation(
+                successful = true,
+                overlaps = listOf(overlap)
+            )
+
+            coVerify {
+                traceTimeIntervalMatchDao.deleteMatchesForPackage(traceWarningPackageId)
+                traceTimeIntervalMatchDao.insert(listOf(overlap.toTraceTimeIntervalMatchEntity()))
+                riskLevelResultDao.insert(result)
+            }
+        }
+    }
+
+    @Test
+    fun `report failed calculation works`() {
+        val traceWarningPackageId = "traceWarningPackageId"
+        val overlap = CheckInWarningOverlap(
+            checkInId = 1L,
+            transmissionRiskLevel = 1,
+            traceWarningPackageId = traceWarningPackageId,
+            startTime = Instant.ofEpochMilli(9991000),
+            endTime = Instant.ofEpochMilli(9997000)
+        )
+
+        val result = PresenceTracingRiskLevelResultEntity(
+            calculatedAtMillis = now.millis,
+            riskState = RiskState.CALCULATION_FAILED
+        )
+        runBlockingTest {
+            createInstance().reportCalculation(
+                successful = false,
+                overlaps = listOf(overlap)
+            )
+
+            coVerify {
+                traceTimeIntervalMatchDao.deleteMatchesForPackage(traceWarningPackageId)
+                traceTimeIntervalMatchDao.insert(any())
+                riskLevelResultDao.insert(result)
+            }
+        }
+    }
+
+    private fun createInstance() = PresenceTracingRiskRepository(
+        presenceTracingRiskCalculator,
+        databaseFactory,
+        timeStamper
+    )
+}