From e7e16f29d7e96ee2becf7e6a8b096925178ab0ac Mon Sep 17 00:00:00 2001
From: Kolya Opahle <k.opahle@sap.com>
Date: Wed, 16 Jun 2021 15:28:01 +0200
Subject: [PATCH] Link to FAQ if Certificate is not available
 (EXPOSUREAPP-7846) (#3454)

* Added labId to test objects and server response

* Added new exception state and strings for dialog

* Extended CertificateData classes with labId field

* Added logic to TestCertificateRepository to add labId to certificate in requestCertificate
and check if its valid in refresh

* Enhanced error processing in CertificatesFragment to display faq link when relevant and human readable exception text

* Fixing unittests

Co-authored-by: BMItter <Berndus@gmx.de>
Co-authored-by: harambasicluka <64483219+harambasicluka@users.noreply.github.com>
Co-authored-by: chris-cwa <69595386+chris-cwa@users.noreply.github.com>
---
 .../coronatest/server/CoronaTestResult.kt     |  6 ++--
 .../coronatest/server/VerificationApiV1.kt    |  3 +-
 .../coronatest/type/CoronaTest.kt             |  3 ++
 .../coronatest/type/pcr/PCRCoronaTest.kt      |  3 ++
 .../coronatest/type/pcr/PCRTestProcessor.kt   |  1 +
 .../type/rapidantigen/RACoronaTest.kt         |  3 ++
 .../type/rapidantigen/RATestProcessor.kt      |  4 ++-
 .../TestCertificateServerException.kt         |  4 +++
 .../test/core/TestCertificateRepository.kt    | 36 ++++++++++++++++++-
 .../test/core/storage/PCRCertificateData.kt   |  3 ++
 .../test/core/storage/RACertificateData.kt    |  3 ++
 .../core/storage/StoredTestCertificateData.kt |  1 +
 .../test/ui/CertificatesFragment.kt           | 23 +++++++-----
 .../values-de/green_certificate_strings.xml   |  4 +++
 .../res/values/green_certificate_strings.xml  |  4 +++
 .../server/VerificationApiV1Test.kt           |  3 +-
 .../server/VerificationServerTest.kt          |  5 +--
 .../coronatest/type/pcr/PCRProcessorTest.kt   |  7 ++++
 .../type/rapidantigen/RAProcessorTest.kt      |  8 +++++
 .../http/playbook/DefaultPlaybookTest.kt      |  9 +++--
 .../submission/CoronaTestServiceTest.kt       |  7 ++--
 21 files changed, 119 insertions(+), 21 deletions(-)

diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/server/CoronaTestResult.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/server/CoronaTestResult.kt
index 0fdb395a6..09c931f12 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/server/CoronaTestResult.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/server/CoronaTestResult.kt
@@ -8,13 +8,15 @@ import org.json.JSONObject
 
 data class CoronaTestResultResponse(
     val coronaTestResult: CoronaTestResult,
-    val sampleCollectedAt: Instant?
+    val sampleCollectedAt: Instant?,
+    val labId: String?
 ) {
     companion object {
         fun fromResponse(response: VerificationApiV1.TestResultResponse) =
             CoronaTestResultResponse(
                 coronaTestResult = CoronaTestResult.fromInt(response.testResult),
-                sampleCollectedAt = response.sampleCollectedAt?.toLong()?.let { Instant.ofEpochSecond(it) }
+                sampleCollectedAt = response.sampleCollectedAt?.toLong()?.let { Instant.ofEpochSecond(it) },
+                labId = response.labId
             )
     }
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/server/VerificationApiV1.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/server/VerificationApiV1.kt
index 4f4662767..b7c4efd79 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/server/VerificationApiV1.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/server/VerificationApiV1.kt
@@ -32,7 +32,8 @@ interface VerificationApiV1 {
 
     data class TestResultResponse(
         @SerializedName("testResult") val testResult: Int,
-        @SerializedName("sc") val sampleCollectedAt: Int?
+        @SerializedName("sc") val sampleCollectedAt: Int?,
+        @SerializedName("labId") val labId: String?
     )
 
     @POST("version/v1/testresult")
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/CoronaTest.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/CoronaTest.kt
index 824a468b7..d1fc0813d 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/CoronaTest.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/CoronaTest.kt
@@ -49,6 +49,9 @@ interface CoronaTest {
     // Has the corresponding entry been created in the test certificate storage
     val isDccDataSetCreated: Boolean
 
+    //  The ID of the lab that uploaded the test result
+    val labId: String?
+
     enum class Type(val raw: String) {
         @SerializedName("PCR")
         PCR("PCR"),
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/pcr/PCRCoronaTest.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/pcr/PCRCoronaTest.kt
index fd28cb447..0fc8c26a3 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/pcr/PCRCoronaTest.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/pcr/PCRCoronaTest.kt
@@ -46,6 +46,9 @@ data class PCRCoronaTest(
 
     @SerializedName("isDccDataSetCreated")
     override val isDccDataSetCreated: Boolean = false,
+
+    @SerializedName("labId")
+    override val labId: String? = null,
 ) : CoronaTest {
 
     override val type: CoronaTest.Type
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/pcr/PCRTestProcessor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/pcr/PCRTestProcessor.kt
index 58bfe8a28..ce35035b4 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/pcr/PCRTestProcessor.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/pcr/PCRTestProcessor.kt
@@ -130,6 +130,7 @@ class PCRTestProcessor @Inject constructor(
             testResult = testResult,
             testResultReceivedAt = determineReceivedDate(null, testResult),
             isDccConsentGiven = request.isDccConsentGiven,
+            labId = response.testResultResponse.labId
         )
     }
 
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RACoronaTest.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RACoronaTest.kt
index 6dfa9ad11..fa0933bc2 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RACoronaTest.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RACoronaTest.kt
@@ -70,6 +70,9 @@ data class RACoronaTest(
     override val isDccConsentGiven: Boolean = false,
     @SerializedName("isDccDataSetCreated")
     override val isDccDataSetCreated: Boolean = false,
+
+    @SerializedName("labId")
+    override val labId: String? = null,
 ) : CoronaTest {
 
     override val type: CoronaTest.Type
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RATestProcessor.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RATestProcessor.kt
index 075881497..e119cba0f 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RATestProcessor.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RATestProcessor.kt
@@ -98,6 +98,7 @@ class RATestProcessor @Inject constructor(
             sampleCollectedAt = sampleCollectedAt,
             isDccSupportedByPoc = request.isDccSupportedByPoc,
             isDccConsentGiven = request.isDccConsentGiven,
+            labId = registrationData.testResultResponse.labId
         )
     }
 
@@ -137,7 +138,8 @@ class RATestProcessor @Inject constructor(
                     Timber.tag(TAG).w("HTTP 400 error after 21 days, remapping to RAT_REDEEMED.")
                     CoronaTestResultResponse(
                         coronaTestResult = RAT_REDEEMED,
-                        sampleCollectedAt = null
+                        sampleCollectedAt = null,
+                        labId = null
                     )
                 } else {
                     Timber.tag(TAG).v("Unexpected HTTP 400 error, rethrowing...")
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/TestCertificateServerException.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/TestCertificateServerException.kt
index 6cbe138c4..fb6fb4585 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/TestCertificateServerException.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/exception/TestCertificateServerException.kt
@@ -62,6 +62,10 @@ class TestCertificateServerException(
             "DCC Components failed with error 500: Signing server error",
             ERROR_MESSAGE_E2E_ERROR_CALL_HOTLINE
         ),
+        DCC_NOT_SUPPORTED_BY_LAB(
+            "DCC is not supported by the lab",
+            ERROR_MESSAGE_DCC_NOT_SUPPORTED_BY_LAB
+        ),
         DCC_COMP_NO_NETWORK(
             "DCC Test Certificate Components failed due to no network connection.",
             ERROR_MESSAGE_NO_NETWORK
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/TestCertificateRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/TestCertificateRepository.kt
index ed383c7d1..17f9632e9 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/TestCertificateRepository.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/TestCertificateRepository.kt
@@ -2,6 +2,7 @@ package de.rki.coronawarnapp.covidcertificate.test.core
 
 import de.rki.coronawarnapp.bugreporting.reportProblem
 import de.rki.coronawarnapp.coronatest.type.CoronaTest
+import de.rki.coronawarnapp.covidcertificate.exception.TestCertificateServerException
 import de.rki.coronawarnapp.covidcertificate.test.core.qrcode.TestCertificateQRCodeExtractor
 import de.rki.coronawarnapp.covidcertificate.test.core.storage.PCRCertificateData
 import de.rki.coronawarnapp.covidcertificate.test.core.storage.RACertificateData
@@ -87,7 +88,7 @@ class TestCertificateRepository @Inject constructor(
 
     /**
      * Will create a new test certificate entry.
-     * Automation via [de.rki.coronawarnapp.coronatest.type.common.TestCertificateRetrievalScheduler] will kick in.
+     * Automation via [de.rki.coronawarnapp.covidcertificate.test.core.execution.TestCertificateRetrievalScheduler] will kick in.
      *
      * Throws an exception if there already is a test certificate entry for this test
      * or this is not a valid test (no consent, not supported by PoC).
@@ -114,11 +115,13 @@ class TestCertificateRepository @Inject constructor(
                     identifier = identifier,
                     registeredAt = test.registeredAt,
                     registrationToken = test.registrationToken,
+                    labId = test.labId
                 )
                 CoronaTest.Type.RAPID_ANTIGEN -> RACertificateData(
                     identifier = identifier,
                     registeredAt = test.registeredAt,
                     registrationToken = test.registrationToken,
+                    labId = test.labId
                 )
             }
             val container = TestCertificateContainer(
@@ -172,12 +175,42 @@ class TestCertificateRepository @Inject constructor(
             }
         }
 
+        // Not sure i really like this
+        internalData.updateBlocking {
+            Timber.tag(TAG).d("Checking for invalid lab id.")
+
+            val refreshedCerts = values
+                .filter { workedOnIds.contains(it.identifier) } // Refresh targets
+                .filter { it.labId == null } // Targets of this step
+                .map { cert ->
+                    Timber.tag(TAG).d("%s is missing a lab id returning exception", cert)
+                    RefreshResult(
+                        cert,
+                        TestCertificateServerException(
+                            TestCertificateServerException.ErrorCode.DCC_NOT_SUPPORTED_BY_LAB
+                        )
+                    )
+                }
+
+            refreshedCerts.forEach {
+                refreshCallResults[it.certificateContainer.identifier] = it
+            }
+
+            mutate {
+                refreshedCerts
+                    .filter { it.error == null }
+                    .map { it.certificateContainer }
+                    .forEach { this[it.identifier] = it }
+            }
+        }
+
         internalData.updateBlocking {
             Timber.tag(TAG).d("Checking for unregistered public keys.")
 
             val refreshedCerts = values
                 .filter { workedOnIds.contains(it.identifier) } // Refresh targets
                 .filter { !it.isPublicKeyRegistered } // Targets of this step
+                .filter { it.labId != null }
                 .map { cert ->
                     withContext(dispatcherProvider.IO) {
                         try {
@@ -208,6 +241,7 @@ class TestCertificateRepository @Inject constructor(
             val refreshedCerts = values
                 .filter { workedOnIds.contains(it.identifier) } // Refresh targets
                 .filter { it.isPublicKeyRegistered && it.isCertificateRetrievalPending } // Targets of this step
+                .filter { it.labId != null }
                 .map { cert ->
                     withContext(dispatcherProvider.IO) {
                         try {
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/storage/PCRCertificateData.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/storage/PCRCertificateData.kt
index 118bf5bc1..2fe7dcb30 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/storage/PCRCertificateData.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/storage/PCRCertificateData.kt
@@ -37,6 +37,9 @@ data class PCRCertificateData internal constructor(
 
     @SerializedName("testCertificateQrCode")
     override val testCertificateQrCode: String? = null,
+
+    @SerializedName("labId")
+    override val labId: String? = null,
 ) : StoredTestCertificateData {
 
     // Otherwise GSON unsafes reflection to create this class, and sets the LAZY to null
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/storage/RACertificateData.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/storage/RACertificateData.kt
index dfcb82bad..8b87ecb42 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/storage/RACertificateData.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/storage/RACertificateData.kt
@@ -37,6 +37,9 @@ data class RACertificateData(
 
     @SerializedName("testCertificateQrCode")
     override val testCertificateQrCode: String? = null,
+
+    @SerializedName("labId")
+    override val labId: String? = null,
 ) : StoredTestCertificateData {
 
     // Otherwise GSON unsafes reflection to create this class, and sets the LAZY to null
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/storage/StoredTestCertificateData.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/storage/StoredTestCertificateData.kt
index 131c18e26..16c307f8e 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/storage/StoredTestCertificateData.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/storage/StoredTestCertificateData.kt
@@ -18,4 +18,5 @@ interface StoredTestCertificateData {
     val encryptedDataEncryptionkey: ByteString?
     val encryptedDccCose: ByteString?
     val testCertificateQrCode: String?
+    val labId: String?
 }
diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/CertificatesFragment.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/CertificatesFragment.kt
index afd660e97..f83587427 100644
--- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/CertificatesFragment.kt
+++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/ui/CertificatesFragment.kt
@@ -7,9 +7,12 @@ import androidx.fragment.app.Fragment
 import androidx.navigation.fragment.findNavController
 import androidx.recyclerview.widget.DefaultItemAnimator
 import de.rki.coronawarnapp.R
+import de.rki.coronawarnapp.bugreporting.ui.toErrorDialogBuilder
+import de.rki.coronawarnapp.covidcertificate.exception.TestCertificateServerException
 import de.rki.coronawarnapp.covidcertificate.vaccination.ui.list.VaccinationListFragment
 import de.rki.coronawarnapp.databinding.FragmentCertificatesBinding
 import de.rki.coronawarnapp.util.DialogHelper
+import de.rki.coronawarnapp.util.ExternalActionHelper.openUrl
 import de.rki.coronawarnapp.util.di.AutoInject
 import de.rki.coronawarnapp.util.lists.decorations.TopBottomPaddingDecorator
 import de.rki.coronawarnapp.util.lists.diffutil.update
@@ -58,14 +61,18 @@ class CertificatesFragment : Fragment(R.layout.fragment_certificates), AutoInjec
                     )
                 }
                 is CertificatesFragmentEvents.ShowRefreshErrorCertificateDialog -> {
-                    val dialog = DialogHelper.DialogInstance(
-                        context = requireContext(),
-                        title = R.string.test_certificate_refresh_dialog_title,
-                        message = event.error.localizedMessage,
-                        positiveButton = R.string.test_certificate_refresh_dialog_confirm_button,
-                        cancelable = false
-                    )
-                    DialogHelper.showDialog(dialog)
+                    event.error.toErrorDialogBuilder(requireContext()).apply {
+                        setTitle(R.string.test_certificate_refresh_dialog_title)
+                        setCancelable(false)
+                        if (
+                            event.error is TestCertificateServerException &&
+                            event.error.errorCode == TestCertificateServerException.ErrorCode.DCC_NOT_SUPPORTED_BY_LAB
+                        ) {
+                            setNeutralButton(R.string.test_certificate_error_invalid_labid_faq) { _, _ ->
+                                openUrl(getString(R.string.test_certificate_error_invalid_labid_faq_link))
+                            }
+                        }
+                    }.show()
                 }
                 is CertificatesFragmentEvents.ShowDeleteErrorCertificateDialog -> {
                     val dialog = DialogHelper.DialogInstance(
diff --git a/Corona-Warn-App/src/main/res/values-de/green_certificate_strings.xml b/Corona-Warn-App/src/main/res/values-de/green_certificate_strings.xml
index 6c5711aae..2cdecbe39 100644
--- a/Corona-Warn-App/src/main/res/values-de/green_certificate_strings.xml
+++ b/Corona-Warn-App/src/main/res/values-de/green_certificate_strings.xml
@@ -100,4 +100,8 @@
     <string name="test_certificate_error_label_refreshing">"Ihr Zertifikat wird gerade erstellt…"</string>
     <!-- XTXT: Test error card body refreshing -->
     <string name="test_certificate_error_refreshing_status">"Ihr Zertifikat wird gerade angefragt, dies kann einige Minuten dauern…"</string>
+    <!-- XBUT: Text for invalid test certificate error button, linking to FAQ-->
+    <string name="test_certificate_error_invalid_labid_faq">"FAQ zu Testzertifikaten"</string>
+    <!-- XTXT: Explains user about test certificate: URL, has to be "translated" into english (relevant for all languages except german) - https://www.coronawarn.app/en/faq/#vac_cert_invalid -->
+    <string name="test_certificate_error_invalid_labid_faq_link">"https://www.coronawarn.app/de/faq/#test_cert"</string>
 </resources>
diff --git a/Corona-Warn-App/src/main/res/values/green_certificate_strings.xml b/Corona-Warn-App/src/main/res/values/green_certificate_strings.xml
index e40bf9c68..be47fa7e5 100644
--- a/Corona-Warn-App/src/main/res/values/green_certificate_strings.xml
+++ b/Corona-Warn-App/src/main/res/values/green_certificate_strings.xml
@@ -100,4 +100,8 @@
     <string name="test_certificate_error_label_refreshing">"Your certificate is being created..."</string>
     <!-- XTXT: Test error card body refreshing -->
     <string name="test_certificate_error_refreshing_status">"Your certificate is being requested. This may take a few minutes..."</string>
+    <!-- XBUT: Text for invalid test certificate error button, linking to FAQ-->
+    <string name="test_certificate_error_invalid_labid_faq"></string>
+    <!-- XTXT: Explains user about test certificate: URL, has to be "translated" into english (relevant for all languages except german) - https://www.coronawarn.app/en/faq/#vac_cert_invalid -->
+    <string name="test_certificate_error_invalid_labid_faq_link"></string>
 </resources>
\ No newline at end of file
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/server/VerificationApiV1Test.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/server/VerificationApiV1Test.kt
index 9076ba3b7..bc48dcd23 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/server/VerificationApiV1Test.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/server/VerificationApiV1Test.kt
@@ -169,7 +169,8 @@ class VerificationApiV1Test : BaseIOTest() {
             requestBody
         ) shouldBe VerificationApiV1.TestResultResponse(
             testResult = 1,
-            sampleCollectedAt = null
+            sampleCollectedAt = null,
+            labId = null,
         )
 
         webServer.takeRequest(5, TimeUnit.SECONDS)!!.apply {
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/server/VerificationServerTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/server/VerificationServerTest.kt
index 07f8cbc45..1f68b62c1 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/server/VerificationServerTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/server/VerificationServerTest.kt
@@ -166,12 +166,13 @@ class VerificationServerTest : BaseIOTest() {
                 registrationToken shouldBe "testRegistrationToken"
                 requestPadding.length shouldBe 170
             }
-            VerificationApiV1.TestResultResponse(testResult = 2, sampleCollectedAt = null)
+            VerificationApiV1.TestResultResponse(testResult = 2, sampleCollectedAt = null, labId = null)
         }
 
         server.pollTestResult("testRegistrationToken") shouldBe CoronaTestResultResponse(
             coronaTestResult = CoronaTestResult.PCR_POSITIVE,
-            sampleCollectedAt = null
+            sampleCollectedAt = null,
+            labId = null,
         )
 
         coVerify { verificationApi.getTestResult(any(), any(), any()) }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/pcr/PCRProcessorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/pcr/PCRProcessorTest.kt
index 04e5a7110..d11874da7 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/pcr/PCRProcessorTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/pcr/PCRProcessorTest.kt
@@ -67,6 +67,7 @@ class PCRProcessorTest : BaseTest() {
             coEvery { checkTestResult(any()) } returns CoronaTestResultResponse(
                 coronaTestResult = PCR_OR_RAT_PENDING,
                 sampleCollectedAt = null,
+                labId = null,
             )
             coEvery { registerTest(any()) } answers {
                 val request = arg<RegistrationRequest>(0)
@@ -76,6 +77,7 @@ class PCRProcessorTest : BaseTest() {
                     testResultResponse = CoronaTestResultResponse(
                         coronaTestResult = PCR_OR_RAT_PENDING,
                         sampleCollectedAt = null,
+                        labId = null,
                     ),
                 )
             }
@@ -131,6 +133,7 @@ class PCRProcessorTest : BaseTest() {
             testResultResponse = CoronaTestResultResponse(
                 coronaTestResult = PCR_OR_RAT_PENDING,
                 sampleCollectedAt = null,
+                labId = null,
             )
         )
         coEvery { submissionService.registerTest(any()) } answers { registrationData }
@@ -144,6 +147,7 @@ class PCRProcessorTest : BaseTest() {
                 testResultResponse = CoronaTestResultResponse(
                     coronaTestResult = it,
                     sampleCollectedAt = null,
+                    labId = null,
                 )
             )
             when (it) {
@@ -170,6 +174,7 @@ class PCRProcessorTest : BaseTest() {
             CoronaTestResultResponse(
                 coronaTestResult = pollResult,
                 sampleCollectedAt = null,
+                labId = null,
             )
         }
 
@@ -222,6 +227,7 @@ class PCRProcessorTest : BaseTest() {
             CoronaTestResultResponse(
                 coronaTestResult = PCR_POSITIVE,
                 sampleCollectedAt = null,
+                labId = null,
             )
         }
 
@@ -284,6 +290,7 @@ class PCRProcessorTest : BaseTest() {
             testResultResponse = CoronaTestResultResponse(
                 coronaTestResult = PCR_OR_RAT_PENDING,
                 sampleCollectedAt = null,
+                labId = null,
             )
         )
         coEvery { submissionService.registerTest(any()) } answers { registrationData }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RAProcessorTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RAProcessorTest.kt
index 2846d0f54..c9c60d347 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RAProcessorTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/coronatest/type/rapidantigen/RAProcessorTest.kt
@@ -67,6 +67,7 @@ class RAProcessorTest : BaseTest() {
             coEvery { checkTestResult(any()) } returns CoronaTestResultResponse(
                 coronaTestResult = PCR_OR_RAT_PENDING,
                 sampleCollectedAt = null,
+                labId = null,
             )
 
             coEvery { registerTest(any()) } answers {
@@ -77,6 +78,7 @@ class RAProcessorTest : BaseTest() {
                     testResultResponse = CoronaTestResultResponse(
                         coronaTestResult = PCR_OR_RAT_PENDING,
                         sampleCollectedAt = null,
+                        labId = null,
                     )
                 )
             }
@@ -121,6 +123,7 @@ class RAProcessorTest : BaseTest() {
         coEvery { submissionService.checkTestResult(any()) } returns CoronaTestResultResponse(
             coronaTestResult = PCR_OR_RAT_PENDING,
             sampleCollectedAt = nowUTC,
+            labId = null,
         )
 
         (instance.pollServer(raTest) as RACoronaTest).sampleCollectedAt shouldBe nowUTC
@@ -171,6 +174,7 @@ class RAProcessorTest : BaseTest() {
             testResultResponse = CoronaTestResultResponse(
                 coronaTestResult = PCR_OR_RAT_PENDING,
                 sampleCollectedAt = null,
+                labId = null,
             ),
         )
         coEvery { submissionService.registerTest(any()) } answers { registrationData }
@@ -187,6 +191,7 @@ class RAProcessorTest : BaseTest() {
                 testResultResponse = CoronaTestResultResponse(
                     coronaTestResult = it,
                     sampleCollectedAt = null,
+                    labId = null,
                 )
             )
             when (it) {
@@ -212,6 +217,7 @@ class RAProcessorTest : BaseTest() {
             CoronaTestResultResponse(
                 coronaTestResult = pollResult,
                 sampleCollectedAt = null,
+                labId = null,
             )
         }
 
@@ -245,6 +251,7 @@ class RAProcessorTest : BaseTest() {
             CoronaTestResultResponse(
                 coronaTestResult = RAT_POSITIVE,
                 sampleCollectedAt = null,
+                labId = null,
             )
         }
 
@@ -312,6 +319,7 @@ class RAProcessorTest : BaseTest() {
             testResultResponse = CoronaTestResultResponse(
                 coronaTestResult = PCR_OR_RAT_PENDING,
                 sampleCollectedAt = null,
+                labId = null,
             )
         )
         coEvery { submissionService.registerTest(any()) } answers { registrationData }
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/http/playbook/DefaultPlaybookTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/http/playbook/DefaultPlaybookTest.kt
index dd870ce11..2ed483adc 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/http/playbook/DefaultPlaybookTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/http/playbook/DefaultPlaybookTest.kt
@@ -46,7 +46,8 @@ class DefaultPlaybookTest : BaseTest() {
         coEvery { verificationServer.retrieveRegistrationToken(any()) } returns "token"
         coEvery { verificationServer.pollTestResult(any()) } returns CoronaTestResultResponse(
             coronaTestResult = CoronaTestResult.PCR_OR_RAT_PENDING,
-            sampleCollectedAt = null
+            sampleCollectedAt = null,
+            labId = null,
         )
         coEvery { verificationServer.retrieveTanFake() } returns mockk()
         coEvery { verificationServer.retrieveTan(any()) } returns "tan"
@@ -214,7 +215,8 @@ class DefaultPlaybookTest : BaseTest() {
         val expectedResult = CoronaTestResult.PCR_OR_RAT_PENDING
         coEvery { verificationServer.pollTestResult(expectedToken) } returns CoronaTestResultResponse(
             coronaTestResult = expectedResult,
-            sampleCollectedAt = null
+            sampleCollectedAt = null,
+            labId = null,
         )
         coEvery { submissionServer.submitFakePayload() } throws TestException()
 
@@ -224,7 +226,8 @@ class DefaultPlaybookTest : BaseTest() {
         registrationToken shouldBe expectedToken
         testResult shouldBe CoronaTestResultResponse(
             coronaTestResult = expectedResult,
-            sampleCollectedAt = null
+            sampleCollectedAt = null,
+            labId = null,
         )
     }
 
diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/submission/CoronaTestServiceTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/submission/CoronaTestServiceTest.kt
index b75849bb4..cc973f05d 100644
--- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/submission/CoronaTestServiceTest.kt
+++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/submission/CoronaTestServiceTest.kt
@@ -45,7 +45,8 @@ class CoronaTestServiceTest : BaseTest() {
             registrationToken = registrationToken,
             testResultResponse = CoronaTestResultResponse(
                 coronaTestResult = CoronaTestResult.PCR_OR_RAT_PENDING,
-                sampleCollectedAt = null
+                sampleCollectedAt = null,
+                labId = null,
             )
         )
     }
@@ -85,13 +86,15 @@ class CoronaTestServiceTest : BaseTest() {
     fun requestTestResultSucceeds() {
         coEvery { mockPlaybook.testResult(registrationToken) } returns CoronaTestResultResponse(
             coronaTestResult = CoronaTestResult.PCR_NEGATIVE,
-            sampleCollectedAt = null
+            sampleCollectedAt = null,
+            labId = null,
         )
 
         runBlocking {
             createInstance().checkTestResult(registrationToken) shouldBe CoronaTestResultResponse(
                 coronaTestResult = CoronaTestResult.PCR_NEGATIVE,
                 sampleCollectedAt = null,
+                labId = null,
             )
         }
         coVerify(exactly = 1) {
-- 
GitLab