Skip to content
This repository has been archived by the owner on Jun 20, 2023. It is now read-only.

Commit

Permalink
Family test censor (EXPOSUREAPP-12785) (#5087)
Browse files Browse the repository at this point in the history
* family test censor

* klint

* tests

* fix test
  • Loading branch information
chiljamgossow authored Apr 14, 2022
1 parent 53c2345 commit c7292d5
Show file tree
Hide file tree
Showing 6 changed files with 224 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import dagger.Module
import dagger.android.ContributesAndroidInjector
import de.rki.coronawarnapp.R
import de.rki.coronawarnapp.bugreporting.censors.family.FamilyTestCensor
import de.rki.coronawarnapp.coronatest.qrcode.CoronaTestQRCode
import io.mockk.MockKAnnotations
import io.mockk.impl.annotations.MockK
import org.junit.After
import org.junit.Before
import org.junit.Test
Expand All @@ -27,6 +29,7 @@ class FamilyTestConsentFragmentTest : BaseUITest() {

private val request = CoronaTestQRCode.PCR(qrCodeGUID = "qrCodeGUID", rawQrCode = "rawQrCode")
private lateinit var viewModel: FamilyTestConsentViewModel
@MockK lateinit var familyTestCensor: FamilyTestCensor

private val fragmentArgs = FamilyTestConsentFragmentArgs(
coronaTestQrCode = request
Expand All @@ -37,7 +40,8 @@ class FamilyTestConsentFragmentTest : BaseUITest() {
MockKAnnotations.init(this, relaxed = true)
viewModel = FamilyTestConsentViewModel(
TestDispatcherProvider(),
request
request,
familyTestCensor
)
setupMockViewModel(
object : FamilyTestConsentViewModel.Factory {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,16 @@ import de.rki.coronawarnapp.bugreporting.censors.contactdiary.OrganizerRegistrat
import de.rki.coronawarnapp.bugreporting.censors.dcc.CwaUserCensor
import de.rki.coronawarnapp.bugreporting.censors.dcc.DccQrCodeCensor
import de.rki.coronawarnapp.bugreporting.censors.dccticketing.DccTicketingJwtCensor
import de.rki.coronawarnapp.bugreporting.censors.family.FamilyTestCensor
import de.rki.coronawarnapp.bugreporting.censors.presencetracing.CheckInsCensor
import de.rki.coronawarnapp.bugreporting.censors.presencetracing.TraceLocationCensor
import de.rki.coronawarnapp.bugreporting.censors.submission.CoronaTestCensor
import de.rki.coronawarnapp.bugreporting.censors.submission.CoronaTestCertificateCensor
import de.rki.coronawarnapp.bugreporting.censors.submission.PcrQrCodeCensor
import de.rki.coronawarnapp.bugreporting.censors.submission.PcrTeleTanCensor
import de.rki.coronawarnapp.bugreporting.censors.submission.RACoronaTestCensor
import de.rki.coronawarnapp.bugreporting.censors.submission.RatProfileCensor
import de.rki.coronawarnapp.bugreporting.censors.submission.RapidQrCodeCensor
import de.rki.coronawarnapp.bugreporting.censors.submission.RatProfileCensor
import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebugLoggerScope
import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebuggerScope
import de.rki.coronawarnapp.bugreporting.debuglog.upload.server.LogUploadApiV1
Expand Down Expand Up @@ -148,4 +149,8 @@ class BugReportingSharedModule {
@Provides
@IntoSet
fun ticketingJwtCensor(censor: DccTicketingJwtCensor): BugCensor = censor

@Provides
@IntoSet
fun familyTestCensor(censor: FamilyTestCensor): BugCensor = censor
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package de.rki.coronawarnapp.bugreporting.censors.family

import de.rki.coronawarnapp.bugreporting.censors.BugCensor
import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebuggerScope
import de.rki.coronawarnapp.familytest.core.repository.FamilyTestRepository
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import org.joda.time.LocalDate
import org.joda.time.format.DateTimeFormat
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class FamilyTestCensor @Inject constructor(
@DebuggerScope debugScope: CoroutineScope,
familyTestRepository: FamilyTestRepository,
) : BugCensor {

private val mutex = Mutex()
private val dateFormatter = DateTimeFormat.forPattern("yyyy-MM-dd")
private val names = mutableSetOf<String>()
private val dates = mutableSetOf<LocalDate>()
private val registrationTokens = mutableSetOf<String>()
private val identifiers = mutableSetOf<String>()

init {
listOf(
familyTestRepository.familyTests,
familyTestRepository.familyTestsInRecycleBin
)
.merge()
.filterNotNull()
.onEach { tests ->
mutex.withLock {
tests.forEach { test ->
registrationTokens.add(test.registrationToken)
identifiers.add(test.identifier)
names.add(test.personName)
test.coronaTest.additionalInfo?.let { info ->
info.firstName?.let { names.add(it) }
info.lastName?.let { names.add(it) }
info.dateOfBirth?.let { dates.add(it) }
}
}
}
}.launchIn(debugScope)
}

override suspend fun checkLog(message: String): BugCensor.CensorContainer? {
var container = BugCensor.CensorContainer(message)
mutex.withLock {
registrationTokens.forEach {
container = container.censor(it, "#token")
}
identifiers.forEach {
container = container.censor(it, "#identifier")
}
names.forEach {
container = container.censor(it, "#name")
}
dates.forEach {
container = container.censor(it.toString(dateFormatter), "#dateOfBirth")
}
}
return container.nullIfEmpty()
}

suspend fun addName(name: String) {
mutex.withLock { names.add(name) }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import androidx.lifecycle.asLiveData
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import de.rki.coronawarnapp.bugreporting.censors.family.FamilyTestCensor
import de.rki.coronawarnapp.coronatest.qrcode.CoronaTestQRCode
import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
import de.rki.coronawarnapp.util.ui.SingleLiveEvent
Expand All @@ -16,6 +17,7 @@ import kotlinx.coroutines.flow.map
class FamilyTestConsentViewModel @AssistedInject constructor(
dispatcherProvider: DispatcherProvider,
@Assisted private val coronaTestQRCode: CoronaTestQRCode,
private val familyTestCensor: FamilyTestCensor,
) : CWAViewModel(dispatcherProvider = dispatcherProvider) {

val routeToScreen = SingleLiveEvent<FamilyTestConsentNavigationEvents>()
Expand All @@ -39,11 +41,13 @@ class FamilyTestConsentViewModel @AssistedInject constructor(
}

fun onConsentButtonClick() = launch {
val personName = personName.first()
familyTestCensor.addName(personName)
FamilyTestConsentNavigationEvents.NavigateToCertificateRequest(
coronaTestQRCode = coronaTestQRCode,
consentGiven = true,
allowReplacement = false,
personName = personName.first()
personName = personName
).run { routeToScreen.postValue(this) }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import de.rki.coronawarnapp.coronatest.CoronaTestRepository
import de.rki.coronawarnapp.coronatest.antigen.profile.RATProfileSettingsDataStore
import de.rki.coronawarnapp.covidcertificate.person.core.PersonCertificatesSettings
import de.rki.coronawarnapp.covidcertificate.test.core.TestCertificateRepository
import de.rki.coronawarnapp.familytest.core.repository.FamilyTestRepository
import de.rki.coronawarnapp.presencetracing.checkins.CheckInRepository
import de.rki.coronawarnapp.presencetracing.storage.repo.TraceLocationRepository
import de.rki.coronawarnapp.submission.SubmissionSettings
Expand Down Expand Up @@ -118,4 +119,11 @@ class MockProvider {
fun personCertificatesSettings(): PersonCertificatesSettings = mockk {
every { currentCwaUser } returns flowOf(null)
}

@Singleton
@Provides
fun familyTestRepository(): FamilyTestRepository = mockk {
every { familyTests } returns flowOf(emptySet())
every { familyTestsInRecycleBin } returns flowOf(emptySet())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package de.rki.coronawarnapp.bugreporting.censors.family

import de.rki.coronawarnapp.coronatest.server.CoronaTestResult
import de.rki.coronawarnapp.coronatest.type.BaseCoronaTest
import de.rki.coronawarnapp.familytest.core.model.CoronaTest
import de.rki.coronawarnapp.familytest.core.model.FamilyCoronaTest
import de.rki.coronawarnapp.familytest.core.repository.FamilyTestRepository
import io.kotest.matchers.shouldBe
import io.mockk.MockKAnnotations
import io.mockk.coEvery
import io.mockk.impl.annotations.MockK
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.TestCoroutineScope
import kotlinx.coroutines.test.runBlockingTest
import org.joda.time.Instant
import org.joda.time.LocalDate
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test

@Suppress("MaxLineLength")
internal class FamilyTestCensorTest {

private val test = CoronaTest(
type = BaseCoronaTest.Type.RAPID_ANTIGEN,
identifier = "qrcode-RAPID_ANTIGEN-6a90a60",
registeredAt = Instant.parse("2022-04-13T15:33:14.637Z"),
registrationToken = "ac7f72a0-0135-41c5-ad14-6a4299865aca",
testResult = CoronaTestResult.PCR_OR_RAT_PENDING,
additionalInfo = CoronaTest.AdditionalInfo(
firstName = "Louisa",
lastName = "Davis",
dateOfBirth = LocalDate.parse("1999-12-02"),
createdAt = Instant.parse("2022-04-13T15:33:14.637Z")
)
)

private val test2 = CoronaTest(
type = BaseCoronaTest.Type.PCR,
identifier = "qrcode-PCR-12345",
registeredAt = Instant.parse("2022-04-13T15:33:14.637Z"),
registrationToken = "regToken1234",
testResult = CoronaTestResult.PCR_OR_RAT_PENDING,
)

private val familyTest = FamilyCoronaTest(
personName = "Angelina",
test
)

private val familyTestRecycleBin = FamilyCoronaTest(
personName = "Maria",
test2
)

@MockK lateinit var familyTestRepository: FamilyTestRepository

@BeforeEach
fun setUp() {
MockKAnnotations.init(this)
coEvery { familyTestRepository.familyTests } returns flowOf(setOf(familyTest))
coEvery { familyTestRepository.familyTestsInRecycleBin } returns flowOf(setOf(familyTestRecycleBin))
}

private fun createInstance() = FamilyTestCensor(
TestCoroutineScope(),
familyTestRepository,
)

@Test
fun `checkLog() should return censored LogLine`() = runBlockingTest {

val censor = createInstance()

val logLineToCensor =
"[FamilyCoronaTest(personName=Angelina, coronaTest=CoronaTest(identifier=qrcode-RAPID_ANTIGEN-6a90a60, type=RAPID_ANTIGEN, registeredAt=2022-04-13T15:33:14.637Z, registrationToken=ac7f72a0-0135-41c5-ad14-6a4299865aca, testResult=RAT_NEGATIVE(6), labId=null, qrCodeHash=795d7c5c3fff50d58694fbd3e1a91d2e1f88f2638a3031c5a3ac21ddea986cf9, dcc=Dcc(isDccSupportedByPoc=false, isDccConsentGiven=true, isDccDataSetCreated=false), uiState=UiState(isViewed=true, didShowBadge=true, isResultAvailableNotificationSent=false, hasResultChangeBadge=false), additionalInfo=AdditionalInfo(createdAt=2022-04-13T11:06:29.000Z, firstName=Louisa, lastName=Davis, dateOfBirth=1999-12-02, sampleCollectedAt=2022-04-13T06:00:00.000Z), recycledAt=null)"

val censored = censor.checkLog(logLineToCensor)!!
.compile()!!.censored

// personName
censored.contains("Angelina") shouldBe false
// identifier
censored.contains("qrcode-RAPID_ANTIGEN-6a90a60") shouldBe false
// registration token
censored.contains("ac7f72a0-0135-41c5-ad14-6a4299865aca") shouldBe false
// first name
censored.contains("Louisa") shouldBe false
// last name
censored.contains("Davis") shouldBe false
// date of birth
censored.contains("1999-12-02") shouldBe false
}

@Test
fun `checkLog() should return null if no data to censor was set`() = runBlockingTest {
coEvery { familyTestRepository.familyTests } returns flowOf(setOf())
coEvery { familyTestRepository.familyTestsInRecycleBin } returns flowOf(setOf())
val censor = createInstance()

val logLineNotToCensor = "Nothing to censor here, Angelina"

censor.checkLog(logLineNotToCensor) shouldBe null
}

@Test
fun `personName of family should be censored`() = runBlockingTest {
coEvery { familyTestRepository.familyTests } returns flowOf(setOf())
coEvery { familyTestRepository.familyTestsInRecycleBin } returns flowOf(setOf())
val censor = createInstance()
censor.addName("Angelina")

val logLineNotToCensor = "Please censor, Angelina"

censor.checkLog(logLineNotToCensor)!!.compile()!!.censored shouldBe "Please censor, #name"
}

@Test
fun `checkLog() should return null if nothing should be censored`() = runBlockingTest {
val censor = createInstance()
val logLineNotToCensor = "Nothing to censor here"

censor.checkLog(logLineNotToCensor) shouldBe null
}
}

0 comments on commit c7292d5

Please sign in to comment.