diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/contactdiary/DiaryEncounterCensor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/contactdiary/DiaryEncounterCensor.kt index 0814fd1f7235c1d2c45ecf1e013f2c9b6729454c..63c6cfc428590001c989c606794e555ffab87f9f 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/contactdiary/DiaryEncounterCensor.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/contactdiary/DiaryEncounterCensor.kt @@ -8,12 +8,13 @@ import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.plus import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNullIfUnmodified import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidComment import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebuggerScope +import de.rki.coronawarnapp.contactdiary.model.ContactDiaryPersonEncounter import de.rki.coronawarnapp.contactdiary.storage.repo.ContactDiaryRepository import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.filterNotNull -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import javax.inject.Inject @Reusable @@ -22,20 +23,22 @@ class DiaryEncounterCensor @Inject constructor( diary: ContactDiaryRepository ) : BugCensor { - private val encounters by lazy { - diary.personEncounters.stateIn( - scope = debugScope, - started = SharingStarted.Lazily, - initialValue = null - ).filterNotNull() + // We keep a history of all encounters so that we can censor them even after they got deleted + private val encounterHistory = mutableSetOf<ContactDiaryPersonEncounter>() + + val mutex = Mutex() + + init { + diary.personEncounters + .onEach { mutex.withLock { encounterHistory.addAll(it) } } + .launchIn(debugScope) } - override suspend fun checkLog(message: String): CensoredString? { - val encountersNow = encounters.first().filter { !it.circumstances.isNullOrBlank() } + override suspend fun checkLog(message: String): CensoredString? = mutex.withLock { - if (encountersNow.isEmpty()) return null + if (encounterHistory.isEmpty()) return null - val newMessage = encountersNow.fold(CensoredString(message)) { orig, encounter -> + val newMessage = encounterHistory.fold(CensoredString(message)) { orig, encounter -> var wip = orig withValidComment(encounter.circumstances) { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/contactdiary/DiaryLocationCensor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/contactdiary/DiaryLocationCensor.kt index 1ee60213595372dbb3e5fb6ebc8441ef377468be..e1439a50c1469658f2c81a10b3252a274ffe32eb 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/contactdiary/DiaryLocationCensor.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/contactdiary/DiaryLocationCensor.kt @@ -10,12 +10,13 @@ import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidEm import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidName import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidPhoneNumber import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebuggerScope +import de.rki.coronawarnapp.contactdiary.model.ContactDiaryLocation import de.rki.coronawarnapp.contactdiary.storage.repo.ContactDiaryRepository import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.filterNotNull -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import javax.inject.Inject @Reusable @@ -24,20 +25,21 @@ class DiaryLocationCensor @Inject constructor( diary: ContactDiaryRepository ) : BugCensor { - private val locations by lazy { - diary.locations.stateIn( - scope = debugScope, - started = SharingStarted.Lazily, - initialValue = null - ).filterNotNull() + private val mutex = Mutex() + + private var locationHistory = mutableSetOf<ContactDiaryLocation>() + + init { + diary.locations + .onEach { mutex.withLock { locationHistory.addAll(it) } } + .launchIn(debugScope) } - override suspend fun checkLog(message: String): CensoredString? { - val locationsNow = locations.first() + override suspend fun checkLog(message: String): CensoredString? = mutex.withLock { - if (locationsNow.isEmpty()) return null + if (locationHistory.isEmpty()) return null - val newMessage = locationsNow.fold(CensoredString(message)) { orig, location -> + val newMessage = locationHistory.fold(CensoredString(message)) { orig, location -> var wip = orig withValidName(location.locationName) { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/contactdiary/DiaryPersonCensor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/contactdiary/DiaryPersonCensor.kt index d525cde21fd60cc4dc3ffa9e6ad237c14140531e..52f542fc4350aa8bf218879148294e4134b3a250 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/contactdiary/DiaryPersonCensor.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/contactdiary/DiaryPersonCensor.kt @@ -10,12 +10,13 @@ import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidEm import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidName import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidPhoneNumber import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebuggerScope +import de.rki.coronawarnapp.contactdiary.model.ContactDiaryPerson import de.rki.coronawarnapp.contactdiary.storage.repo.ContactDiaryRepository import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.filterNotNull -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import javax.inject.Inject @Reusable @@ -24,20 +25,22 @@ class DiaryPersonCensor @Inject constructor( diary: ContactDiaryRepository ) : BugCensor { - private val persons by lazy { - diary.people.stateIn( - scope = debugScope, - started = SharingStarted.Lazily, - initialValue = null - ).filterNotNull() + private val mutex = Mutex() + + // We keep a history of all persons so that we can censor them even after they got deleted + private val personHistory = mutableSetOf<ContactDiaryPerson>() + + init { + diary.people + .onEach { mutex.withLock { personHistory.addAll(it) } } + .launchIn(debugScope) } - override suspend fun checkLog(message: String): CensoredString? { - val personsNow = persons.first() + override suspend fun checkLog(message: String): CensoredString? = mutex.withLock { - if (personsNow.isEmpty()) return null + if (personHistory.isEmpty()) return null - val newMessage = personsNow.fold(CensoredString(message)) { orig, person -> + val newMessage = personHistory.fold(CensoredString(message)) { orig, person -> var wip = orig withValidName(person.fullName) { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/contactdiary/DiaryVisitCensor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/contactdiary/DiaryVisitCensor.kt index 61398937d7a0f82b3823d1864ef91ac0b342b8fa..f08bfc69db37440967acd31172e5ce0c4f7275bc 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/contactdiary/DiaryVisitCensor.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/contactdiary/DiaryVisitCensor.kt @@ -7,12 +7,13 @@ import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.censor import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.plus import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNullIfUnmodified import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebuggerScope +import de.rki.coronawarnapp.contactdiary.model.ContactDiaryLocationVisit import de.rki.coronawarnapp.contactdiary.storage.repo.ContactDiaryRepository import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.filterNotNull -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import javax.inject.Inject @Reusable @@ -21,20 +22,26 @@ class DiaryVisitCensor @Inject constructor( diary: ContactDiaryRepository ) : BugCensor { - private val visits by lazy { - diary.locationVisits.stateIn( - scope = debugScope, - started = SharingStarted.Lazily, - initialValue = null - ).filterNotNull() + private val mutex = Mutex() + + private val visitsHistory = mutableSetOf<ContactDiaryLocationVisit>() + + init { + diary.locationVisits + .onEach { locationVisitList -> + val visitsWithCircumstances = locationVisitList.filterNot { it.circumstances.isNullOrBlank() } + mutex.withLock { + visitsHistory.addAll(visitsWithCircumstances) + } + } + .launchIn(debugScope) } - override suspend fun checkLog(message: String): CensoredString? { - val visitsNow = visits.first().filter { !it.circumstances.isNullOrBlank() } + override suspend fun checkLog(message: String): CensoredString? = mutex.withLock { - if (visitsNow.isEmpty()) return null + if (visitsHistory.isEmpty()) return null - val newMessage = visitsNow.fold(CensoredString(message)) { orig, visit -> + val newMessage = visitsHistory.fold(CensoredString(message)) { orig, visit -> var wip = orig BugCensor.withValidComment(visit.circumstances) { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/presencetracing/CheckInsCensor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/presencetracing/CheckInsCensor.kt index 018f5208b7686fd6b57bd24d5fa756a634ce713d..7cbede14a180730ca3d2f45efe804039bb737dbf 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/presencetracing/CheckInsCensor.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/presencetracing/CheckInsCensor.kt @@ -9,35 +9,36 @@ import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNullIfUnm import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidAddress import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidDescription import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebuggerScope +import de.rki.coronawarnapp.presencetracing.checkins.CheckIn import de.rki.coronawarnapp.presencetracing.checkins.CheckInRepository import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.filterNotNull -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import javax.inject.Inject @Reusable class CheckInsCensor @Inject constructor( @DebuggerScope debugScope: CoroutineScope, - private val checkInRepository: CheckInRepository + checkInRepository: CheckInRepository ) : BugCensor { - private val checkInsFlow by lazy { - checkInRepository.allCheckIns.stateIn( - scope = debugScope, - started = SharingStarted.Lazily, - initialValue = null - ).filterNotNull() - } + private val mutex = Mutex() + + private val checkInsHistory = mutableSetOf<CheckIn>() - override suspend fun checkLog(message: String): CensoredString? { + init { + checkInRepository.allCheckIns + .onEach { mutex.withLock { checkInsHistory.addAll(it) } } + .launchIn(debugScope) + } - val checkIns = checkInsFlow.first() + override suspend fun checkLog(message: String): CensoredString? = mutex.withLock { - if (checkIns.isEmpty()) return null + if (checkInsHistory.isEmpty()) return null - val newLogMsg = checkIns.fold(CensoredString(message)) { initial, checkIn -> + val newLogMsg = checkInsHistory.fold(CensoredString(message)) { initial, checkIn -> var acc = initial diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/presencetracing/TraceLocationCensor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/presencetracing/TraceLocationCensor.kt index 5f702727edc854a0382e020cd766a7753f46f494..cae77e40731e632bc380e509a64293bfd028006c 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/presencetracing/TraceLocationCensor.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/presencetracing/TraceLocationCensor.kt @@ -9,19 +9,20 @@ import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNullIfUnm import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidAddress import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidDescription import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebuggerScope +import de.rki.coronawarnapp.presencetracing.checkins.qrcode.TraceLocation import de.rki.coronawarnapp.presencetracing.locations.TraceLocationUserInput import de.rki.coronawarnapp.presencetracing.storage.repo.TraceLocationRepository import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.filterNotNull -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import javax.inject.Inject /** * Censors Trace Location Data * - * The information about which data to censor comes from two places + * The information about what data to censor comes from two places * - traceLocationRepository, for traceLocations that are already stored * - dataToCensor, which is set before a traceLocation is created; this is needed in cases when the app crashes between * data input and storing @@ -29,22 +30,22 @@ import javax.inject.Inject @Reusable class TraceLocationCensor @Inject constructor( @DebuggerScope debugScope: CoroutineScope, - private val traceLocationRepository: TraceLocationRepository + traceLocationRepository: TraceLocationRepository ) : BugCensor { - private val traceLocationsFlow by lazy { - traceLocationRepository.allTraceLocations.stateIn( - scope = debugScope, - started = SharingStarted.Lazily, - initialValue = null - ).filterNotNull() - } + private val mutex = Mutex() + + private val traceLocationHistory = mutableSetOf<TraceLocation>() - override suspend fun checkLog(message: String): CensoredString? { + init { + traceLocationRepository.allTraceLocations + .onEach { mutex.withLock { traceLocationHistory.addAll(it) } } + .launchIn(debugScope) + } - val traceLocations = traceLocationsFlow.first() + override suspend fun checkLog(message: String): CensoredString? = mutex.withLock { - var newLogMsg = traceLocations.fold(CensoredString(message)) { initial, traceLocation -> + var newLogMsg = traceLocationHistory.fold(CensoredString(message)) { initial, traceLocation -> var acc = initial acc += acc.censor(traceLocation.type.name, "TraceLocation#${traceLocation.id}/Type") diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/CoronaTestCensor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/CoronaTestCensor.kt index ccac2fe3de9b71c2e7bce5602ad393149d9de886..ea9d31a4fc46d6a0d37b76ab9c6e97721d9fc676 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/CoronaTestCensor.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/CoronaTestCensor.kt @@ -9,11 +9,9 @@ import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNullIfUnm import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebuggerScope import de.rki.coronawarnapp.coronatest.CoronaTestRepository import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.filterNotNull -import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import javax.inject.Inject @@ -21,7 +19,7 @@ import javax.inject.Inject @Reusable class CoronaTestCensor @Inject constructor( @DebuggerScope debugScope: CoroutineScope, - private val coronaTestRepository: CoronaTestRepository, + coronaTestRepository: CoronaTestRepository, ) : BugCensor { private val mutex = Mutex() @@ -30,20 +28,19 @@ class CoronaTestCensor @Inject constructor( private val tokenHistory = mutableSetOf<String>() private val identifierHistory = mutableSetOf<String>() - private val coronaTestFlow by lazy { - coronaTestRepository.coronaTests.stateIn( - scope = debugScope, - started = SharingStarted.Lazily, - initialValue = null - ).filterNotNull().onEach { tests -> - // The Registration Token is received after registration of PCR and RAT tests. It is required to poll the test result. - tokenHistory.addAll(tests.map { it.registrationToken }) - identifierHistory.addAll(tests.map { it.identifier }) - } + init { + coronaTestRepository.coronaTests + .filterNotNull() + .onEach { tests -> + mutex.withLock { + // The Registration Token is received after registration of PCR and RAT tests. It is required to poll the test result. + tokenHistory.addAll(tests.map { it.registrationToken }) + identifierHistory.addAll(tests.map { it.identifier }) + } + }.launchIn(debugScope) } override suspend fun checkLog(message: String): CensoredString? = mutex.withLock { - coronaTestFlow.first() var newMessage = CensoredString(message) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/RACoronaTestCensor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/RACoronaTestCensor.kt index fff34729468c06bf30f6f95888bb17161512501b..b2eff318663524e5953a18989ece304814901b87 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/RACoronaTestCensor.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/RACoronaTestCensor.kt @@ -10,48 +10,50 @@ import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebuggerScope import de.rki.coronawarnapp.coronatest.CoronaTestRepository import de.rki.coronawarnapp.coronatest.type.rapidantigen.RACoronaTest import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.filterNotNull -import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import org.joda.time.format.DateTimeFormat import javax.inject.Inject class RACoronaTestCensor @Inject constructor( @DebuggerScope debugScope: CoroutineScope, - private val coronaTestRepository: CoronaTestRepository + coronaTestRepository: CoronaTestRepository ) : BugCensor { + private val mutex = Mutex() + private val dayOfBirthFormatter = DateTimeFormat.forPattern("yyyy-MM-dd") - private val coronaTestFlow by lazy { - coronaTestRepository.coronaTests.stateIn( - scope = debugScope, - started = SharingStarted.Lazily, - initialValue = null - ).filterNotNull() - } + // We keep a history of rat corona test so that we are able to censor even after they got deleted + private val ratCoronaTestHistory = mutableSetOf<RACoronaTest>() - override suspend fun checkLog(message: String): CensoredString? { + init { + coronaTestRepository + .coronaTests + .map { it.filterIsInstance<RACoronaTest>() } + .onEach { mutex.withLock { ratCoronaTestHistory.addAll(it) } } + .launchIn(debugScope) + } - val raCoronaTestFlow = coronaTestFlow.map { tests -> tests.filterIsInstance<RACoronaTest>() }.first() - val raCoronaTest = raCoronaTestFlow.firstOrNull() ?: return null + override suspend fun checkLog(message: String): CensoredString? = mutex.withLock { var newMessage = CensoredString(message) - with(raCoronaTest) { - withValidName(firstName) { firstName -> + ratCoronaTestHistory.forEach { ratCoronaTest -> + withValidName(ratCoronaTest.firstName) { firstName -> newMessage += newMessage.censor(firstName, "RATest/FirstName") } - withValidName(lastName) { lastName -> + withValidName(ratCoronaTest.lastName) { lastName -> newMessage += newMessage.censor(lastName, "RATest/LastName") } - val dateOfBirthString = dateOfBirth?.toString(dayOfBirthFormatter) ?: return@with - - newMessage += newMessage.censor(dateOfBirthString, "RATest/DateOfBirth") + ratCoronaTest.dateOfBirth?.toString(dayOfBirthFormatter)?.let { dateOfBirthString -> + newMessage += newMessage.censor(dateOfBirthString, "RATest/DateOfBirth") + } } return newMessage.toNullIfUnmodified() diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/CensorInjectionTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/CensorInjectionTest.kt index cf4989e79c22668f3f03905bd2d0845dd589b5f8..915ca4bb0b46e5c24d9890a5d6516565e5218ced 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/CensorInjectionTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/CensorInjectionTest.kt @@ -13,7 +13,9 @@ import de.rki.coronawarnapp.submission.SubmissionSettings import io.github.classgraph.ClassGraph import io.kotest.matchers.collections.shouldContainAll import io.kotest.matchers.shouldBe +import io.mockk.every import io.mockk.mockk +import kotlinx.coroutines.flow.flowOf import org.junit.jupiter.api.Test import testhelpers.BaseTest import timber.log.Timber @@ -67,7 +69,12 @@ class MockProvider { @Singleton @Provides - fun diary(): ContactDiaryRepository = mockk() + fun diary(): ContactDiaryRepository = mockk() { + every { people } returns flowOf(emptyList()) + every { personEncounters } returns flowOf(emptyList()) + every { locations } returns flowOf(emptyList()) + every { locationVisits } returns flowOf(emptyList()) + } @Singleton @Provides @@ -75,15 +82,21 @@ class MockProvider { @Singleton @Provides - fun coronaTestRepository(): CoronaTestRepository = mockk() + fun coronaTestRepository(): CoronaTestRepository = mockk() { + every { coronaTests } returns flowOf(emptySet()) + } @Singleton @Provides - fun checkInRepository(): CheckInRepository = mockk() + fun checkInRepository(): CheckInRepository = mockk() { + every { allCheckIns } returns flowOf(emptyList()) + } @Singleton @Provides - fun traceLocationRepository(): TraceLocationRepository = mockk() + fun traceLocationRepository(): TraceLocationRepository = mockk() { + every { allTraceLocations } returns flowOf(emptyList()) + } @Singleton @Provides diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/CheckInsCensorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/CheckInsCensorTest.kt index 9965c621541b55b972a5569e334d8da19ada3cf8..b49f0ac8ac868f5e10a95e4d5253217f490c1cc5 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/CheckInsCensorTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/CheckInsCensorTest.kt @@ -11,6 +11,7 @@ import io.mockk.mockk import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.runBlockingTest import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import testhelpers.BaseTest @@ -40,7 +41,7 @@ internal class CheckInsCensorTest : BaseTest() { } @Test - fun `checkLog() should return LogLine with censored check-in information`() = runBlocking { + fun `checkLog() should return LogLine with censored check-in information`() = runBlockingTest { every { checkInsRepo.allCheckIns } returns flowOf( listOf( mockCheckIn( @@ -68,9 +69,44 @@ internal class CheckInsCensorTest : BaseTest() { Let's go to CheckIn#1/Description in CheckIn#1/Address. Who needs the CheckIn#2/Description in CheckIn#2/Address? I doooo! """.trimIndent() + } - // censoring should still work after user deletes his check-ins - every { checkInsRepo.allCheckIns } returns flowOf(emptyList()) + @Test + fun `censoring should still work after user deletes his check-ins`() = runBlockingTest { + every { checkInsRepo.allCheckIns } returns flowOf( + listOf( + mockCheckIn( + checkInId = 1, + checkInDescription = "Moe's Tavern", + checkInAddress = "Near 742 Evergreen Terrace, 12345 Springfield" + ), + mockCheckIn( + checkInId = 2, + checkInDescription = "Kwik-E-Mart", + checkInAddress = "Some Street, 12345 Springfield" + ) + ), + listOf( + mockCheckIn( + checkInId = 1, + checkInDescription = "Moe's Tavern", + checkInAddress = "Near 742 Evergreen Terrace, 12345 Springfield" + ), + /* deleted: mockCheckIn( + checkInId = 2, + checkInDescription = "Kwik-E-Mart", + checkInAddress = "Some Street, 12345 Springfield" + )*/ + ) + ) + + val censor = createInstance(this) + + val logLineToCensor = + """ + Let's go to Moe's Tavern in Near 742 Evergreen Terrace, 12345 Springfield. + Who needs the Kwik-E-Mart in Some Street, 12345 Springfield? I doooo! + """.trimIndent() censor.checkLog(logLineToCensor)!!.string shouldBe """ Let's go to CheckIn#1/Description in CheckIn#1/Address. diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/DiaryEncounterCensorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/DiaryEncounterCensorTest.kt index 5f7b72554c16ae360c327856d4429c30df0dc799..75740a998fe5238d8e097c4a0c0abd956321205d 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/DiaryEncounterCensorTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/DiaryEncounterCensorTest.kt @@ -63,9 +63,31 @@ class DiaryEncounterCensorTest : BaseTest() { two persons Encounter#3/Circumstances, everyone disliked that. """.trimIndent() + } + + @Test + fun `censoring should still work after encounters are deleted`() = runBlockingTest { + every { diaryRepo.personEncounters } returns flowOf( + listOf( + mockEncounter(1, _circumstances = ""), + mockEncounter(2, _circumstances = "A rainy day"), + mockEncounter(3, "Spilled coffee on each others laptops") + ), + listOf( + mockEncounter(1, _circumstances = ""), + // "a rainy day" was deleted + mockEncounter(3, "Spilled coffee on each others laptops") + ) + ) + + val instance = createInstance(this) + val censorMe = + """ + On A rainy day, + two persons Spilled coffee on each others laptops, + everyone disliked that. + """.trimIndent() - // censoring should still work after encounters are deleted - every { diaryRepo.personEncounters } returns flowOf(emptyList()) instance.checkLog(censorMe)!!.string shouldBe """ On Encounter#2/Circumstances, diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/DiaryLocationCensorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/DiaryLocationCensorTest.kt index c708da3707548094dc2ad7840eac3b72d42af101..fbc4cd1af89a58d9a29a7b226f2b86d19c1f2c82 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/DiaryLocationCensorTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/DiaryLocationCensorTest.kt @@ -65,9 +65,30 @@ class DiaryLocationCensorTest : BaseTest() { Both agreed that their emails (Location#1/EMail|Location#3/EMail) are awesome, and that Location#2/Name doesn't exist as it has neither phonenumber (null) nor email (null). """.trimIndent() + } - // censoring should still work after locations are deleted - every { diaryRepo.locations } returns flowOf(emptyList()) + @Test + fun `censoring should still work after locations are deleted`() = runBlockingTest { + every { diaryRepo.locations } returns flowOf( + listOf( + mockLocation(1, "Munich", phone = "+49 089 3333", mail = "bürgermeister@münchen.de"), + mockLocation(2, "Bielefeld", phone = null, mail = null), + mockLocation(3, "Aachen", phone = "+49 0241 9999", mail = "karl@aachen.de") + ), + listOf( + mockLocation(1, "Munich", phone = "+49 089 3333", mail = "bürgermeister@münchen.de"), + // Bielefeld was deleted + mockLocation(3, "Aachen", phone = "+49 0241 9999", mail = "karl@aachen.de") + ) + ) + + val instance = createInstance(this) + val censorMe = + """ + Bürgermeister of Munich (+49 089 3333) and Karl of Aachen [+49 0241 9999] called each other. + Both agreed that their emails (bürgermeister@münchen.de|karl@aachen.de) are awesome, + and that Bielefeld doesn't exist as it has neither phonenumber (null) nor email (null). + """.trimIndent() instance.checkLog(censorMe)!!.string shouldBe """ Bürgermeister of Location#1/Name (Location#1/PhoneNumber) and Karl of Location#3/Name [Location#3/PhoneNumber] called each other. diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/DiaryPersonCensorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/DiaryPersonCensorTest.kt index 240c80f3c5cca78d36a651e4e8fe54e7c70b61bd..1d8ccac54698f3af2e230df487c937a034129972 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/DiaryPersonCensorTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/DiaryPersonCensorTest.kt @@ -66,9 +66,31 @@ class DiaryPersonCensorTest : BaseTest() { but Person#3/Name thought he had enough has had enough for today. A quick mail to Person#1/EMail confirmed this. """.trimIndent() + } + + @Test + fun `censoring should still work after people are deleted`() = runBlockingTest { + every { diaryRepo.people } returns flowOf( + listOf( + mockPerson(1, "Luka", phone = "+49 1234 7777", mail = "luka@sap.com"), + mockPerson(2, "Ralf", phone = null, mail = null), + mockPerson(3, "Matthias", phone = null, mail = "matthias@sap.com") + ), + listOf( + mockPerson(1, "Luka", phone = "+49 1234 7777", mail = "luka@sap.com"), + mockPerson(2, "Ralf", phone = null, mail = null), + // Matthias was deleted + ) + ) + + val instance = createInstance(this) + val censorMe = + """ + Ralf requested more coffee from +49 1234 7777, + but Matthias thought he had enough has had enough for today. + A quick mail to luka@sap.com confirmed this. + """.trimIndent() - // censoring should still work after people are deleted - every { diaryRepo.people } returns flowOf(emptyList()) instance.checkLog(censorMe)!!.string shouldBe """ Person#2/Name requested more coffee from Person#1/PhoneNumber, diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/DiaryVisitCensorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/DiaryVisitCensorTest.kt index cdd31e2a544b5ed96cf3f386ddd945bd1e18f987..3f554b853a6c7274f7c3f9ad9de3988200f29142 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/DiaryVisitCensorTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/DiaryVisitCensorTest.kt @@ -61,9 +61,29 @@ class DiaryVisitCensorTest : BaseTest() { I got my Visit#2/Circumstances, only to find out the supermarket was Visit#3/Circumstances. """.trimIndent() + } - // censoring should still work even after visits are deleted - every { diaryRepo.locationVisits } returns flowOf(emptyList()) + @Test + fun `censor should still work even after visits are deleted`() = runBlockingTest { + every { diaryRepo.locationVisits } returns flowOf( + listOf( + mockVisit(1, _circumstances = "Döner that was too spicy"), + mockVisit(2, _circumstances = "beard shaved without mask"), + mockVisit(3, _circumstances = "out of toiletpaper") + ), + listOf( + mockVisit(1, _circumstances = "Döner that was too spicy"), + // mockVisit(2, _circumstances = "beard shaved without mask"), => deleted + mockVisit(3, _circumstances = "out of toiletpaper") + ) + ) + val instance = createInstance(this) + val censorMe = + """ + After having a Döner that was too spicy, + I got my beard shaved without mask, + only to find out the supermarket was out of toiletpaper. + """.trimIndent() instance.checkLog(censorMe)!!.string shouldBe """ After having a Visit#1/Circumstances, diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/RACoronaTestCensorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/RACoronaTestCensorTest.kt index 3a4e06d93b17e278a5fd95886d68b9e9f27c3405..fa2b323d34acf04aca761b881f6685670a40b8e9 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/RACoronaTestCensorTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/RACoronaTestCensorTest.kt @@ -11,6 +11,7 @@ import io.mockk.mockk import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.runBlockingTest import org.joda.time.LocalDate import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test @@ -31,7 +32,7 @@ internal class RACoronaTestCensorTest : BaseTest() { ) @Test - fun `checkLog() should return censored LogLine`() = runBlocking { + fun `checkLog() should return censored LogLine`() = runBlockingTest { every { coronaTestRepository.coronaTests } returns flowOf( setOf( mockk<RACoronaTest>().apply { @@ -53,9 +54,28 @@ internal class RACoronaTestCensorTest : BaseTest() { """ Hello! My name is RATest/FirstName. My friends call me Mister RATest/LastName and I was born on RATest/DateOfBirth. """.trimIndent() + } - // censoring should still work when test gets deleted - every { coronaTestRepository.coronaTests } returns flowOf(emptySet()) + @Test + fun `censoring should still work when test gets deleted`() = runBlockingTest { + every { coronaTestRepository.coronaTests } returns flowOf( + setOf( + mockk<RACoronaTest>().apply { + every { firstName } returns "John" + every { lastName } returns "Doe" + every { dateOfBirth } returns LocalDate.parse("2020-01-01") + } + ), + // Test got deleted + emptySet() + ) + + val censor = createInstance(this) + + val logLineToCensor = + """ + Hello! My name is John. My friends call me Mister Doe and I was born on 2020-01-01. + """.trimIndent() censor.checkLog(logLineToCensor)!!.string shouldBe """ @@ -91,8 +111,4 @@ internal class RACoronaTestCensorTest : BaseTest() { val logLine = "Lorem ipsum" censor.checkLog(logLine) shouldBe null } - - @Test - fun `censoring should still work when test gets deleted`() { - } } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/TraceLocationCensorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/TraceLocationCensorTest.kt index 92bd63b96555ef40094af42240631c45fb595c74..cb123802a53d20acd8349a4571f82d5eaa0adfc4 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/TraceLocationCensorTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/TraceLocationCensorTest.kt @@ -51,7 +51,7 @@ internal class TraceLocationCensorTest : BaseTest() { } @Test - fun `checkLog() should return LogLine with censored trace location information from repository`() = runBlocking { + fun `checkLog() should return LogLine with censored trace location information from repository`() = runBlockingTest { every { traceLocationRepo.allTraceLocations } returns flowOf( listOf( mockTraceLocation( @@ -82,9 +82,49 @@ internal class TraceLocationCensorTest : BaseTest() { The type is TraceLocation#2/Type. Yesterday we went to the TraceLocation#2/Description. The spectacle took place in TraceLocation#2/Address. Afterwards we had some food in TraceLocation#1/Description in TraceLocation#1/Address. It a nice TraceLocation#1/Type. """.trimIndent() + } - // censoring should still work after the user deletes his trace locations - every { traceLocationRepo.allTraceLocations } returns flowOf(emptyList()) + @Test + fun `censoring should still work after the user deletes his trace locations`() = runBlockingTest { + + every { traceLocationRepo.allTraceLocations } returns flowOf( + listOf( + mockTraceLocation( + traceLocationId = 1, + traceLocationType = TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_PERMANENT_FOOD_SERVICE, + traceLocationDescription = "Sushi Place", + traceLocationAddress = "Sushi Street 123, 12345 Fish Town" + ), + mockTraceLocation( + traceLocationId = 2, + traceLocationType = TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_TEMPORARY_CULTURAL_EVENT, + traceLocationDescription = "Rick Astley Concert", + traceLocationAddress = "Never gonna give you up street 1, 12345 RickRoll City" + ) + ), + listOf( + mockTraceLocation( + traceLocationId = 1, + traceLocationType = TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_PERMANENT_FOOD_SERVICE, + traceLocationDescription = "Sushi Place", + traceLocationAddress = "Sushi Street 123, 12345 Fish Town" + ), + /* deleted: mockTraceLocation( + traceLocationId = 2, + traceLocationType = TraceLocationOuterClass.TraceLocationType.LOCATION_TYPE_TEMPORARY_CULTURAL_EVENT, + traceLocationDescription = "Rick Astley Concert", + traceLocationAddress = "Never gonna give you up street 1, 12345 RickRoll City" + )*/ + ) + ) + + val censor = createInstance(this) + + val logLineToCensor = + """ + The type is LOCATION_TYPE_TEMPORARY_CULTURAL_EVENT. Yesterday we went to the Rick Astley Concert. The spectacle took place in Never gonna give you up street 1, 12345 RickRoll City. + Afterwards we had some food in Sushi Place in Sushi Street 123, 12345 Fish Town. It a nice LOCATION_TYPE_PERMANENT_FOOD_SERVICE. + """.trimIndent() censor.checkLog(logLineToCensor)!!.string shouldBe """ diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/submission/RatProfileCensorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/submission/RatProfileCensorTest.kt index 2134750ac4c2a2a86ff1a3abc64f99a755140b04..9954cd867b141eb7bb06b84ecaf4eefb40cbb81d 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/submission/RatProfileCensorTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/submission/RatProfileCensorTest.kt @@ -8,6 +8,7 @@ import io.mockk.every import io.mockk.impl.annotations.MockK import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.runBlockingTest import org.joda.time.format.DateTimeFormat import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test @@ -61,9 +62,17 @@ internal class RatProfileCensorTest : BaseTest() { censor.checkLog(logLine)!!.string shouldBe "Mister RAT-Profile/FirstName who is also known as RAT-Profile/LastName and is born on RAT-Profile/DateOfBirth lives in RAT-Profile/Street, " + "RAT-Profile/Zip-Code in the beautiful city of RAT-Profile/City. You can reach him by phone: RAT-Profile/Phone or email: RAT-Profile/eMail" + } - // censoring should still work after the user deletes his profile - every { ratProfileSettings.profile.flow } returns flowOf(null) + @Test + fun `censoring should still work after the user deletes his profile`() = runBlockingTest { + every { ratProfileSettings.profile.flow } returns flowOf(profile, null) + + val censor = createInstance() + + val logLine = + "Mister First name who is also known as Last name and is born on 1950-08-01 lives in Main street, " + + "12132 in the beautiful city of London. You can reach him by phone: 111111111 or email: email@example.com" censor.checkLog(logLine)!!.string shouldBe "Mister RAT-Profile/FirstName who is also known as RAT-Profile/LastName and is born on RAT-Profile/DateOfBirth lives in RAT-Profile/Street, " +