From 51856cf9cf7beacbf13d88b8675a1ae0f15dd022 Mon Sep 17 00:00:00 2001 From: Milen Marinov Date: Tue, 9 Jul 2024 14:06:48 +0300 Subject: [PATCH 1/2] [MS-488] Add verificationSuccess field to AppMatchResult --- .../response/CreateVerifyResponseUseCase.kt | 23 ++- .../CreateVerifyResponseUseCaseTest.kt | 156 +++++++++++++++++- .../config/store/models/FaceConfiguration.kt | 3 + .../data/responses/AppMatchResult.kt | 17 +- .../data/responses/AppMatchResultTest.kt | 40 +++++ 5 files changed, 222 insertions(+), 17 deletions(-) diff --git a/feature/orchestrator/src/main/java/com/simprints/feature/orchestrator/usecases/response/CreateVerifyResponseUseCase.kt b/feature/orchestrator/src/main/java/com/simprints/feature/orchestrator/usecases/response/CreateVerifyResponseUseCase.kt index 400d63c408..7a097cf3bd 100644 --- a/feature/orchestrator/src/main/java/com/simprints/feature/orchestrator/usecases/response/CreateVerifyResponseUseCase.kt +++ b/feature/orchestrator/src/main/java/com/simprints/feature/orchestrator/usecases/response/CreateVerifyResponseUseCase.kt @@ -30,11 +30,17 @@ internal class CreateVerifyResponseUseCase @Inject constructor() { .lastOrNull()?.let { fingerprintMatchResult -> projectConfiguration.fingerprint ?.getSdkConfiguration(fingerprintMatchResult.sdk) - ?.decisionPolicy - ?.let { decisionPolicy -> + ?.let { sdkConfiguration -> fingerprintMatchResult.results .maxByOrNull { it.confidence } - ?.let { AppMatchResult(it.subjectId, it.confidence, decisionPolicy) } + ?.let { + AppMatchResult( + guid = it.subjectId, + confidenceScore = it.confidence, + decisionPolicy = sdkConfiguration.decisionPolicy, + verificationMatchThreshold = sdkConfiguration.verificationMatchThreshold + ) + } } } @@ -43,10 +49,17 @@ internal class CreateVerifyResponseUseCase @Inject constructor() { results: List, ) = results.filterIsInstance() .lastOrNull()?.let { faceMatchResult -> - projectConfiguration.face?.decisionPolicy?.let { decisionPolicy -> + projectConfiguration.face?.let { faceConfiguration -> faceMatchResult.results .maxByOrNull { it.confidence } - ?.let { AppMatchResult(it.subjectId, it.confidence, decisionPolicy) } + ?.let { + AppMatchResult( + guid = it.subjectId, + confidenceScore = it.confidence, + decisionPolicy = faceConfiguration.decisionPolicy, + verificationMatchThreshold = faceConfiguration.verificationMatchThreshold + ) + } } } } diff --git a/feature/orchestrator/src/test/java/com/simprints/feature/orchestrator/usecases/response/CreateVerifyResponseUseCaseTest.kt b/feature/orchestrator/src/test/java/com/simprints/feature/orchestrator/usecases/response/CreateVerifyResponseUseCaseTest.kt index 9218259363..74e11c5257 100644 --- a/feature/orchestrator/src/test/java/com/simprints/feature/orchestrator/usecases/response/CreateVerifyResponseUseCaseTest.kt +++ b/feature/orchestrator/src/test/java/com/simprints/feature/orchestrator/usecases/response/CreateVerifyResponseUseCaseTest.kt @@ -25,8 +25,8 @@ class CreateVerifyResponseUseCaseTest { fun `Returns error if no decision policy`() { val result = useCase( mockk { - every { face?.decisionPolicy } returns null - every { fingerprint?.getSdkConfiguration((any()))?.decisionPolicy } returns null + every { face } returns null + every { fingerprint?.getSdkConfiguration((any())) } returns null }, results = listOf(createFaceMatchResult(10f, 20f, 30f)) ) @@ -35,11 +35,13 @@ class CreateVerifyResponseUseCaseTest { } @Test - fun `Returns face identifications with highest score`() { + fun `Returns face matches with highest score`() { val result = useCase( mockk { every { face?.decisionPolicy } returns DecisionPolicy(10, 20, 30) every { fingerprint?.getSdkConfiguration((any()))?.decisionPolicy } returns null + every { face?.verificationMatchThreshold } returns null + every { fingerprint?.getSdkConfiguration((any()))?.verificationMatchThreshold } returns null }, results = listOf(createFaceMatchResult(10f, 50f, 100f)) ) @@ -48,7 +50,7 @@ class CreateVerifyResponseUseCaseTest { } @Test - fun `Returns fingerprint identifications with highest score`() { + fun `Returns fingerprint matches with highest score`() { val result = useCase( mockk { every { face?.decisionPolicy } returns null @@ -57,6 +59,7 @@ class CreateVerifyResponseUseCaseTest { 20, 30 ) + every { fingerprint?.getSdkConfiguration((any()))?.verificationMatchThreshold } returns 50f }, results = listOf(createFingerprintMatchResult(10f, 50f, 100f)) ) @@ -65,7 +68,7 @@ class CreateVerifyResponseUseCaseTest { } @Test - fun `Returns identifications with highest face match score`() { + fun `Returns matches with highest face match score`() { val result = useCase( mockk { every { face?.decisionPolicy } returns DecisionPolicy(10, 20, 30) @@ -74,6 +77,8 @@ class CreateVerifyResponseUseCaseTest { 20, 30 ) + every { face?.verificationMatchThreshold } returns 50f + every { fingerprint?.getSdkConfiguration((any()))?.verificationMatchThreshold } returns 50f }, results = listOf( createFaceMatchResult(10f, 50f, 105f), @@ -84,9 +89,8 @@ class CreateVerifyResponseUseCaseTest { assertThat((result as AppVerifyResponse).matchResult.confidenceScore).isEqualTo(105) } - @Test - fun `Returns identifications with highest fingerprint match score`() { + fun `Returns matches with highest fingerprint match score`() { val result = useCase( mockk { every { face?.decisionPolicy } returns DecisionPolicy(10, 20, 30) @@ -95,6 +99,8 @@ class CreateVerifyResponseUseCaseTest { 20, 30 ) + every { face?.verificationMatchThreshold } returns 50f + every { fingerprint?.getSdkConfiguration((any()))?.verificationMatchThreshold } returns 50f }, results = listOf( createFaceMatchResult(10f, 50f, 100f), @@ -105,6 +111,142 @@ class CreateVerifyResponseUseCaseTest { assertThat((result as AppVerifyResponse).matchResult.confidenceScore).isEqualTo(105) } + @Test + fun `When face verificationMatchThreshold is null - verificationSuccess is null`() { + val result = useCase( + mockk { + every { face?.decisionPolicy } returns DecisionPolicy(10, 20, 30) + every { face?.verificationMatchThreshold } returns null + }, + results = listOf( + createFaceMatchResult(10f, 50f, 100f), + ) + ) + + assertThat((result as AppVerifyResponse).matchResult.verificationSuccess).isNull() + } + + @Test + fun `When fingerprint verificationMatchThreshold is null - verificationSuccess is null`() { + val result = useCase( + mockk { + every { fingerprint?.getSdkConfiguration((any()))?.decisionPolicy } returns DecisionPolicy( + 10, + 20, + 30 + ) + every { fingerprint?.getSdkConfiguration((any()))?.verificationMatchThreshold } returns null + }, + results = listOf( + createFingerprintMatchResult(10f, 50f, 100f), + ) + ) + + assertThat((result as AppVerifyResponse).matchResult.verificationSuccess).isNull() + } + + @Test + fun `When face match score is above verificationMatchThreshold - verificationSuccess is true`() { + val result = useCase( + mockk { + every { face?.decisionPolicy } returns DecisionPolicy(10, 20, 30) + every { face?.verificationMatchThreshold } returns 50f + }, + results = listOf( + createFaceMatchResult(51f), + ) + ) + + assertThat((result as AppVerifyResponse).matchResult.verificationSuccess).isEqualTo(true) + } + + @Test + fun `When fingerprint match score is above verificationMatchThreshold - verificationSuccess is true`() { + val result = useCase( + mockk { + every { fingerprint?.getSdkConfiguration((any()))?.decisionPolicy } returns DecisionPolicy( + 10, + 20, + 30 + ) + every { fingerprint?.getSdkConfiguration((any()))?.verificationMatchThreshold } returns 50f + }, + results = listOf( + createFingerprintMatchResult(51f), + ) + ) + + assertThat((result as AppVerifyResponse).matchResult.verificationSuccess).isEqualTo(true) + } + + @Test + fun `When face match score is equal to verificationMatchThreshold - verificationSuccess is true`() { + val result = useCase( + mockk { + every { face?.decisionPolicy } returns DecisionPolicy(10, 20, 30) + every { face?.verificationMatchThreshold } returns 50f + }, + results = listOf( + createFaceMatchResult(50f), + ) + ) + + assertThat((result as AppVerifyResponse).matchResult.verificationSuccess).isEqualTo(true) + } + + @Test + fun `When fingerprint match score is equal to verificationMatchThreshold - verificationSuccess is true`() { + val result = useCase( + mockk { + every { fingerprint?.getSdkConfiguration((any()))?.decisionPolicy } returns DecisionPolicy( + 10, + 20, + 30 + ) + every { fingerprint?.getSdkConfiguration((any()))?.verificationMatchThreshold } returns 50f + }, + results = listOf( + createFingerprintMatchResult(50f), + ) + ) + + assertThat((result as AppVerifyResponse).matchResult.verificationSuccess).isEqualTo(true) + } + + @Test + fun `When face match score is below verificationMatchThreshold - verificationSuccess is false`() { + val result = useCase( + mockk { + every { face?.decisionPolicy } returns DecisionPolicy(10, 20, 30) + every { face?.verificationMatchThreshold } returns 50f + }, + results = listOf( + createFaceMatchResult(49f), + ) + ) + + assertThat((result as AppVerifyResponse).matchResult.verificationSuccess).isEqualTo(false) + } + + @Test + fun `When fingerprint match score is below verificationMatchThreshold - verificationSuccess is false`() { + val result = useCase( + mockk { + every { fingerprint?.getSdkConfiguration((any()))?.decisionPolicy } returns DecisionPolicy( + 10, + 20, + 30 + ) + every { fingerprint?.getSdkConfiguration((any()))?.verificationMatchThreshold } returns 50f + }, + results = listOf( + createFingerprintMatchResult(49f), + ) + ) + + assertThat((result as AppVerifyResponse).matchResult.verificationSuccess).isEqualTo(false) + } + private fun createFingerprintMatchResult(vararg confidences: Float): Serializable = FingerprintMatchResult( confidences.map { FingerprintMatchResult.Item(subjectId = "1", confidence = it) }, mockk(), diff --git a/infra/config-store/src/main/java/com/simprints/infra/config/store/models/FaceConfiguration.kt b/infra/config-store/src/main/java/com/simprints/infra/config/store/models/FaceConfiguration.kt index 932af9fa07..87dc606a34 100644 --- a/infra/config-store/src/main/java/com/simprints/infra/config/store/models/FaceConfiguration.kt +++ b/infra/config-store/src/main/java/com/simprints/infra/config/store/models/FaceConfiguration.kt @@ -17,6 +17,9 @@ data class FaceConfiguration( val decisionPolicy: DecisionPolicy get() = rankOne?.decisionPolicy!! + val verificationMatchThreshold: Float? + get() = rankOne?.verificationMatchThreshold + data class FaceSdkConfiguration( val nbOfImagesToCapture: Int, val qualityThreshold: Int, diff --git a/infra/orchestrator-data/src/main/java/com/simprints/infra/orchestration/data/responses/AppMatchResult.kt b/infra/orchestrator-data/src/main/java/com/simprints/infra/orchestration/data/responses/AppMatchResult.kt index 4e096a47d1..f02b2e73e8 100644 --- a/infra/orchestrator-data/src/main/java/com/simprints/infra/orchestration/data/responses/AppMatchResult.kt +++ b/infra/orchestrator-data/src/main/java/com/simprints/infra/orchestration/data/responses/AppMatchResult.kt @@ -2,7 +2,6 @@ package com.simprints.infra.orchestration.data.responses import android.os.Parcelable import androidx.annotation.Keep -import com.simprints.core.ExcludedFromGeneratedTestCoverageReports import com.simprints.core.domain.response.AppMatchConfidence import com.simprints.core.domain.response.AppResponseTier import com.simprints.infra.config.store.models.DecisionPolicy @@ -15,17 +14,20 @@ data class AppMatchResult( val confidenceScore: Int, val tier: AppResponseTier, val matchConfidence: AppMatchConfidence, + val verificationSuccess: Boolean? = null, ) : Parcelable { constructor( guid: String, confidenceScore: Float, decisionPolicy: DecisionPolicy, + verificationMatchThreshold: Float? = null ) : this( - guid, - confidenceScore.toInt(), - computeTier(confidenceScore), - computeMatchConfidence(confidenceScore.toInt(), decisionPolicy) + guid = guid, + confidenceScore = confidenceScore.toInt(), + tier = computeTier(confidenceScore), + matchConfidence = computeMatchConfidence(confidenceScore.toInt(), decisionPolicy), + verificationSuccess = computeVerificationSuccess(confidenceScore.toInt(), verificationMatchThreshold), ) companion object { @@ -44,5 +46,10 @@ data class AppMatchResult( confidenceScore < policy.high -> AppMatchConfidence.MEDIUM else -> AppMatchConfidence.HIGH } + + fun computeVerificationSuccess(confidenceScore: Int, verificationMatchThreshold: Float?) = when { + verificationMatchThreshold == null -> null + else -> confidenceScore >= verificationMatchThreshold + } } } diff --git a/infra/orchestrator-data/src/test/java/com/simprints/infra/orchestration/data/responses/AppMatchResultTest.kt b/infra/orchestrator-data/src/test/java/com/simprints/infra/orchestration/data/responses/AppMatchResultTest.kt index ed6cd59e5a..74512309e2 100644 --- a/infra/orchestrator-data/src/test/java/com/simprints/infra/orchestration/data/responses/AppMatchResultTest.kt +++ b/infra/orchestrator-data/src/test/java/com/simprints/infra/orchestration/data/responses/AppMatchResultTest.kt @@ -62,4 +62,44 @@ class AppMatchResultTest { assertThat(AppMatchResult.computeMatchConfidence(score, policy)).isEqualTo(expected) } } + + @Test + fun `test computeVerificationSuccess with verificationMatchThreshold present`() { + mapOf( + 0 to false, + 10 to false, + 20 to false, + 30 to false, + 35 to false, + 40 to true, + 50 to true, + 60 to true, + 70 to true, + 75 to true, + 80 to true, + 90 to true, + ).forEach { (score, expected) -> + assertThat(AppMatchResult.computeVerificationSuccess(score, 40.0f)).isEqualTo(expected) + } + } + + @Test + fun `test computeVerificationSuccess with verificationMatchThreshold null`() { + mapOf( + 0 to null, + 10 to null, + 20 to null, + 30 to null, + 35 to null, + 40 to null, + 50 to null, + 60 to null, + 70 to null, + 75 to null, + 80 to null, + 90 to null, + ).forEach { (score, expected) -> + assertThat(AppMatchResult.computeVerificationSuccess(score, null)).isEqualTo(expected) + } + } } From af31610a5cfda456eced67431d5c95aa0d763453 Mon Sep 17 00:00:00 2001 From: Milen Marinov Date: Tue, 9 Jul 2024 14:57:36 +0300 Subject: [PATCH 2/2] [MS-488] Add verificationSuccess to VERIFY response in all 3 mappers --- .../response/CommCareResponseMapper.kt | 6 +- .../response/LibSimprintsResponseMapper.kt | 6 +- .../mappers/response/OdkResponseMapper.kt | 6 +- .../feature/clientapi/models/Constants.kt | 2 + .../response/CommCareResponseMapperTest.kt | 48 ++++++++++++++- .../LibSimprintsResponseMapperTest.kt | 58 ++++++++++++++++++- .../mappers/response/OdkResponseMapperTest.kt | 48 ++++++++++++++- gradle/libs.versions.toml | 2 +- 8 files changed, 169 insertions(+), 7 deletions(-) diff --git a/feature/client-api/src/main/java/com/simprints/feature/clientapi/mappers/response/CommCareResponseMapper.kt b/feature/client-api/src/main/java/com/simprints/feature/clientapi/mappers/response/CommCareResponseMapper.kt index ee5a5c08e5..d5f778998c 100644 --- a/feature/client-api/src/main/java/com/simprints/feature/clientapi/mappers/response/CommCareResponseMapper.kt +++ b/feature/client-api/src/main/java/com/simprints/feature/clientapi/mappers/response/CommCareResponseMapper.kt @@ -43,7 +43,11 @@ internal class CommCareResponseMapper @Inject constructor() { CommCareConstants.VERIFICATION_GUID_KEY to response.matchResult.guid, CommCareConstants.VERIFICATION_CONFIDENCE_KEY to response.matchResult.confidenceScore.toString(), CommCareConstants.VERIFICATION_TIER_KEY to response.matchResult.tier.name, - ).toCommCareBundle() + ).also { + response.matchResult.verificationSuccess?.let { verificationSuccess -> + it.putString(CommCareConstants.VERIFICATION_SUCCESS_KEY, verificationSuccess.toString()) + } + }.toCommCareBundle() is ActionResponse.ExitFormActionResponse -> bundleOf( CommCareConstants.SIMPRINTS_SESSION_ID to response.sessionId, diff --git a/feature/client-api/src/main/java/com/simprints/feature/clientapi/mappers/response/LibSimprintsResponseMapper.kt b/feature/client-api/src/main/java/com/simprints/feature/clientapi/mappers/response/LibSimprintsResponseMapper.kt index 2ae23600dd..cb369c7251 100644 --- a/feature/client-api/src/main/java/com/simprints/feature/clientapi/mappers/response/LibSimprintsResponseMapper.kt +++ b/feature/client-api/src/main/java/com/simprints/feature/clientapi/mappers/response/LibSimprintsResponseMapper.kt @@ -45,7 +45,11 @@ internal class LibSimprintsResponseMapper @Inject constructor() { Tier.valueOf(response.matchResult.tier.name), response.matchResult.guid, ), - ) + ).also { + response.matchResult.verificationSuccess?.let { verificationSuccess -> + it.putBoolean(Constants.SIMPRINTS_VERIFICATION_SUCCESS, verificationSuccess) + } + } is ActionResponse.ExitFormActionResponse -> bundleOf( Constants.SIMPRINTS_SESSION_ID to response.sessionId, diff --git a/feature/client-api/src/main/java/com/simprints/feature/clientapi/mappers/response/OdkResponseMapper.kt b/feature/client-api/src/main/java/com/simprints/feature/clientapi/mappers/response/OdkResponseMapper.kt index dd63a84376..71326c9188 100644 --- a/feature/client-api/src/main/java/com/simprints/feature/clientapi/mappers/response/OdkResponseMapper.kt +++ b/feature/client-api/src/main/java/com/simprints/feature/clientapi/mappers/response/OdkResponseMapper.kt @@ -36,7 +36,11 @@ internal class OdkResponseMapper @Inject constructor() { OdkConstants.ODK_GUIDS_KEY to response.matchResult.guid, OdkConstants.ODK_CONFIDENCES_KEY to response.matchResult.confidenceScore.toString(), OdkConstants.ODK_TIERS_KEY to response.matchResult.tier.name, - ).addFlowCompletedCheckBasedOnAction(response.actionIdentifier, true) + ).also { + response.matchResult.verificationSuccess?.let { verificationSuccess -> + it.putBoolean(OdkConstants.ODK_VERIFICATION_SUCCESS_KEY, verificationSuccess) + } + }.addFlowCompletedCheckBasedOnAction(response.actionIdentifier, true) is ActionResponse.ExitFormActionResponse -> bundleOf( OdkConstants.ODK_SESSION_ID to response.sessionId, diff --git a/feature/client-api/src/main/java/com/simprints/feature/clientapi/models/Constants.kt b/feature/client-api/src/main/java/com/simprints/feature/clientapi/models/Constants.kt index 88cbbe2028..c68d611b91 100644 --- a/feature/client-api/src/main/java/com/simprints/feature/clientapi/models/Constants.kt +++ b/feature/client-api/src/main/java/com/simprints/feature/clientapi/models/Constants.kt @@ -13,6 +13,7 @@ internal object OdkConstants { const val ODK_BIOMETRICS_COMPLETE_CHECK_KEY = "odk-biometrics-complete" const val ODK_CONFIDENCES_KEY = "odk-confidences" const val ODK_TIERS_KEY = "odk-tiers" + const val ODK_VERIFICATION_SUCCESS_KEY = "odk-verification-success" const val ODK_SESSION_ID = "odk-session-id" const val ODK_EXIT_REASON = "odk-exit-reason" const val ODK_EXIT_EXTRA = "odk-exit-extra" @@ -58,6 +59,7 @@ internal object CommCareConstants { const val VERIFICATION_CONFIDENCE_KEY = "confidence" const val VERIFICATION_TIER_KEY = "tier" const val VERIFICATION_GUID_KEY = "guid" + const val VERIFICATION_SUCCESS_KEY = "verificationSuccess" const val EXIT_REASON = "exitReason" const val EXIT_EXTRA = "exitExtra" const val SIMPRINTS_SESSION_ID = "sessionId" diff --git a/feature/client-api/src/test/java/com/simprints/feature/clientapi/mappers/response/CommCareResponseMapperTest.kt b/feature/client-api/src/test/java/com/simprints/feature/clientapi/mappers/response/CommCareResponseMapperTest.kt index 817bab1115..22a3327e22 100644 --- a/feature/client-api/src/test/java/com/simprints/feature/clientapi/mappers/response/CommCareResponseMapperTest.kt +++ b/feature/client-api/src/test/java/com/simprints/feature/clientapi/mappers/response/CommCareResponseMapperTest.kt @@ -85,7 +85,7 @@ class CommCareResponseMapperTest { } @Test - fun `correctly maps verify response`() { + fun `correctly maps verify response with null verificationSuccess`() { val extras = mapper(ActionResponse.VerifyActionResponse( actionIdentifier = VerifyActionFactory.getIdentifier(), sessionId = "sessionId", @@ -94,6 +94,7 @@ class CommCareResponseMapperTest { confidenceScore = 50, tier = AppResponseTier.TIER_2, matchConfidence = AppMatchConfidence.HIGH, + verificationSuccess = null, ), )).getBundle(CommCareConstants.COMMCARE_BUNDLE_KEY) ?: bundleOf() @@ -102,6 +103,51 @@ class CommCareResponseMapperTest { assertThat(extras.getString(CommCareConstants.VERIFICATION_CONFIDENCE_KEY)).isEqualTo("50") assertThat(extras.getString(CommCareConstants.VERIFICATION_TIER_KEY)).isEqualTo("TIER_2") assertThat(extras.getString(CommCareConstants.BIOMETRICS_COMPLETE_CHECK_KEY)).isEqualTo("true") + assertThat(extras.getString(CommCareConstants.VERIFICATION_SUCCESS_KEY)).isNull() + } + + @Test + fun `correctly maps verify response with verificationSuccess = false`() { + val extras = mapper(ActionResponse.VerifyActionResponse( + actionIdentifier = VerifyActionFactory.getIdentifier(), + sessionId = "sessionId", + matchResult = AppMatchResult( + guid = "guid", + confidenceScore = 50, + tier = AppResponseTier.TIER_2, + matchConfidence = AppMatchConfidence.HIGH, + verificationSuccess = false, + ), + )).getBundle(CommCareConstants.COMMCARE_BUNDLE_KEY) ?: bundleOf() + + assertThat(extras.getString(CommCareConstants.SIMPRINTS_SESSION_ID)).isEqualTo("sessionId") + assertThat(extras.getString(CommCareConstants.VERIFICATION_GUID_KEY)).isEqualTo("guid") + assertThat(extras.getString(CommCareConstants.VERIFICATION_CONFIDENCE_KEY)).isEqualTo("50") + assertThat(extras.getString(CommCareConstants.VERIFICATION_TIER_KEY)).isEqualTo("TIER_2") + assertThat(extras.getString(CommCareConstants.BIOMETRICS_COMPLETE_CHECK_KEY)).isEqualTo("true") + assertThat(extras.getString(CommCareConstants.VERIFICATION_SUCCESS_KEY)).isEqualTo("false") + } + + @Test + fun `correctly maps verify response with verificationSuccess = true`() { + val extras = mapper(ActionResponse.VerifyActionResponse( + actionIdentifier = VerifyActionFactory.getIdentifier(), + sessionId = "sessionId", + matchResult = AppMatchResult( + guid = "guid", + confidenceScore = 50, + tier = AppResponseTier.TIER_2, + matchConfidence = AppMatchConfidence.HIGH, + verificationSuccess = true, + ), + )).getBundle(CommCareConstants.COMMCARE_BUNDLE_KEY) ?: bundleOf() + + assertThat(extras.getString(CommCareConstants.SIMPRINTS_SESSION_ID)).isEqualTo("sessionId") + assertThat(extras.getString(CommCareConstants.VERIFICATION_GUID_KEY)).isEqualTo("guid") + assertThat(extras.getString(CommCareConstants.VERIFICATION_CONFIDENCE_KEY)).isEqualTo("50") + assertThat(extras.getString(CommCareConstants.VERIFICATION_TIER_KEY)).isEqualTo("TIER_2") + assertThat(extras.getString(CommCareConstants.BIOMETRICS_COMPLETE_CHECK_KEY)).isEqualTo("true") + assertThat(extras.getString(CommCareConstants.VERIFICATION_SUCCESS_KEY)).isEqualTo("true") } @Test diff --git a/feature/client-api/src/test/java/com/simprints/feature/clientapi/mappers/response/LibSimprintsResponseMapperTest.kt b/feature/client-api/src/test/java/com/simprints/feature/clientapi/mappers/response/LibSimprintsResponseMapperTest.kt index a57d0c8cf9..8eb65034c8 100644 --- a/feature/client-api/src/test/java/com/simprints/feature/clientapi/mappers/response/LibSimprintsResponseMapperTest.kt +++ b/feature/client-api/src/test/java/com/simprints/feature/clientapi/mappers/response/LibSimprintsResponseMapperTest.kt @@ -89,7 +89,7 @@ class LibSimprintsResponseMapperTest { } @Test - fun `correctly maps verify response`() { + fun `correctly maps verify response with null verificationSuccess`() { val extras = mapper( ActionResponse.VerifyActionResponse( actionIdentifier = VerifyActionFactory.getIdentifier(), @@ -99,6 +99,7 @@ class LibSimprintsResponseMapperTest { confidenceScore = 50, tier = AppResponseTier.TIER_2, matchConfidence = AppMatchConfidence.HIGH, + verificationSuccess = null, ), ) ) @@ -111,6 +112,61 @@ class LibSimprintsResponseMapperTest { assertThat(extraVerification?.tier).isEqualTo(Tier.TIER_2) assertThat(extraVerification?.confidence).isEqualTo(50) assertThat(extras.getBoolean(Constants.SIMPRINTS_BIOMETRICS_COMPLETE_CHECK)).isEqualTo(true) + assertThat(extras.getBoolean(Constants.SIMPRINTS_VERIFICATION_SUCCESS)).isFalse() // Default value + } + + @Test + fun `correctly maps verify response with verificationSuccess = false`() { + val extras = mapper( + ActionResponse.VerifyActionResponse( + actionIdentifier = VerifyActionFactory.getIdentifier(), + sessionId = "sessionId", + matchResult = AppMatchResult( + guid = "guid", + confidenceScore = 50, + tier = AppResponseTier.TIER_2, + matchConfidence = AppMatchConfidence.HIGH, + verificationSuccess = false, + ), + ) + ) + + // Verification does not implement equals, so we have to check each field individually + val extraVerification = extras.getParcelable(Constants.SIMPRINTS_VERIFICATION) + + assertThat(extras.getString(Constants.SIMPRINTS_SESSION_ID)).isEqualTo("sessionId") + assertThat(extraVerification?.guid).isEqualTo("guid") + assertThat(extraVerification?.tier).isEqualTo(Tier.TIER_2) + assertThat(extraVerification?.confidence).isEqualTo(50) + assertThat(extras.getBoolean(Constants.SIMPRINTS_BIOMETRICS_COMPLETE_CHECK)).isEqualTo(true) + assertThat(extras.getBoolean(Constants.SIMPRINTS_VERIFICATION_SUCCESS)).isEqualTo(false) + } + + @Test + fun `correctly maps verify response with verificationSuccess = true`() { + val extras = mapper( + ActionResponse.VerifyActionResponse( + actionIdentifier = VerifyActionFactory.getIdentifier(), + sessionId = "sessionId", + matchResult = AppMatchResult( + guid = "guid", + confidenceScore = 50, + tier = AppResponseTier.TIER_2, + matchConfidence = AppMatchConfidence.HIGH, + verificationSuccess = true, + ), + ) + ) + + // Verification does not implement equals, so we have to check each field individually + val extraVerification = extras.getParcelable(Constants.SIMPRINTS_VERIFICATION) + + assertThat(extras.getString(Constants.SIMPRINTS_SESSION_ID)).isEqualTo("sessionId") + assertThat(extraVerification?.guid).isEqualTo("guid") + assertThat(extraVerification?.tier).isEqualTo(Tier.TIER_2) + assertThat(extraVerification?.confidence).isEqualTo(50) + assertThat(extras.getBoolean(Constants.SIMPRINTS_BIOMETRICS_COMPLETE_CHECK)).isEqualTo(true) + assertThat(extras.getBoolean(Constants.SIMPRINTS_VERIFICATION_SUCCESS)).isEqualTo(true) } @Test diff --git a/feature/client-api/src/test/java/com/simprints/feature/clientapi/mappers/response/OdkResponseMapperTest.kt b/feature/client-api/src/test/java/com/simprints/feature/clientapi/mappers/response/OdkResponseMapperTest.kt index fe0fa8d84b..289fac2560 100644 --- a/feature/client-api/src/test/java/com/simprints/feature/clientapi/mappers/response/OdkResponseMapperTest.kt +++ b/feature/client-api/src/test/java/com/simprints/feature/clientapi/mappers/response/OdkResponseMapperTest.kt @@ -89,7 +89,7 @@ class OdkResponseMapperTest { } @Test - fun `correctly maps verify response`() { + fun `correctly maps verify response with null verificationSuccess`() { val extras = mapper(ActionResponse.VerifyActionResponse( actionIdentifier = VerifyActionFactory.getIdentifier(), sessionId = "sessionId", @@ -98,6 +98,7 @@ class OdkResponseMapperTest { confidenceScore = 50, tier = AppResponseTier.TIER_2, matchConfidence = AppMatchConfidence.HIGH, + verificationSuccess = null, ), )) @@ -106,6 +107,51 @@ class OdkResponseMapperTest { assertThat(extras.getString(OdkConstants.ODK_CONFIDENCES_KEY)).isEqualTo("50") assertThat(extras.getString(OdkConstants.ODK_TIERS_KEY)).isEqualTo("TIER_2") assertThat(extras.getBoolean(OdkConstants.ODK_VERIFY_BIOMETRICS_COMPLETE)).isEqualTo(true) + assertThat(extras.getBoolean(OdkConstants.ODK_VERIFICATION_SUCCESS_KEY)).isEqualTo(false) // default value + } + + @Test + fun `correctly maps verify response with verificationSuccess = false`() { + val extras = mapper(ActionResponse.VerifyActionResponse( + actionIdentifier = VerifyActionFactory.getIdentifier(), + sessionId = "sessionId", + matchResult = AppMatchResult( + guid = "guid", + confidenceScore = 50, + tier = AppResponseTier.TIER_2, + matchConfidence = AppMatchConfidence.HIGH, + verificationSuccess = false, + ), + )) + + assertThat(extras.getString(OdkConstants.ODK_SESSION_ID)).isEqualTo("sessionId") + assertThat(extras.getString(OdkConstants.ODK_GUIDS_KEY)).isEqualTo("guid") + assertThat(extras.getString(OdkConstants.ODK_CONFIDENCES_KEY)).isEqualTo("50") + assertThat(extras.getString(OdkConstants.ODK_TIERS_KEY)).isEqualTo("TIER_2") + assertThat(extras.getBoolean(OdkConstants.ODK_VERIFY_BIOMETRICS_COMPLETE)).isEqualTo(true) + assertThat(extras.getBoolean(OdkConstants.ODK_VERIFICATION_SUCCESS_KEY)).isEqualTo(false) + } + + @Test + fun `correctly maps verify response with verificationSuccess = true`() { + val extras = mapper(ActionResponse.VerifyActionResponse( + actionIdentifier = VerifyActionFactory.getIdentifier(), + sessionId = "sessionId", + matchResult = AppMatchResult( + guid = "guid", + confidenceScore = 50, + tier = AppResponseTier.TIER_2, + matchConfidence = AppMatchConfidence.HIGH, + verificationSuccess = true, + ), + )) + + assertThat(extras.getString(OdkConstants.ODK_SESSION_ID)).isEqualTo("sessionId") + assertThat(extras.getString(OdkConstants.ODK_GUIDS_KEY)).isEqualTo("guid") + assertThat(extras.getString(OdkConstants.ODK_CONFIDENCES_KEY)).isEqualTo("50") + assertThat(extras.getString(OdkConstants.ODK_TIERS_KEY)).isEqualTo("TIER_2") + assertThat(extras.getBoolean(OdkConstants.ODK_VERIFY_BIOMETRICS_COMPLETE)).isEqualTo(true) + assertThat(extras.getBoolean(OdkConstants.ODK_VERIFICATION_SUCCESS_KEY)).isEqualTo(true) } @Test diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4785891012..c2a37aeac3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -66,7 +66,7 @@ protobuf_version = "4.26.1" circleImageView_version = "3.1.0" timber_version = "5.0.1" -libsimprints_version = "2024.2.0" +libsimprints_version = "2024.2.2" simmatcher_version = "1.2.0" roc_wrapper_version = "1.23" nec_version = "1.5.0"