From 4e47438b8e9d78cbae7980917ecaa1a7fdf0af66 Mon Sep 17 00:00:00 2001 From: Matthias Urhahn <matthias.urhahn@sap.com> Date: Fri, 21 May 2021 12:40:18 +0200 Subject: [PATCH] Fix debug log censoring collisions (EXPOSUREAPP-7196) (#3230) * Detect censoring collision and replace whole line with placeholder. Give the debug logger an additional thread to parallelize censoring. * Smart censoring collision handling. * Tweak logging performance. * Adjusted unit tests to censoring changes. * Print stacktraces to debug log too! * Make KLINT happy * Adjust tests to changed log formatting. * Add tests for throwable formatting in debuglogger lines. * Re-enable debug tree. * Fix incorrect censoring range. We need the range of the original match, not it's replacement. * Fix duplicate new line if exceptions are logged. Co-authored-by: Kolya Opahle <k.opahle@sap.com> Co-authored-by: harambasicluka <64483219+harambasicluka@users.noreply.github.com> Co-authored-by: Mohamed Metwalli <mohamed.metwalli@sap.com> --- .../bugreporting/censors/BugCensor.kt | 40 ++++++++- .../contactdiary/DiaryEncounterCensor.kt | 14 ++-- .../contactdiary/DiaryLocationCensor.kt | 18 +++-- .../censors/contactdiary/DiaryPersonCensor.kt | 18 +++-- .../censors/contactdiary/DiaryVisitCensor.kt | 14 ++-- .../censors/presencetracing/CheckInsCensor.kt | 16 ++-- .../presencetracing/TraceLocationCensor.kt | 24 +++--- .../censors/submission/CoronaTestCensor.kt | 48 +++++++---- .../censors/submission/PcrQrCodeCensor.kt | 13 ++- .../censors/submission/RACoronaTestCensor.kt | 18 +++-- .../censors/submission/RatProfileCensor.kt | 31 ++++--- .../censors/submission/RatQrCodeCensor.kt | 22 ++--- .../vaccination/CertificateQrCodeCensor.kt | 57 +++++++------ .../bugreporting/debuglog/DebugLogger.kt | 28 ++++++- .../bugreporting/debuglog/LogLine.kt | 36 +++++++-- .../debuglog/internal/DebugLogStorageCheck.kt | 10 +-- .../debuglog/internal/DebugLoggerScope.kt | 3 +- .../debuglog/internal/LogWriter.kt | 13 +-- .../bugreporting/censors/BugCensorTest.kt | 16 +--- .../censors/CheckInsCensorTest.kt | 55 ++++--------- .../censors/CoronaTestCensorTest.kt | 48 +++-------- .../censors/DiaryEncounterCensorTest.kt | 81 ++++++------------- .../censors/DiaryLocationCensorTest.kt | 71 +++++----------- .../censors/DiaryPersonCensorTest.kt | 71 +++++----------- .../censors/DiaryVisitCensorTest.kt | 79 +++++------------- .../censors/PcrQrCodeCensorTest.kt | 29 +------ .../censors/RACoronaTestCensorTest.kt | 51 ++++-------- .../censors/RatQrCodeCensorTest.kt | 30 ++----- .../censors/TraceLocationCensorTest.kt | 77 ++++++------------ .../submission/RatProfileCensorTest.kt | 42 +++------- .../CertificateQrCodeCensorTest.kt | 55 +++---------- .../bugreporting/debuglog/DebugLoggerTest.kt | 63 +++++++++++---- .../bugreporting/debuglog/LogLineTest.kt | 39 +++++++++ .../internal/DebugLogStorageCheckTest.kt | 40 +++++---- .../debuglog/internal/LogSnapshotterTest.kt | 9 ++- 35 files changed, 571 insertions(+), 708 deletions(-) create mode 100644 Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/LogLineTest.kt diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/BugCensor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/BugCensor.kt index 48c13a4a7..57cf1c85a 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/BugCensor.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/BugCensor.kt @@ -1,15 +1,47 @@ package de.rki.coronawarnapp.bugreporting.censors -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine +import kotlin.math.max +import kotlin.math.min interface BugCensor { /** * If there is something to censor a new log line is returned, otherwise returns null */ - suspend fun checkLog(entry: LogLine): LogLine? + suspend fun checkLog(message: String): CensoredString? + + data class CensoredString( + // The censored version of the string + val string: String, + // The range that we censored + // If there is a collision, this range in the original needs to be removed. + val range: IntRange? = null + ) companion object { + operator fun CensoredString.plus(newer: CensoredString?): CensoredString { + if (newer == null) return this + + val range = when { + newer.range == null -> this.range + this.range == null -> newer.range + else -> min(this.range.first, newer.range.first)..max(this.range.last, newer.range.last) + } + + return CensoredString(string = newer.string, range = range) + } + + fun CensoredString.censor(orig: String, replacement: String): CensoredString? { + val start = this.string.indexOf(orig) + if (start == -1) return null + + val end = start + orig.length + return CensoredString( + string = this.string.replace(orig, replacement), + range = start..end + ) + } + fun withValidName(name: String?, action: (String) -> Unit): Boolean { if (name.isNullOrBlank()) return false if (name.length < 3) return false @@ -66,8 +98,8 @@ interface BugCensor { return true } - fun LogLine.toNewLogLineIfDifferent(newMessage: String): LogLine? { - return if (newMessage != message) copy(message = newMessage) else null + fun CensoredString.toNullIfUnmodified(): CensoredString? { + return if (range == null) null else this } } } 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 9c75a723f..0814fd1f7 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 @@ -2,9 +2,11 @@ package de.rki.coronawarnapp.bugreporting.censors.contactdiary import dagger.Reusable import de.rki.coronawarnapp.bugreporting.censors.BugCensor -import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNewLogLineIfDifferent +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.CensoredString +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.censors.BugCensor.Companion.withValidComment -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebuggerScope import de.rki.coronawarnapp.contactdiary.storage.repo.ContactDiaryRepository import kotlinx.coroutines.CoroutineScope @@ -28,21 +30,21 @@ class DiaryEncounterCensor @Inject constructor( ).filterNotNull() } - override suspend fun checkLog(entry: LogLine): LogLine? { + override suspend fun checkLog(message: String): CensoredString? { val encountersNow = encounters.first().filter { !it.circumstances.isNullOrBlank() } if (encountersNow.isEmpty()) return null - val newMessage = encountersNow.fold(entry.message) { orig, encounter -> + val newMessage = encountersNow.fold(CensoredString(message)) { orig, encounter -> var wip = orig withValidComment(encounter.circumstances) { - wip = wip.replace(it, "Encounter#${encounter.id}/Circumstances") + wip += wip.censor(it, "Encounter#${encounter.id}/Circumstances") } wip } - return entry.toNewLogLineIfDifferent(newMessage) + return newMessage.toNullIfUnmodified() } } 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 70628444c..1ee602135 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 @@ -2,11 +2,13 @@ package de.rki.coronawarnapp.bugreporting.censors.contactdiary import dagger.Reusable import de.rki.coronawarnapp.bugreporting.censors.BugCensor -import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNewLogLineIfDifferent +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.CensoredString +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.censors.BugCensor.Companion.withValidEmail import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidName import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidPhoneNumber -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebuggerScope import de.rki.coronawarnapp.contactdiary.storage.repo.ContactDiaryRepository import kotlinx.coroutines.CoroutineScope @@ -30,27 +32,27 @@ class DiaryLocationCensor @Inject constructor( ).filterNotNull() } - override suspend fun checkLog(entry: LogLine): LogLine? { + override suspend fun checkLog(message: String): CensoredString? { val locationsNow = locations.first() if (locationsNow.isEmpty()) return null - val newMessage = locationsNow.fold(entry.message) { orig, location -> + val newMessage = locationsNow.fold(CensoredString(message)) { orig, location -> var wip = orig withValidName(location.locationName) { - wip = wip.replace(it, "Location#${location.locationId}/Name") + wip += wip.censor(it, "Location#${location.locationId}/Name") } withValidEmail(location.emailAddress) { - wip = wip.replace(it, "Location#${location.locationId}/EMail") + wip += wip.censor(it, "Location#${location.locationId}/EMail") } withValidPhoneNumber(location.phoneNumber) { - wip = wip.replace(it, "Location#${location.locationId}/PhoneNumber") + wip += wip.censor(it, "Location#${location.locationId}/PhoneNumber") } wip } - return entry.toNewLogLineIfDifferent(newMessage) + return newMessage.toNullIfUnmodified() } } 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 a8a0056d9..d525cde21 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 @@ -2,11 +2,13 @@ package de.rki.coronawarnapp.bugreporting.censors.contactdiary import dagger.Reusable import de.rki.coronawarnapp.bugreporting.censors.BugCensor -import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNewLogLineIfDifferent +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.CensoredString +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.censors.BugCensor.Companion.withValidEmail import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidName import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidPhoneNumber -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebuggerScope import de.rki.coronawarnapp.contactdiary.storage.repo.ContactDiaryRepository import kotlinx.coroutines.CoroutineScope @@ -30,27 +32,27 @@ class DiaryPersonCensor @Inject constructor( ).filterNotNull() } - override suspend fun checkLog(entry: LogLine): LogLine? { + override suspend fun checkLog(message: String): CensoredString? { val personsNow = persons.first() if (personsNow.isEmpty()) return null - val newMessage = personsNow.fold(entry.message) { orig, person -> + val newMessage = personsNow.fold(CensoredString(message)) { orig, person -> var wip = orig withValidName(person.fullName) { - wip = wip.replace(it, "Person#${person.personId}/Name") + wip += wip.censor(it, "Person#${person.personId}/Name") } withValidEmail(person.emailAddress) { - wip = wip.replace(it, "Person#${person.personId}/EMail") + wip += wip.censor(it, "Person#${person.personId}/EMail") } withValidPhoneNumber(person.phoneNumber) { - wip = wip.replace(it, "Person#${person.personId}/PhoneNumber") + wip += wip.censor(it, "Person#${person.personId}/PhoneNumber") } wip } - return entry.toNewLogLineIfDifferent(newMessage) + return newMessage.toNullIfUnmodified() } } 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 f060c0fd2..61398937d 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 @@ -2,8 +2,10 @@ package de.rki.coronawarnapp.bugreporting.censors.contactdiary import dagger.Reusable import de.rki.coronawarnapp.bugreporting.censors.BugCensor -import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNewLogLineIfDifferent -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.CensoredString +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.storage.repo.ContactDiaryRepository import kotlinx.coroutines.CoroutineScope @@ -27,21 +29,21 @@ class DiaryVisitCensor @Inject constructor( ).filterNotNull() } - override suspend fun checkLog(entry: LogLine): LogLine? { + override suspend fun checkLog(message: String): CensoredString? { val visitsNow = visits.first().filter { !it.circumstances.isNullOrBlank() } if (visitsNow.isEmpty()) return null - val newMessage = visitsNow.fold(entry.message) { orig, visit -> + val newMessage = visitsNow.fold(CensoredString(message)) { orig, visit -> var wip = orig BugCensor.withValidComment(visit.circumstances) { - wip = wip.replace(it, "Visit#${visit.id}/Circumstances") + wip += wip.censor(it, "Visit#${visit.id}/Circumstances") } wip } - return entry.toNewLogLineIfDifferent(newMessage) + return newMessage.toNullIfUnmodified() } } 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 a5f10d81c..018f5208b 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 @@ -2,10 +2,12 @@ package de.rki.coronawarnapp.bugreporting.censors.presencetracing import dagger.Reusable import de.rki.coronawarnapp.bugreporting.censors.BugCensor -import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNewLogLineIfDifferent +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.CensoredString +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.censors.BugCensor.Companion.withValidAddress import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidDescription -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebuggerScope import de.rki.coronawarnapp.presencetracing.checkins.CheckInRepository import kotlinx.coroutines.CoroutineScope @@ -29,27 +31,27 @@ class CheckInsCensor @Inject constructor( ).filterNotNull() } - override suspend fun checkLog(entry: LogLine): LogLine? { + override suspend fun checkLog(message: String): CensoredString? { val checkIns = checkInsFlow.first() if (checkIns.isEmpty()) return null - val newLogMsg = checkIns.fold(entry.message) { initial, checkIn -> + val newLogMsg = checkIns.fold(CensoredString(message)) { initial, checkIn -> var acc = initial withValidDescription(checkIn.description) { description -> - acc = acc.replace(description, "CheckIn#${checkIn.id}/Description") + acc += acc.censor(description, "CheckIn#${checkIn.id}/Description") } withValidAddress(checkIn.address) { address -> - acc = acc.replace(address, "CheckIn#${checkIn.id}/Address") + acc += acc.censor(address, "CheckIn#${checkIn.id}/Address") } acc } - return entry.toNewLogLineIfDifferent(newLogMsg) + return newLogMsg.toNullIfUnmodified() } } 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 6d3f60ffb..5f702727e 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 @@ -2,10 +2,12 @@ package de.rki.coronawarnapp.bugreporting.censors.presencetracing import dagger.Reusable import de.rki.coronawarnapp.bugreporting.censors.BugCensor -import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNewLogLineIfDifferent +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.CensoredString +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.censors.BugCensor.Companion.withValidAddress import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidDescription -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebuggerScope import de.rki.coronawarnapp.presencetracing.locations.TraceLocationUserInput import de.rki.coronawarnapp.presencetracing.storage.repo.TraceLocationRepository @@ -38,21 +40,21 @@ class TraceLocationCensor @Inject constructor( ).filterNotNull() } - override suspend fun checkLog(entry: LogLine): LogLine? { + override suspend fun checkLog(message: String): CensoredString? { val traceLocations = traceLocationsFlow.first() - var newLogMsg = traceLocations.fold(entry.message) { initial, traceLocation -> + var newLogMsg = traceLocations.fold(CensoredString(message)) { initial, traceLocation -> var acc = initial - acc = acc.replace(traceLocation.type.name, "TraceLocation#${traceLocation.id}/Type") + acc += acc.censor(traceLocation.type.name, "TraceLocation#${traceLocation.id}/Type") withValidDescription(traceLocation.description) { description -> - acc = acc.replace(description, "TraceLocation#${traceLocation.id}/Description") + acc += acc.censor(description, "TraceLocation#${traceLocation.id}/Description") } withValidAddress(traceLocation.address) { address -> - acc = acc.replace(address, "TraceLocation#${traceLocation.id}/Address") + acc += acc.censor(address, "TraceLocation#${traceLocation.id}/Address") } acc @@ -60,18 +62,18 @@ class TraceLocationCensor @Inject constructor( val inputDataToCensor = dataToCensor if (inputDataToCensor != null) { - newLogMsg = newLogMsg.replace(inputDataToCensor.type.name, "TraceLocationUserInput#Type") + newLogMsg += newLogMsg.censor(inputDataToCensor.type.name, "TraceLocationUserInput#Type") withValidDescription(inputDataToCensor.description) { - newLogMsg = newLogMsg.replace(inputDataToCensor.description, "TraceLocationUserInput#Description") + newLogMsg += newLogMsg.censor(inputDataToCensor.description, "TraceLocationUserInput#Description") } withValidAddress(inputDataToCensor.address) { - newLogMsg = newLogMsg.replace(inputDataToCensor.address, "TraceLocationUserInput#Address") + newLogMsg += newLogMsg.censor(inputDataToCensor.address, "TraceLocationUserInput#Address") } } - return entry.toNewLogLineIfDifferent(newLogMsg) + return newLogMsg.toNullIfUnmodified() } companion object { 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 8958fe290..ccac2fe3d 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 @@ -2,44 +2,64 @@ package de.rki.coronawarnapp.bugreporting.censors.submission import dagger.Reusable import de.rki.coronawarnapp.bugreporting.censors.BugCensor -import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNewLogLineIfDifferent -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.CensoredString +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.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.onEach +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import javax.inject.Inject @Reusable class CoronaTestCensor @Inject constructor( + @DebuggerScope debugScope: CoroutineScope, private val coronaTestRepository: CoronaTestRepository, ) : BugCensor { + private val mutex = Mutex() + // Keep a history to have references even after the user deletes a test private val tokenHistory = mutableSetOf<String>() private val identifierHistory = mutableSetOf<String>() - override suspend fun checkLog(entry: LogLine): LogLine? { + 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 }) + } + } - // The Registration Token is received after registration of PCR and RAT tests. It is required to poll the test result. - val tokens = coronaTestRepository.coronaTests.first().map { it.registrationToken } - tokenHistory.addAll(tokens) + override suspend fun checkLog(message: String): CensoredString? = mutex.withLock { + coronaTestFlow.first() - val identifiers = coronaTestRepository.coronaTests.first().map { it.identifier } - identifierHistory.addAll(identifiers) + var newMessage = CensoredString(message) - var newMessage = entry.message for (token in tokenHistory) { - if (!entry.message.contains(token)) continue + if (!message.contains(token)) continue - newMessage = newMessage.replace(token, PLACEHOLDER + token.takeLast(4)) + newMessage += newMessage.censor(token, PLACEHOLDER + token.takeLast(4)) } identifierHistory - .filter { entry.message.contains(it) } + .filter { message.contains(it) } .forEach { - newMessage = newMessage.replace(it, "${it.take(11)}CoronaTest/Identifier") + newMessage += newMessage.censor(it, "${it.take(11)}CoronaTest/Identifier") } - return entry.toNewLogLineIfDifferent(newMessage) + return newMessage.toNullIfUnmodified() } companion object { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/PcrQrCodeCensor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/PcrQrCodeCensor.kt index 881a5396f..0c61dd0ca 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/PcrQrCodeCensor.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/PcrQrCodeCensor.kt @@ -2,21 +2,18 @@ package de.rki.coronawarnapp.bugreporting.censors.submission import dagger.Reusable import de.rki.coronawarnapp.bugreporting.censors.BugCensor -import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNewLogLineIfDifferent -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.CensoredString +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.censor import javax.inject.Inject @Reusable class PcrQrCodeCensor @Inject constructor() : BugCensor { - override suspend fun checkLog(entry: LogLine): LogLine? { - + override suspend fun checkLog(message: String): CensoredString? { val guid = lastGUID ?: return null - if (!entry.message.contains(guid)) return null - - val newMessage = entry.message.replace(guid, PLACEHOLDER + guid.takeLast(4)) + if (!message.contains(guid)) return null - return entry.toNewLogLineIfDifferent(newMessage) + return CensoredString(message).censor(guid, PLACEHOLDER + guid.takeLast(4)) } companion object { 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 38c06dca4..fff347294 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 @@ -1,9 +1,11 @@ package de.rki.coronawarnapp.bugreporting.censors.submission import de.rki.coronawarnapp.bugreporting.censors.BugCensor -import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNewLogLineIfDifferent +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.CensoredString +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.censors.BugCensor.Companion.withValidName -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebuggerScope import de.rki.coronawarnapp.coronatest.CoronaTestRepository import de.rki.coronawarnapp.coronatest.type.rapidantigen.RACoronaTest @@ -31,27 +33,27 @@ class RACoronaTestCensor @Inject constructor( ).filterNotNull() } - override suspend fun checkLog(entry: LogLine): LogLine? { + override suspend fun checkLog(message: String): CensoredString? { val raCoronaTestFlow = coronaTestFlow.map { tests -> tests.filterIsInstance<RACoronaTest>() }.first() val raCoronaTest = raCoronaTestFlow.firstOrNull() ?: return null - var newMessage = entry.message + var newMessage = CensoredString(message) with(raCoronaTest) { withValidName(firstName) { firstName -> - newMessage = newMessage.replace(firstName, "RATest/FirstName") + newMessage += newMessage.censor(firstName, "RATest/FirstName") } withValidName(lastName) { lastName -> - newMessage = newMessage.replace(lastName, "RATest/LastName") + newMessage += newMessage.censor(lastName, "RATest/LastName") } val dateOfBirthString = dateOfBirth?.toString(dayOfBirthFormatter) ?: return@with - newMessage = newMessage.replace(dateOfBirthString, "RATest/DateOfBirth") + newMessage += newMessage.censor(dateOfBirthString, "RATest/DateOfBirth") } - return entry.toNewLogLineIfDifferent(newMessage) + return newMessage.toNullIfUnmodified() } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/RatProfileCensor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/RatProfileCensor.kt index fa1e919bb..b33838de5 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/RatProfileCensor.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/RatProfileCensor.kt @@ -1,16 +1,20 @@ package de.rki.coronawarnapp.bugreporting.censors.submission import de.rki.coronawarnapp.bugreporting.censors.BugCensor -import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNewLogLineIfDifferent +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.CensoredString +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.censors.BugCensor.Companion.withValidAddress import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidCity import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidName import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidPhoneNumber import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidZipCode -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import de.rki.coronawarnapp.coronatest.antigen.profile.RATProfile import de.rki.coronawarnapp.coronatest.antigen.profile.RATProfileSettings import kotlinx.coroutines.flow.first +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import org.joda.time.format.DateTimeFormat import javax.inject.Inject @@ -18,10 +22,11 @@ class RatProfileCensor @Inject constructor( private val ratProfileSettings: RATProfileSettings ) : BugCensor { + private val mutex = Mutex() private val dayOfBirthFormatter = DateTimeFormat.forPattern("yyyy-MM-dd") private val ratProfileHistory = mutableSetOf<RATProfile>() - override suspend fun checkLog(entry: LogLine): LogLine? { + override suspend fun checkLog(message: String): CensoredString? = mutex.withLock { val ratProfile = ratProfileSettings.profile.flow.first() // store the profile in a property so we still have a reference after it was deleted by the user @@ -29,46 +34,46 @@ class RatProfileCensor @Inject constructor( ratProfileHistory.add(ratProfile) } - var newMessage = entry.message + var newMessage = CensoredString(message) ratProfileHistory.forEach { profile -> with(profile) { withValidName(firstName) { firstName -> - newMessage = newMessage.replace(firstName, "RAT-Profile/FirstName") + newMessage += newMessage.censor(firstName, "RAT-Profile/FirstName") } withValidName(lastName) { lastName -> - newMessage = newMessage.replace(lastName, "RAT-Profile/LastName") + newMessage += newMessage.censor(lastName, "RAT-Profile/LastName") } val dateOfBirthString = birthDate?.toString(dayOfBirthFormatter) if (dateOfBirthString != null) { - newMessage = newMessage.replace(dateOfBirthString, "RAT-Profile/DateOfBirth") + newMessage += newMessage.censor(dateOfBirthString, "RAT-Profile/DateOfBirth") } withValidAddress(street) { street -> - newMessage = newMessage.replace(street, "RAT-Profile/Street") + newMessage += newMessage.censor(street, "RAT-Profile/Street") } withValidCity(city) { city -> - newMessage = newMessage.replace(city, "RAT-Profile/City") + newMessage += newMessage.censor(city, "RAT-Profile/City") } withValidZipCode(zipCode) { zipCode -> - newMessage = newMessage.replace(zipCode, "RAT-Profile/Zip-Code") + newMessage += newMessage.censor(zipCode, "RAT-Profile/Zip-Code") } withValidPhoneNumber(phone) { phone -> - newMessage = newMessage.replace(phone, "RAT-Profile/Phone") + newMessage += newMessage.censor(phone, "RAT-Profile/Phone") } withValidPhoneNumber(email) { phone -> - newMessage = newMessage.replace(phone, "RAT-Profile/eMail") + newMessage += newMessage.censor(phone, "RAT-Profile/eMail") } } } - return entry.toNewLogLineIfDifferent(newMessage) + return newMessage.toNullIfUnmodified() } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/RatQrCodeCensor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/RatQrCodeCensor.kt index 29a9c1fa5..f7537dc8d 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/RatQrCodeCensor.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/submission/RatQrCodeCensor.kt @@ -2,9 +2,11 @@ package de.rki.coronawarnapp.bugreporting.censors.submission import dagger.Reusable import de.rki.coronawarnapp.bugreporting.censors.BugCensor -import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNewLogLineIfDifferent +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.CensoredString +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.censors.BugCensor.Companion.withValidName -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import de.rki.coronawarnapp.coronatest.qrcode.RapidAntigenHash import org.joda.time.LocalDate import org.joda.time.format.DateTimeFormat @@ -15,31 +17,31 @@ class RatQrCodeCensor @Inject constructor() : BugCensor { private val dayOfBirthFormatter = DateTimeFormat.forPattern("yyyy-MM-dd") - override suspend fun checkLog(entry: LogLine): LogLine? { + override suspend fun checkLog(message: String): CensoredString? { val dataToCensor = dataToCensor ?: return null - var newMessage = entry.message + var newMessage = CensoredString(message) with(dataToCensor) { - newMessage = newMessage.replace(rawString, "RatQrCode/ScannedRawString") + newMessage += newMessage.censor(rawString, "RatQrCode/ScannedRawString") - newMessage = newMessage.replace(hash, PLACEHOLDER + hash.takeLast(4)) + newMessage += newMessage.censor(hash, PLACEHOLDER + hash.takeLast(4)) withValidName(firstName) { firstName -> - newMessage = newMessage.replace(firstName, "RATest/FirstName") + newMessage += newMessage.censor(firstName, "RATest/FirstName") } withValidName(lastName) { lastName -> - newMessage = newMessage.replace(lastName, "RATest/LastName") + newMessage += newMessage.censor(lastName, "RATest/LastName") } val dateOfBirthString = dateOfBirth?.toString(dayOfBirthFormatter) ?: return@with - newMessage = newMessage.replace(dateOfBirthString, "RATest/DateOfBirth") + newMessage += newMessage.censor(dateOfBirthString, "RATest/DateOfBirth") } - return entry.toNewLogLineIfDifferent(newMessage) + return newMessage.toNullIfUnmodified() } companion object { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/vaccination/CertificateQrCodeCensor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/vaccination/CertificateQrCodeCensor.kt index b3de1ea4f..3b1dbda24 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/vaccination/CertificateQrCodeCensor.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/censors/vaccination/CertificateQrCodeCensor.kt @@ -2,8 +2,10 @@ package de.rki.coronawarnapp.bugreporting.censors.vaccination import dagger.Reusable import de.rki.coronawarnapp.bugreporting.censors.BugCensor -import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNewLogLineIfDifferent -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.CensoredString +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.vaccination.core.certificate.VaccinationDGCV1 import de.rki.coronawarnapp.vaccination.core.qrcode.VaccinationCertificateData import java.util.LinkedList @@ -12,86 +14,83 @@ import javax.inject.Inject @Reusable class CertificateQrCodeCensor @Inject constructor() : BugCensor { - override suspend fun checkLog(entry: LogLine): LogLine? { - var newMessage = entry.message + override suspend fun checkLog(message: String): CensoredString? { + var newMessage = CensoredString(message) synchronized(qrCodeStringsToCensor) { qrCodeStringsToCensor.toList() }.forEach { - newMessage = newMessage.replace( - it, - PLACEHOLDER + it.takeLast(4) - ) + newMessage += newMessage.censor(it, PLACEHOLDER + it.takeLast(4)) } synchronized(certsToCensor) { certsToCensor.toList() }.forEach { it.certificate.apply { - newMessage = newMessage.replace( + newMessage += newMessage.censor( dob, "vaccinationCertificate/dob" ) - newMessage = newMessage.replace( + newMessage += newMessage.censor( dateOfBirth.toString(), "vaccinationCertificate/dateOfBirth" ) - newMessage = censorNameData(nameData, newMessage) + newMessage += censorNameData(nameData, newMessage) vaccinationDatas.forEach { data -> - newMessage = censorVaccinationData(data, newMessage) + newMessage += censorVaccinationData(data, newMessage) } } } - return entry.toNewLogLineIfDifferent(newMessage) + return newMessage.toNullIfUnmodified() } private fun censorVaccinationData( vaccinationData: VaccinationDGCV1.VaccinationData, - message: String - ): String { + message: CensoredString + ): CensoredString { var newMessage = message - newMessage = newMessage.replace( + newMessage += newMessage.censor( vaccinationData.dt, "vaccinationData/dt" ) - newMessage = newMessage.replace( + newMessage += newMessage.censor( vaccinationData.marketAuthorizationHolderId, "vaccinationData/marketAuthorizationHolderId" ) - newMessage = newMessage.replace( + newMessage += newMessage.censor( vaccinationData.medicalProductId, "vaccinationData/medicalProductId" ) - newMessage = newMessage.replace( + newMessage += newMessage.censor( vaccinationData.targetId, "vaccinationData/targetId" ) - newMessage = newMessage.replace( + newMessage += newMessage.censor( vaccinationData.certificateIssuer, "vaccinationData/certificateIssuer" ) - newMessage = newMessage.replace( + newMessage += newMessage.censor( vaccinationData.uniqueCertificateIdentifier, "vaccinationData/uniqueCertificateIdentifier" ) - newMessage = newMessage.replace( + newMessage += newMessage.censor( vaccinationData.countryOfVaccination, "vaccinationData/countryOfVaccination" ) - newMessage = newMessage.replace( + newMessage += newMessage.censor( vaccinationData.vaccineId, "vaccinationData/vaccineId" ) - newMessage = newMessage.replace( + newMessage += newMessage.censor( vaccinationData.vaccinatedAt.toString(), "vaccinationData/vaccinatedAt" ) @@ -99,30 +98,30 @@ class CertificateQrCodeCensor @Inject constructor() : BugCensor { return newMessage } - private fun censorNameData(nameData: VaccinationDGCV1.NameData, message: String): String { + private fun censorNameData(nameData: VaccinationDGCV1.NameData, message: CensoredString): CensoredString { var newMessage = message nameData.familyName?.let { fName -> - newMessage = newMessage.replace( + newMessage += newMessage.censor( fName, "nameData/familyName" ) } - newMessage = newMessage.replace( + newMessage += newMessage.censor( nameData.familyNameStandardized, "nameData/familyNameStandardized" ) nameData.givenName?.let { gName -> - newMessage = newMessage.replace( + newMessage += newMessage.censor( gName, "nameData/givenName" ) } nameData.givenNameStandardized?.let { gName -> - newMessage = newMessage.replace( + newMessage += newMessage.censor( gName, "nameData/givenNameStandardized" ) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/DebugLogger.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/DebugLogger.kt index 698f5b68c..5fe3b904e 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/DebugLogger.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/DebugLogger.kt @@ -3,6 +3,7 @@ package de.rki.coronawarnapp.bugreporting.debuglog import android.annotation.SuppressLint import android.content.Context import android.util.Log +import de.rki.coronawarnapp.bugreporting.censors.BugCensor import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebugLogStorageCheck import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebugLogTree import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebugLoggerScope @@ -12,6 +13,8 @@ import de.rki.coronawarnapp.util.di.ApplicationComponent import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job +import kotlinx.coroutines.async +import kotlinx.coroutines.awaitAll import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow @@ -160,10 +163,28 @@ class DebugLogger( launch { // Censor data sources need a moment to know what to censor delay(1000) - val censoredLine = bugCensors.get().fold(rawLine) { prev, censor -> - censor.checkLog(prev) ?: prev + + val formattedMessage = rawLine.format() + val censored: Collection<BugCensor.CensoredString> = bugCensors.get() + .map { + async { + it.checkLog(formattedMessage) + } + } + .awaitAll() + .filterNotNull() + .filter { it.range != null } + + val toWrite: String = when (censored.size) { + 0 -> formattedMessage + 1 -> censored.single().string + else -> { + val minMin = censored.minOf { it.range!!.first } + val maxMax = censored.maxOf { it.range!!.last } + formattedMessage.replaceRange(minMin, maxMax, CENSOR_COLLISION_PLACERHOLDER) + } } - logWriter.write(censoredLine) + logWriter.write(toWrite) } } } catch (e: CancellationException) { @@ -174,6 +195,7 @@ class DebugLogger( } companion object { + private const val CENSOR_COLLISION_PLACERHOLDER = "<censoring-collision>" internal const val TAG = "DebugLogger" } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/LogLine.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/LogLine.kt index defe6c2c2..67664ffba 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/LogLine.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/LogLine.kt @@ -2,6 +2,8 @@ package de.rki.coronawarnapp.bugreporting.debuglog import android.util.Log import org.joda.time.Instant +import java.io.PrintWriter +import java.io.StringWriter data class LogLine( val timestamp: Long, @@ -13,15 +15,33 @@ data class LogLine( fun format(): String { val time = Instant.ofEpochMilli(timestamp) - return "$time ${priorityLabel(priority)}/$tag: $message\n" + + val baseLine = "$time ${priorityLabel(priority)}/$tag: $message" + + return if (throwable != null) { + baseLine + "\n" + getStackTraceString(throwable) + } else { + baseLine + } } - private fun priorityLabel(priority: Int): String = when (priority) { - Log.ERROR -> "E" - Log.WARN -> "W" - Log.INFO -> "I" - Log.DEBUG -> "D" - Log.VERBOSE -> "V" - else -> priority.toString() + companion object { + // Based on Timber.Tree.getStackTraceString() + internal fun getStackTraceString(t: Throwable): String { + val sw = StringWriter(256) + val pw = PrintWriter(sw, false) + t.printStackTrace(pw) + pw.flush() + return sw.toString() + } + + internal fun priorityLabel(priority: Int): String = when (priority) { + Log.ERROR -> "E" + Log.WARN -> "W" + Log.INFO -> "I" + Log.DEBUG -> "D" + Log.VERBOSE -> "V" + else -> priority.toString() + } } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/DebugLogStorageCheck.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/DebugLogStorageCheck.kt index 113ffeb5b..1b9298774 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/DebugLogStorageCheck.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/DebugLogStorageCheck.kt @@ -30,7 +30,7 @@ class DebugLogStorageCheck @Inject constructor( return eval.usableSpace } - fun isLowStorage(forceCheck: Boolean = false): Boolean { + suspend fun isLowStorage(forceCheck: Boolean = false): Boolean { val now = timeProvider() if (!forceCheck && now - lastCheckAt < 5_000) return isLowStorage.value @@ -64,23 +64,23 @@ class DebugLogStorageCheck @Inject constructor( companion object { private const val TAG = DebugLogger.TAG - private val createStorageCheckErrorLine: (Throwable) -> LogLine = { + private val createStorageCheckErrorLine: (Throwable) -> String = { LogLine( timestamp = System.currentTimeMillis(), priority = Log.ERROR, tag = TAG, message = "Low storage check failed.", throwable = it - ) + ).format() } - private val createLowStorageLogLine: () -> LogLine = { + private val createLowStorageLogLine: () -> String = { LogLine( timestamp = System.currentTimeMillis(), priority = Log.WARN, tag = TAG, message = "Low storage, debug logger halted.", throwable = null - ) + ).format() } } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/DebugLoggerScope.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/DebugLoggerScope.kt index 9e60dc67b..77c72ec18 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/DebugLoggerScope.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/DebugLoggerScope.kt @@ -9,7 +9,8 @@ import javax.inject.Qualifier import kotlin.coroutines.CoroutineContext object DebugLoggerScope : CoroutineScope { - val dispatcher = Executors.newSingleThreadExecutor( + val dispatcher = Executors.newFixedThreadPool( + 4, NamedThreadFactory("DebugLogger") ).asCoroutineDispatcher() override val coroutineContext: CoroutineContext = SupervisorJob() + dispatcher diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/LogWriter.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/LogWriter.kt index ebb188567..a5448ea4d 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/LogWriter.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/LogWriter.kt @@ -1,20 +1,22 @@ package de.rki.coronawarnapp.bugreporting.debuglog.internal -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import timber.log.Timber import java.io.File import javax.inject.Inject class LogWriter @Inject constructor(val logFile: File) { private var ioLimiter = 0 + private val mutex = Mutex() val logSize = MutableStateFlow(logFile.length()) private fun updateLogSize() { logSize.value = logFile.length() } - fun setup() { + suspend fun setup() = mutex.withLock { if (!logFile.exists()) { logFile.parentFile?.mkdirs() if (logFile.createNewFile()) { @@ -24,16 +26,15 @@ class LogWriter @Inject constructor(val logFile: File) { updateLogSize() } - fun teardown() { + suspend fun teardown() = mutex.withLock { if (logFile.exists() && logFile.delete()) { Timber.d("Log file was deleted.") } updateLogSize() } - fun write(line: LogLine) { - val formattedLine = line.format() - logFile.appendText(formattedLine, Charsets.UTF_8) + suspend fun write(formattedLine: String): Unit = mutex.withLock { + logFile.appendText(formattedLine + "\n", Charsets.UTF_8) if (ioLimiter % 10 == 0) { updateLogSize() diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/BugCensorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/BugCensorTest.kt index 988042877..bb6d1f2f7 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/BugCensorTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/BugCensorTest.kt @@ -1,7 +1,6 @@ package de.rki.coronawarnapp.bugreporting.censors -import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNewLogLineIfDifferent -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNullIfUnmodified import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldNotBe import org.junit.jupiter.api.Test @@ -100,15 +99,8 @@ class BugCensorTest : BaseTest() { } @Test - fun `loglines are only copied if the message is different`() { - val logLine = LogLine( - timestamp = 1, - priority = 3, - message = "Message", - tag = "Tag", - throwable = null - ) - logLine.toNewLogLineIfDifferent("Message") shouldBe null - logLine.toNewLogLineIfDifferent("Message ") shouldNotBe logLine + fun `cesnsor string is nulled if not modified`() { + BugCensor.CensoredString("abc", 1..2).toNullIfUnmodified() shouldNotBe null + BugCensor.CensoredString("abc", null).toNullIfUnmodified() shouldBe null } } 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 818cdbb8e..9965c6215 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 @@ -1,7 +1,6 @@ package de.rki.coronawarnapp.bugreporting.censors import de.rki.coronawarnapp.bugreporting.censors.presencetracing.CheckInsCensor -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import de.rki.coronawarnapp.presencetracing.checkins.CheckIn import de.rki.coronawarnapp.presencetracing.checkins.CheckInRepository import io.kotest.matchers.shouldBe @@ -59,36 +58,24 @@ internal class CheckInsCensorTest : BaseTest() { val censor = createInstance(this) - val logLineToCensor = LogLine( - timestamp = 1, - priority = 3, - message = - """ - 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(), - tag = "I am tag", - throwable = null - ) + 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) shouldBe logLineToCensor.copy( - message = - """ - Let's go to CheckIn#1/Description in CheckIn#1/Address. - Who needs the CheckIn#2/Description in CheckIn#2/Address? I doooo! - """.trimIndent() - ) + censor.checkLog(logLineToCensor)!!.string shouldBe """ + 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()) - censor.checkLog(logLineToCensor) shouldBe logLineToCensor.copy( - message = - """ - Let's go to CheckIn#1/Description in CheckIn#1/Address. - Who needs the CheckIn#2/Description in CheckIn#2/Address? I doooo! - """.trimIndent() - ) + censor.checkLog(logLineToCensor)!!.string shouldBe """ + Let's go to CheckIn#1/Description in CheckIn#1/Address. + Who needs the CheckIn#2/Description in CheckIn#2/Address? I doooo! + """.trimIndent() } @Test @@ -96,13 +83,7 @@ internal class CheckInsCensorTest : BaseTest() { every { checkInsRepo.allCheckIns } returns flowOf(emptyList()) val censor = createInstance(this) - val logLine = LogLine( - timestamp = 1, - priority = 3, - message = "Some log message that shouldn't be censored.", - tag = "I'm a tag", - throwable = null - ) + val logLine = "Some log message that shouldn't be censored." censor.checkLog(logLine) shouldBe null } @@ -126,13 +107,7 @@ internal class CheckInsCensorTest : BaseTest() { ) val censor = createInstance(this) - val logLine = LogLine( - timestamp = 1, - priority = 3, - message = "Some log message that shouldn't be censored.", - tag = "I'm a tag", - throwable = null - ) + val logLine = "Some log message that shouldn't be censored." censor.checkLog(logLine) shouldBe null } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/CoronaTestCensorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/CoronaTestCensorTest.kt index f80997a6a..e61a463d4 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/CoronaTestCensorTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/CoronaTestCensorTest.kt @@ -1,7 +1,6 @@ package de.rki.coronawarnapp.bugreporting.censors import de.rki.coronawarnapp.bugreporting.censors.submission.CoronaTestCensor -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import de.rki.coronawarnapp.coronatest.CoronaTestRepository import de.rki.coronawarnapp.coronatest.type.CoronaTest import de.rki.coronawarnapp.coronatest.type.pcr.PCRCoronaTest @@ -13,6 +12,7 @@ import io.mockk.impl.annotations.MockK import io.mockk.mockk import io.mockk.verify import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.test.TestCoroutineScope import kotlinx.coroutines.test.runBlockingTest import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test @@ -46,22 +46,15 @@ class CoronaTestCensorTest : BaseTest() { } private fun createInstance() = CoronaTestCensor( + debugScope = TestCoroutineScope(), coronaTestRepository = coronaTestRepository ) @Test fun `censoring replaces the logline message`() = runBlockingTest { val instance = createInstance() - val filterMe = LogLine( - timestamp = 1, - priority = 3, - message = "I'm a shy registration token: $testToken and we are extrovert $pcrIdentifier and $ratIdentifier", - tag = "I'm a tag", - throwable = null - ) - instance.checkLog(filterMe) shouldBe filterMe.copy( - message = "I'm a shy registration token: ########-####-####-####-########3a2f and we are extrovert qrcode-pcr-CoronaTest/Identifier and qrcode-rat-CoronaTest/Identifier" - ) + val filterMe = "I'm a shy registration token: $testToken and we are extrovert $pcrIdentifier and $ratIdentifier" + instance.checkLog(filterMe)!!.string shouldBe "I'm a shy registration token: ########-####-####-####-########3a2f and we are extrovert qrcode-pcr-CoronaTest/Identifier and qrcode-rat-CoronaTest/Identifier" verify { coronaTestRepository.coronaTests } } @@ -71,26 +64,15 @@ class CoronaTestCensorTest : BaseTest() { coronaTests.value = emptySet() val instance = createInstance() - val filterMeNot = LogLine( - timestamp = 1, - priority = 3, - message = "I'm a shy registration token: $testToken and we are extrovert $pcrIdentifier and $ratIdentifier", - tag = "I'm a tag", - throwable = null - ) + val filterMeNot = + "I'm a shy registration token: $testToken and we are extrovert $pcrIdentifier and $ratIdentifier" instance.checkLog(filterMeNot) shouldBe null } @Test fun `censoring returns null if there is no match`() = runBlockingTest { val instance = createInstance() - val filterMeNot = LogLine( - timestamp = 1, - priority = 3, - message = "I'm not a registration token ;)", - tag = "I'm a tag", - throwable = null - ) + val filterMeNot = "I'm not a registration token ;)" instance.checkLog(filterMeNot) shouldBe null } @@ -99,23 +81,13 @@ class CoronaTestCensorTest : BaseTest() { val censor = createInstance() - val filterMe = LogLine( - timestamp = 1, - priority = 3, - message = "I'm a shy registration token: $testToken and we are extrovert $pcrIdentifier and $ratIdentifier", - tag = "I'm a tag", - throwable = null - ) + val filterMe = "I'm a shy registration token: $testToken and we are extrovert $pcrIdentifier and $ratIdentifier" - censor.checkLog(filterMe) shouldBe filterMe.copy( - message = "I'm a shy registration token: ########-####-####-####-########3a2f and we are extrovert qrcode-pcr-CoronaTest/Identifier and qrcode-rat-CoronaTest/Identifier" - ) + censor.checkLog(filterMe)!!.string shouldBe "I'm a shy registration token: ########-####-####-####-########3a2f and we are extrovert qrcode-pcr-CoronaTest/Identifier and qrcode-rat-CoronaTest/Identifier" // delete all tests coronaTests.value = emptySet() - censor.checkLog(filterMe) shouldBe filterMe.copy( - message = "I'm a shy registration token: ########-####-####-####-########3a2f and we are extrovert qrcode-pcr-CoronaTest/Identifier and qrcode-rat-CoronaTest/Identifier" - ) + censor.checkLog(filterMe)!!.string shouldBe "I'm a shy registration token: ########-####-####-####-########3a2f and we are extrovert qrcode-pcr-CoronaTest/Identifier and qrcode-rat-CoronaTest/Identifier" } } 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 fead49fe9..5f7b72554 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 @@ -1,7 +1,6 @@ package de.rki.coronawarnapp.bugreporting.censors import de.rki.coronawarnapp.bugreporting.censors.contactdiary.DiaryEncounterCensor -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import de.rki.coronawarnapp.contactdiary.model.ContactDiaryPersonEncounter import de.rki.coronawarnapp.contactdiary.storage.repo.ContactDiaryRepository import io.kotest.matchers.shouldBe @@ -51,51 +50,35 @@ class DiaryEncounterCensorTest : BaseTest() { ) val instance = createInstance(this) - val censorMe = LogLine( - timestamp = 1, - priority = 3, - message = - """ - On A rainy day, - two persons Spilled coffee on each others laptops, - everyone disliked that. - """.trimIndent(), - tag = "I'm a tag", - throwable = null - ) - - instance.checkLog(censorMe) shouldBe censorMe.copy( - message = - """ - On Encounter#2/Circumstances, - two persons Encounter#3/Circumstances, - everyone disliked that. - """.trimIndent() - ) + val censorMe = + """ + On A rainy day, + two persons Spilled coffee on each others laptops, + everyone disliked that. + """.trimIndent() + + instance.checkLog(censorMe)!!.string shouldBe + """ + On Encounter#2/Circumstances, + two persons Encounter#3/Circumstances, + everyone disliked that. + """.trimIndent() // censoring should still work after encounters are deleted every { diaryRepo.personEncounters } returns flowOf(emptyList()) - instance.checkLog(censorMe) shouldBe censorMe.copy( - message = - """ - On Encounter#2/Circumstances, - two persons Encounter#3/Circumstances, - everyone disliked that. - """.trimIndent() - ) + instance.checkLog(censorMe)!!.string shouldBe + """ + On Encounter#2/Circumstances, + two persons Encounter#3/Circumstances, + everyone disliked that. + """.trimIndent() } @Test fun `censoring returns null if all circumstances are blank`() = runBlockingTest { every { diaryRepo.personEncounters } returns flowOf(listOf(mockEncounter(1, _circumstances = ""))) val instance = createInstance(this) - val notCensored = LogLine( - timestamp = 1, - priority = 3, - message = "That was strange.", - tag = "I'm a tag", - throwable = null - ) + val notCensored = "That was strange." instance.checkLog(notCensored) shouldBe null } @@ -105,13 +88,7 @@ class DiaryEncounterCensorTest : BaseTest() { val instance = createInstance(this) - val notCensored = LogLine( - timestamp = 1, - priority = 3, - message = "Nothing ever happens.", - tag = "I'm a tag", - throwable = null - ) + val notCensored = "Nothing ever happens." instance.checkLog(notCensored) shouldBe null } @@ -125,13 +102,7 @@ class DiaryEncounterCensorTest : BaseTest() { ) val instance = createInstance(this) - val notCensored = LogLine( - timestamp = 1, - priority = 3, - message = "I like turtles", - tag = "I'm a tag", - throwable = null - ) + val notCensored = "I like turtles" instance.checkLog(notCensored) shouldBe null } @@ -145,13 +116,7 @@ class DiaryEncounterCensorTest : BaseTest() { ) ) - val logLine = LogLine( - timestamp = 1, - priority = 3, - message = "Lorem ipsum", - tag = "I'm a tag", - throwable = null - ) + val logLine = "Lorem ipsum" var isFinished = false 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 191afcd5d..c708da370 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 @@ -1,7 +1,6 @@ package de.rki.coronawarnapp.bugreporting.censors import de.rki.coronawarnapp.bugreporting.censors.contactdiary.DiaryLocationCensor -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import de.rki.coronawarnapp.contactdiary.model.ContactDiaryLocation import de.rki.coronawarnapp.contactdiary.storage.repo.ContactDiaryRepository import io.kotest.matchers.shouldBe @@ -54,50 +53,34 @@ class DiaryLocationCensorTest : BaseTest() { ) ) val instance = createInstance(this) - val censorMe = LogLine( - timestamp = 1, - priority = 3, - message = - """ - 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(), - tag = "I'm a tag", - throwable = null - ) - instance.checkLog(censorMe) shouldBe censorMe.copy( - message = - """ - Bürgermeister of Location#1/Name (Location#1/PhoneNumber) and Karl of Location#3/Name [Location#3/PhoneNumber] called each other. - 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() - ) + 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. + 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()) - instance.checkLog(censorMe) shouldBe censorMe.copy( - message = - """ - Bürgermeister of Location#1/Name (Location#1/PhoneNumber) and Karl of Location#3/Name [Location#3/PhoneNumber] called each other. - 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() - ) + 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. + 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() } @Test fun `censoring returns null if there are no locations no match`() = runBlockingTest { every { diaryRepo.locations } returns flowOf(emptyList()) val instance = createInstance(this) - val notCensored = LogLine( - timestamp = 1, - priority = 3, - message = "Can't visit many cities during lockdown...", - tag = "I'm a tag", - throwable = null - ) + val notCensored = "Can't visit many cities during lockdown..." instance.checkLog(notCensored) shouldBe null } @@ -111,13 +94,7 @@ class DiaryLocationCensorTest : BaseTest() { ) ) val instance = createInstance(this) - val logLine = LogLine( - timestamp = 1, - priority = 3, - message = "Lorem ipsum", - tag = "I'm a tag", - throwable = null - ) + val logLine = "Lorem ipsum" instance.checkLog(logLine) shouldBe null } @@ -132,13 +109,7 @@ class DiaryLocationCensorTest : BaseTest() { ) ) - val logLine = LogLine( - timestamp = 1, - priority = 3, - message = "Lorem ipsum", - tag = "I'm a tag", - throwable = null - ) + val logLine = "Lorem ipsum" var isFinished = false 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 1025df09c..240c80f3c 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 @@ -1,7 +1,6 @@ package de.rki.coronawarnapp.bugreporting.censors import de.rki.coronawarnapp.bugreporting.censors.contactdiary.DiaryPersonCensor -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import de.rki.coronawarnapp.contactdiary.model.ContactDiaryPerson import de.rki.coronawarnapp.contactdiary.storage.repo.ContactDiaryRepository import io.kotest.matchers.shouldBe @@ -55,50 +54,34 @@ class DiaryPersonCensorTest : BaseTest() { ) ) val instance = createInstance(this) - val censorMe = LogLine( - timestamp = 1, - priority = 3, - message = - """ - 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(), - tag = "I'm a tag", - throwable = null - ) - instance.checkLog(censorMe) shouldBe censorMe.copy( - message = - """ - Person#2/Name requested more coffee from Person#1/PhoneNumber, - but Person#3/Name thought he had enough has had enough for today. - A quick mail to Person#1/EMail confirmed this. - """.trimIndent() - ) + 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() + instance.checkLog(censorMe)!!.string shouldBe + """ + Person#2/Name requested more coffee from Person#1/PhoneNumber, + but Person#3/Name thought he had enough has had enough for today. + A quick mail to Person#1/EMail confirmed this. + """.trimIndent() // censoring should still work after people are deleted every { diaryRepo.people } returns flowOf(emptyList()) - instance.checkLog(censorMe) shouldBe censorMe.copy( - message = - """ - Person#2/Name requested more coffee from Person#1/PhoneNumber, - but Person#3/Name thought he had enough has had enough for today. - A quick mail to Person#1/EMail confirmed this. - """.trimIndent() - ) + instance.checkLog(censorMe)!!.string shouldBe + """ + Person#2/Name requested more coffee from Person#1/PhoneNumber, + 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 returns null if there are no persons no match`() = runBlockingTest { every { diaryRepo.people } returns flowOf(emptyList()) val instance = createInstance(this) - val notCensored = LogLine( - timestamp = 1, - priority = 3, - message = "May 2021 be better than 2020.", - tag = "I'm a tag", - throwable = null - ) + val notCensored = "May 2021 be better than 2020." instance.checkLog(notCensored) shouldBe null } @@ -112,13 +95,7 @@ class DiaryPersonCensorTest : BaseTest() { ) ) val instance = createInstance(this) - val logLine = LogLine( - timestamp = 1, - priority = 3, - message = "Lorem ipsum", - tag = "I'm a tag", - throwable = null - ) + val logLine = "Lorem ipsum" instance.checkLog(logLine) shouldBe null } @@ -133,13 +110,7 @@ class DiaryPersonCensorTest : BaseTest() { ) ) - val logLine = LogLine( - timestamp = 1, - priority = 3, - message = "Lorem ipsum", - tag = "I'm a tag", - throwable = null - ) + val logLine = "Lorem ipsum" var isFinished = false 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 5c8a0ed51..cdd31e2a5 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 @@ -1,7 +1,6 @@ package de.rki.coronawarnapp.bugreporting.censors import de.rki.coronawarnapp.bugreporting.censors.contactdiary.DiaryVisitCensor -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import de.rki.coronawarnapp.contactdiary.model.ContactDiaryLocationVisit import de.rki.coronawarnapp.contactdiary.storage.repo.ContactDiaryRepository import io.kotest.matchers.shouldBe @@ -50,50 +49,34 @@ class DiaryVisitCensorTest : BaseTest() { ) ) val instance = createInstance(this) - val censorMe = LogLine( - timestamp = 1, - priority = 3, - message = - """ - 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(), - tag = "I'm a tag", - throwable = null - ) - instance.checkLog(censorMe) shouldBe censorMe.copy( - message = - """ - After having a Visit#1/Circumstances, - I got my Visit#2/Circumstances, - only to find out the supermarket was Visit#3/Circumstances. - """.trimIndent() - ) + 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, + 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()) - instance.checkLog(censorMe) shouldBe censorMe.copy( - message = - """ - After having a Visit#1/Circumstances, - I got my Visit#2/Circumstances, - only to find out the supermarket was Visit#3/Circumstances. - """.trimIndent() - ) + instance.checkLog(censorMe)!!.string shouldBe + """ + After having a Visit#1/Circumstances, + I got my Visit#2/Circumstances, + only to find out the supermarket was Visit#3/Circumstances. + """.trimIndent() } @Test fun `censoring returns null if all circumstances are blank`() = runBlockingTest { every { diaryRepo.locationVisits } returns flowOf(listOf(mockVisit(1, _circumstances = ""))) val instance = createInstance(this) - val notCensored = LogLine( - timestamp = 1, - priority = 3, - message = "So many places to visit, but no place like home!", - tag = "I'm a tag", - throwable = null - ) + val notCensored = "So many places to visit, but no place like home!" instance.checkLog(notCensored) shouldBe null } @@ -101,13 +84,7 @@ class DiaryVisitCensorTest : BaseTest() { fun `censoring returns null if there are no visits no match`() = runBlockingTest { every { diaryRepo.locationVisits } returns flowOf(emptyList()) val instance = createInstance(this) - val notCensored = LogLine( - timestamp = 1, - priority = 3, - message = "So many places to visit, but no place like home!", - tag = "I'm a tag", - throwable = null - ) + val notCensored = "So many places to visit, but no place like home!" instance.checkLog(notCensored) shouldBe null } @@ -120,13 +97,7 @@ class DiaryVisitCensorTest : BaseTest() { ) ) val instance = createInstance(this) - val notCensored = LogLine( - timestamp = 1, - priority = 3, - message = "Wakey wakey, eggs and bakey.", - tag = "I'm a tag", - throwable = null - ) + val notCensored = "Wakey wakey, eggs and bakey." instance.checkLog(notCensored) shouldBe null } @@ -140,13 +111,7 @@ class DiaryVisitCensorTest : BaseTest() { ) ) - val logLine = LogLine( - timestamp = 1, - priority = 3, - message = "Lorem ipsum", - tag = "I'm a tag", - throwable = null - ) + val logLine = "Lorem ipsum" var isFinished = false diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/PcrQrCodeCensorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/PcrQrCodeCensorTest.kt index 58826f8ff..f7551bb70 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/PcrQrCodeCensorTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/PcrQrCodeCensorTest.kt @@ -1,7 +1,6 @@ package de.rki.coronawarnapp.bugreporting.censors import de.rki.coronawarnapp.bugreporting.censors.submission.PcrQrCodeCensor -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import io.kotest.matchers.shouldBe import io.mockk.MockKAnnotations import kotlinx.coroutines.test.runBlockingTest @@ -30,29 +29,15 @@ class PcrQrCodeCensorTest : BaseTest() { fun `censoring replaces the logline message`() = runBlockingTest { PcrQrCodeCensor.lastGUID = testGUID val instance = createInstance() - val censored = LogLine( - timestamp = 1, - priority = 3, - message = "I'm a shy qrcode: $testGUID", - tag = "I'm a tag", - throwable = null - ) - instance.checkLog(censored) shouldBe censored.copy( - message = "I'm a shy qrcode: ########-####-####-####-########3a2f" - ) + val censored = "I'm a shy qrcode: $testGUID" + instance.checkLog(censored)!!.string shouldBe "I'm a shy qrcode: ########-####-####-####-########3a2f" } @Test fun `censoring returns null if there is no match`() = runBlockingTest { PcrQrCodeCensor.lastGUID = testGUID.replace("f", "a") val instance = createInstance() - val notCensored = LogLine( - timestamp = 1, - priority = 3, - message = "I'm a shy qrcode: $testGUID", - tag = "I'm a tag", - throwable = null - ) + val notCensored = "I'm a shy qrcode: $testGUID" instance.checkLog(notCensored) shouldBe null } @@ -60,13 +45,7 @@ class PcrQrCodeCensorTest : BaseTest() { fun `censoring aborts if no qrcode was set`() = runBlockingTest { PcrQrCodeCensor.lastGUID = null val instance = createInstance() - val notCensored = LogLine( - timestamp = 1, - priority = 3, - message = "I'm a shy qrcode: $testGUID", - tag = "I'm a tag", - throwable = null - ) + val notCensored = "I'm a shy qrcode: $testGUID" instance.checkLog(notCensored) shouldBe null } } 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 74c66acfa..3a4e06d93 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 @@ -1,7 +1,6 @@ package de.rki.coronawarnapp.bugreporting.censors import de.rki.coronawarnapp.bugreporting.censors.submission.RACoronaTestCensor -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import de.rki.coronawarnapp.coronatest.CoronaTestRepository import de.rki.coronawarnapp.coronatest.type.rapidantigen.RACoronaTest import io.kotest.matchers.shouldBe @@ -45,33 +44,23 @@ internal class RACoronaTestCensorTest : BaseTest() { val censor = createInstance(this) - val logLineToCensor = LogLine( - timestamp = 1, - priority = 3, - message = - """ - Hello! My name is John. My friends call me Mister Doe and I was born on 2020-01-01. - """.trimIndent(), - tag = "I am tag", - throwable = null - ) + 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) shouldBe logLineToCensor.copy( - message = - """ - Hello! My name is RATest/FirstName. My friends call me Mister RATest/LastName and I was born on RATest/DateOfBirth. - """.trimIndent() - ) + censor.checkLog(logLineToCensor)!!.string shouldBe + """ + 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()) - censor.checkLog(logLineToCensor) shouldBe logLineToCensor.copy( - message = - """ - Hello! My name is RATest/FirstName. My friends call me Mister RATest/LastName and I was born on RATest/DateOfBirth. - """.trimIndent() - ) + censor.checkLog(logLineToCensor)!!.string shouldBe + """ + Hello! My name is RATest/FirstName. My friends call me Mister RATest/LastName and I was born on RATest/DateOfBirth. + """.trimIndent() } @Test @@ -80,13 +69,7 @@ internal class RACoronaTestCensorTest : BaseTest() { val censor = createInstance(this) - val logLine = LogLine( - timestamp = 1, - priority = 3, - message = "Lorem ipsum", - tag = "I'm a tag", - throwable = null - ) + val logLine = "Lorem ipsum" censor.checkLog(logLine) shouldBe null } @@ -105,13 +88,7 @@ internal class RACoronaTestCensorTest : BaseTest() { val censor = createInstance(this) - val logLine = LogLine( - timestamp = 1, - priority = 3, - message = "Lorem ipsum", - tag = "I'm a tag", - throwable = null - ) + val logLine = "Lorem ipsum" censor.checkLog(logLine) shouldBe null } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/RatQrCodeCensorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/RatQrCodeCensorTest.kt index 6689f4e48..afef21806 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/RatQrCodeCensorTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/RatQrCodeCensorTest.kt @@ -1,7 +1,6 @@ package de.rki.coronawarnapp.bugreporting.censors import de.rki.coronawarnapp.bugreporting.censors.submission.RatQrCodeCensor -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import io.kotest.matchers.shouldBe import io.mockk.MockKAnnotations import kotlinx.coroutines.test.runBlockingTest @@ -39,30 +38,17 @@ internal class RatQrCodeCensorTest { val censor = createInstance() - val logLineToCensor = LogLine( - timestamp = 1, - priority = 3, - message = "Here comes the hash: $testHash of the rat test of Milhouse Van Houten. He was born on 1980-07-01", - tag = "I am tag", - throwable = null - ) + val logLineToCensor = + "Here comes the hash: $testHash of the rat test of Milhouse Van Houten. He was born on 1980-07-01" - censor.checkLog(logLineToCensor) shouldBe logLineToCensor.copy( - message = "Here comes the hash: SHA256HASH-ENDING-WITH-15ad of the rat test of RATest/FirstName RATest/LastName. He was born on RATest/DateOfBirth" - ) + censor.checkLog(logLineToCensor)!!.string shouldBe "Here comes the hash: SHA256HASH-ENDING-WITH-15ad of the rat test of RATest/FirstName RATest/LastName. He was born on RATest/DateOfBirth" } @Test fun `checkLog() should return null if no data to censor was set`() = runBlockingTest { val censor = createInstance() - val logLineNotToCensor = LogLine( - timestamp = 1, - priority = 3, - message = "Here comes the hash: $testHash", - tag = "I am tag", - throwable = null - ) + val logLineNotToCensor = "Here comes the hash: $testHash" censor.checkLog(logLineNotToCensor) shouldBe null } @@ -79,13 +65,7 @@ internal class RatQrCodeCensorTest { val censor = createInstance() - val logLineNotToCensor = LogLine( - timestamp = 1, - priority = 3, - message = "Here comes the hash: $testHash", - tag = "I am tag", - throwable = null - ) + val logLineNotToCensor = "Here comes the hash: $testHash" censor.checkLog(logLineNotToCensor) shouldBe null } 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 c7f6d6b7f..92bd63b96 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 @@ -1,7 +1,6 @@ package de.rki.coronawarnapp.bugreporting.censors import de.rki.coronawarnapp.bugreporting.censors.presencetracing.TraceLocationCensor -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import de.rki.coronawarnapp.presencetracing.checkins.qrcode.TraceLocation import de.rki.coronawarnapp.presencetracing.locations.TraceLocationUserInput import de.rki.coronawarnapp.presencetracing.storage.repo.TraceLocationRepository @@ -72,36 +71,26 @@ internal class TraceLocationCensorTest : BaseTest() { val censor = createInstance(this) - val logLineToCensor = LogLine( - timestamp = 1, - priority = 3, - message = - """ - 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(), - tag = "I am tag", - throwable = null - ) + 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) shouldBe logLineToCensor.copy( - message = - """ - 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() - ) + censor.checkLog(logLineToCensor)!!.string shouldBe + """ + 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()) - censor.checkLog(logLineToCensor) shouldBe logLineToCensor.copy( - message = - """ - 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() - ) + censor.checkLog(logLineToCensor)!!.string shouldBe + """ + 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() } @Test @@ -119,25 +108,17 @@ internal class TraceLocationCensorTest : BaseTest() { val censor = createInstance(this) - val logLineToCensor = LogLine( - timestamp = 1, - priority = 3, - message = - """ + val logLineToCensor = + """ The user just created a new traceLocation with Top Secret Private Event as the description and top secret address as the address. The type is LOCATION_TYPE_TEMPORARY_PRIVATE_EVENT. - """.trimIndent(), - tag = "I am tag", - throwable = null - ) + """.trimIndent() - censor.checkLog(logLineToCensor) shouldBe logLineToCensor.copy( - message = - """ + censor.checkLog(logLineToCensor)!!.string shouldBe + """ The user just created a new traceLocation with TraceLocationUserInput#Description as the description and TraceLocationUserInput#Address as the address. The type is TraceLocationUserInput#Type. - """.trimIndent() - ) + """.trimIndent() } @Test @@ -145,13 +126,7 @@ internal class TraceLocationCensorTest : BaseTest() { every { traceLocationRepo.allTraceLocations } returns flowOf(emptyList()) val censor = createInstance(this) - val logLine = LogLine( - timestamp = 1, - priority = 3, - message = "Lorem ipsum", - tag = "I'm a tag", - throwable = null - ) + val logLine = "Lorem ipsum" censor.checkLog(logLine) shouldBe null } @@ -176,13 +151,7 @@ internal class TraceLocationCensorTest : BaseTest() { ) val censor = createInstance(this) - val logLine = LogLine( - timestamp = 1, - priority = 3, - message = "Lorem ipsum", - tag = "I'm a tag", - throwable = null - ) + val logLine = "Lorem ipsum" censor.checkLog(logLine) shouldBe null } 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 9093882a6..2134750ac 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 @@ -1,6 +1,5 @@ package de.rki.coronawarnapp.bugreporting.censors.submission -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import de.rki.coronawarnapp.coronatest.antigen.profile.RATProfile import de.rki.coronawarnapp.coronatest.antigen.profile.RATProfileSettings import io.kotest.matchers.shouldBe @@ -33,13 +32,7 @@ internal class RatProfileCensorTest : BaseTest() { val censor = createInstance() - val logLine = LogLine( - timestamp = 1, - priority = 3, - message = "Lorem ipsum", - tag = "I'm a tag", - throwable = null - ) + val logLine = "Lorem ipsum" censor.checkLog(logLine) shouldBe null } @@ -50,13 +43,7 @@ internal class RatProfileCensorTest : BaseTest() { val censor = createInstance() - val logLine = LogLine( - timestamp = 1, - priority = 3, - message = "Lorem ipsum", - tag = "I'm a tag", - throwable = null - ) + val logLine = "I'm a tag" censor.checkLog(logLine) shouldBe null } @@ -67,27 +54,20 @@ internal class RatProfileCensorTest : BaseTest() { val censor = createInstance() - val logLine = LogLine( - timestamp = 1, - priority = 3, - message = "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", - tag = "I'm a tag", - throwable = null - ) + 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) shouldBe logLine.copy( - message = "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" - ) + 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) - censor.checkLog(logLine) shouldBe logLine.copy( - message = "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" - ) + 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" } private val formatter = DateTimeFormat.forPattern("yyyy-MM-dd") diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/vaccination/CertificateQrCodeCensorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/vaccination/CertificateQrCodeCensorTest.kt index e6c292712..a5509d80b 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/vaccination/CertificateQrCodeCensorTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/censors/vaccination/CertificateQrCodeCensorTest.kt @@ -1,6 +1,5 @@ package de.rki.coronawarnapp.bugreporting.censors.vaccination -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import de.rki.coronawarnapp.vaccination.core.certificate.VaccinationDGCV1 import de.rki.coronawarnapp.vaccination.core.qrcode.VaccinationCertificateData import io.kotest.matchers.shouldBe @@ -63,49 +62,27 @@ internal class CertificateQrCodeCensorTest { val censor = createInstance() - val logLineToCensor = LogLine( - timestamp = 1, - priority = 3, - message = "Here comes the rawString: $testRawString of the vaccine certificate", - tag = "I am tag", - throwable = null - ) + val logLineToCensor = "Here comes the rawString: $testRawString of the vaccine certificate" - censor.checkLog(logLineToCensor) shouldBe logLineToCensor.copy( - message = "Here comes the rawString: ########-####-####-####-########C\$AH of the vaccine certificate", - ) + censor.checkLog(logLineToCensor)!!.string shouldBe "Here comes the rawString: ########-####-####-####-########C\$AH of the vaccine certificate" - val certDataToCensor = LogLine( - timestamp = 1, - priority = 3, - message = "Hello my name is Kevin Bob, i was born at 1969-11-16, i have been " + - "vaccinated with: 12345 1214765 aaEd/easd ASD-2312 1969-04-20 DE Herbert" + - " urn:uvci:01:NL:PlA8UWS60Z4RZXVALl6GAZ", - tag = "I am tag", - throwable = null - ) + val certDataToCensor = "Hello my name is Kevin Bob, i was born at 1969-11-16, i have been " + + "vaccinated with: 12345 1214765 aaEd/easd ASD-2312 1969-04-20 DE Herbert" + + " urn:uvci:01:NL:PlA8UWS60Z4RZXVALl6GAZ" - censor.checkLog(certDataToCensor) shouldBe certDataToCensor.copy( - message = "Hello my name is nameData/familyName nameData/givenName, i was born at " + - "vaccinationCertificate/dob, i have been vaccinated with: vaccinationData/targetId " + - "vaccinationData/vaccineId vaccinationData/medicalProductId" + - " vaccinationData/marketAuthorizationHolderId vaccinationData/dt" + - " vaccinationData/countryOfVaccination vaccinationData/certificateIssuer" + - " vaccinationData/uniqueCertificateIdentifier" - ) + censor.checkLog(certDataToCensor)!!.string shouldBe "Hello my name is nameData/familyName nameData/givenName, i was born at " + + "vaccinationCertificate/dob, i have been vaccinated with: vaccinationData/targetId " + + "vaccinationData/vaccineId vaccinationData/medicalProductId" + + " vaccinationData/marketAuthorizationHolderId vaccinationData/dt" + + " vaccinationData/countryOfVaccination vaccinationData/certificateIssuer" + + " vaccinationData/uniqueCertificateIdentifier" } @Test fun `checkLog() should return null if no data to censor was set`() = runBlockingTest { val censor = createInstance() - val logLineNotToCensor = LogLine( - timestamp = 1, - priority = 3, - message = "Here comes the rawData: $testRawString", - tag = "I am tag", - throwable = null - ) + val logLineNotToCensor = "Here comes the rawData: $testRawString" censor.checkLog(logLineNotToCensor) shouldBe null } @@ -117,13 +94,7 @@ internal class CertificateQrCodeCensorTest { val censor = createInstance() - val logLineNotToCensor = LogLine( - timestamp = 1, - priority = 3, - message = "Here comes the rawString: $testRawString", - tag = "I am tag", - throwable = null - ) + val logLineNotToCensor = "Here comes the rawString: $testRawString" censor.checkLog(logLineNotToCensor) shouldBe null } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/DebugLoggerTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/DebugLoggerTest.kt index 029f51ee5..24b467db1 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/DebugLoggerTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/DebugLoggerTest.kt @@ -2,6 +2,8 @@ package de.rki.coronawarnapp.bugreporting.debuglog import android.app.Application import dagger.Lazy +import de.rki.coronawarnapp.bugreporting.censors.BugCensor +import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.censor import de.rki.coronawarnapp.bugreporting.censors.submission.CoronaTestCensor import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebugLogTree import de.rki.coronawarnapp.util.CWADebug @@ -29,7 +31,8 @@ class DebugLoggerTest : BaseIOTest() { @MockK lateinit var application: Application @MockK lateinit var component: ApplicationComponent - @MockK lateinit var coronaTestCensor: CoronaTestCensor + @MockK lateinit var coronaTestCensor1: CoronaTestCensor + @MockK lateinit var coronaTestCensor2: CoronaTestCensor private val testDir = File(IO_TEST_BASEDIR, this::class.simpleName!!) private val cacheDir = File(testDir, "cache") @@ -49,10 +52,11 @@ class DebugLoggerTest : BaseIOTest() { every { application.cacheDir } returns cacheDir every { component.inject(any<DebugLogger>()) } answers { val logger = arg<DebugLogger>(0) - logger.bugCensors = Lazy { setOf(coronaTestCensor) } + logger.bugCensors = Lazy { setOf(coronaTestCensor1, coronaTestCensor2) } } - coEvery { coronaTestCensor.checkLog(any()) } returns null + coEvery { coronaTestCensor1.checkLog(any()) } returns null + coEvery { coronaTestCensor2.checkLog(any()) } returns null } @AfterEach @@ -178,19 +182,15 @@ class DebugLoggerTest : BaseIOTest() { setInjectionIsReady(component) } - runBlockingTest { - instance.start() + instance.start() - Timber.tag("Tag123").v("Message456") - advanceTimeBy(2000L) + Timber.tag("Tag123").v("Message456") + advanceTimeBy(2000L) - runningLog.readLines().last().substring(26) shouldBe """ - V/Tag123: Message456 - """.trimIndent() + runningLog.readLines().last().substring(25) shouldBe "V/Tag123: Message456" - instance.stop() - advanceUntilIdle() - } + instance.stop() + advanceUntilIdle() } @Test @@ -214,7 +214,7 @@ class DebugLoggerTest : BaseIOTest() { testCollector.latestValue shouldBe LogState( isLogging = true, isLowStorage = false, - logSize = 78L + logSize = 77L ) instance.stop() @@ -228,4 +228,39 @@ class DebugLoggerTest : BaseIOTest() { testCollector.cancel() } + + @Test + fun `affected text ranges are removed when censoring collisions occur`() = runBlockingTest { + val instance = createInstance(scope = this).apply { + init() + setInjectionIsReady(component) + } + + val logMsg = "Lukas says: A hot coffee is really nice!" + + coEvery { coronaTestCensor1.checkLog(any()) } answers { + val msg = arg<String>(0) + BugCensor.CensoredString(msg).censor("says: A hot coffee", "says: A hot tea") + } + + instance.start() + + Timber.tag("Test").v(logMsg) + advanceTimeBy(2000L) + + runningLog.readLines().last().substring(25) shouldBe "V/Test: Lukas says: A hot tea is really nice!" + + coEvery { coronaTestCensor2.checkLog(any()) } answers { + val msg = arg<String>(0) + BugCensor.CensoredString(msg).censor("says:", "sings:") + } + + Timber.tag("Test").v(logMsg) + advanceTimeBy(2000L) + + runningLog.readLines().last().substring(25) shouldBe "V/Test: Lukas <censoring-collision> is really nice!" + + instance.stop() + advanceUntilIdle() + } } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/LogLineTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/LogLineTest.kt new file mode 100644 index 000000000..50b05b41b --- /dev/null +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/LogLineTest.kt @@ -0,0 +1,39 @@ +package de.rki.coronawarnapp.bugreporting.debuglog + +import android.util.Log +import de.rki.coronawarnapp.util.trimToLength +import io.kotest.matchers.shouldBe +import okio.IOException +import org.junit.jupiter.api.Test +import testhelpers.BaseTest + +class LogLineTest : BaseTest() { + + @Test + fun `log formatting`() { + LogLine( + timestamp = 123L, + priority = Log.ERROR, + tag = "IamATag", + message = "Low storage check failed.", + throwable = null + ).format() shouldBe """ + 1970-01-01T00:00:00.123Z E/IamATag: Low storage check failed. + """.trimIndent() + } + + @Test + fun `log formatting with error`() { + LogLine( + timestamp = 123L, + priority = Log.ERROR, + tag = "IamATag", + message = "Low storage check failed.", + throwable = IOException() + ).format().trimToLength(182) shouldBe """ + 1970-01-01T00:00:00.123Z E/IamATag: Low storage check failed. + java.io.IOException + at de.rki.coronawarnapp.bugreporting.debuglog.LogLineTest.log formatting with error(LogLineTest.kt: + """.trimIndent() + } +} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/DebugLogStorageCheckTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/DebugLogStorageCheckTest.kt index f19da6396..d8d72156f 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/DebugLogStorageCheckTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/DebugLogStorageCheckTest.kt @@ -1,16 +1,19 @@ package de.rki.coronawarnapp.bugreporting.debuglog.internal -import de.rki.coronawarnapp.bugreporting.debuglog.LogLine import io.kotest.matchers.shouldBe +import io.kotest.matchers.string.shouldContain import io.mockk.Called 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 io.mockk.mockk import io.mockk.slot import io.mockk.verify +import kotlinx.coroutines.test.runBlockingTest import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test @@ -22,7 +25,7 @@ class DebugLogStorageCheckTest : BaseTest() { @MockK lateinit var targetPath: File @MockK lateinit var logWriter: LogWriter - private var currentTime: Long = 5001L + private var ourTime: Long = 5001L @BeforeEach fun setup() { @@ -31,7 +34,7 @@ class DebugLogStorageCheckTest : BaseTest() { every { targetPath.usableSpace } returns 250 * 1000 * 1024L every { targetPath.parentFile } returns null every { targetPath.exists() } returns true - every { logWriter.write(any()) } just Runs + coEvery { logWriter.write(any()) } just Runs } @AfterEach @@ -40,12 +43,12 @@ class DebugLogStorageCheckTest : BaseTest() { private fun createInstance() = DebugLogStorageCheck( targetPath = targetPath, - timeProvider = { currentTime }, + timeProvider = { ourTime }, logWriter = logWriter ) @Test - fun `normal not low storage case`() { + fun `normal not low storage case`() = runBlockingTest { val instance = createInstance() instance.isLowStorage() shouldBe false @@ -53,34 +56,37 @@ class DebugLogStorageCheckTest : BaseTest() { } @Test - fun `on errors we print it but do expect low storage`() { - val unexpectedError = Exception("ಠ_ಠ") - every { targetPath.usableSpace } throws unexpectedError + fun `on errors we print it but do expect low storage`() = runBlockingTest { + val unexpectedException = IllegalThreadStateException("ಠ_ಠ") + every { targetPath.usableSpace } throws unexpectedException - val logSlot = slot<LogLine>() - every { logWriter.write(capture(logSlot)) } just Runs + val logSlot = slot<String>() + coEvery { logWriter.write(capture(logSlot)) } just Runs val instance = createInstance() instance.isLowStorage() shouldBe true - logSlot.captured.throwable shouldBe unexpectedError + logSlot.captured.apply { + this shouldContain "ಠ_ಠ" + this shouldContain "IllegalThreadStateException" + } } @Test - fun `low storage default is 200MB`() { + fun `low storage default is 200MB`() = runBlockingTest { every { targetPath.usableSpace } returns 199 * 1000 * 1024L val instance = createInstance() instance.isLowStorage() shouldBe true - currentTime += 60 * 1000L + ourTime += 60 * 1000L instance.isLowStorage() shouldBe true // We only write the warning once - verify(exactly = 1) { logWriter.write(any()) } + coVerify(exactly = 1) { logWriter.write(any()) } } @Test - fun `target path does not exists`() { + fun `target path does not exists`() = runBlockingTest { val parentPath = mockk<File>() every { parentPath.exists() } returns true every { parentPath.parentFile } returns null @@ -97,7 +103,7 @@ class DebugLogStorageCheckTest : BaseTest() { } @Test - fun `checks happen at most every 5 seconds`() { + fun `checks happen at most every 5 seconds`() = runBlockingTest { val instance = createInstance() instance.isLowStorage() shouldBe false @@ -107,7 +113,7 @@ class DebugLogStorageCheckTest : BaseTest() { verify(exactly = 1) { targetPath.usableSpace } - currentTime += 5000L + ourTime += 5000L instance.isLowStorage() shouldBe true diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/LogSnapshotterTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/LogSnapshotterTest.kt index 0bba493b4..475ec34f8 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/LogSnapshotterTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/bugreporting/debuglog/internal/LogSnapshotterTest.kt @@ -8,7 +8,8 @@ import io.kotest.matchers.shouldBe import io.mockk.MockKAnnotations import io.mockk.every import io.mockk.impl.annotations.MockK -import org.joda.time.DateTime +import org.joda.time.Instant +import org.joda.time.format.DateTimeFormat import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test @@ -27,7 +28,9 @@ class LogSnapshotterTest : BaseIOTest() { private val runningLogFake = File(testDir, "running.log") private val snapshotDir = File(cacheDir, "debuglog_snapshots") - private val expectedSnapshot = File(snapshotDir, "CWA Log 1970-01-01 00_00_00.000.zip") + private val fileNameDateFormatter = DateTimeFormat.forPattern("yyyy-MM-dd HH_mm_ss.SSS") + private val userTime = Instant.EPOCH.toUserTimeZone() + private val expectedSnapshot = File(snapshotDir, "CWA Log ${userTime.toString(fileNameDateFormatter)}.zip") @BeforeEach fun setup() { @@ -39,7 +42,7 @@ class LogSnapshotterTest : BaseIOTest() { testDir.exists() shouldBe true every { debugLogger.runningLog } returns runningLogFake - every { timeStamper.nowUTC.toUserTimeZone() } returns DateTime.parse("1970-01-01T00:00:00.000Z") + every { timeStamper.nowUTC } returns userTime.toInstant() runningLogFake.parentFile!!.mkdirs() runningLogFake.writeText("1 Doge = 1 Doge") -- GitLab