From 512c01072182b6c2a9aa13cd3a84df6c275c509a Mon Sep 17 00:00:00 2001 From: Benjamin Mwalimu Date: Tue, 19 Nov 2024 02:57:59 +0300 Subject: [PATCH] Main | Performance improvements (#3586) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Test single transaction save for questionnaires * Caching questionnaires and their SM * spotless ran * Fetch search results in batches for when loading all * Fix infinite loop for mocks with FhirEngine#search in tests * [WIP] FhirEngine search integration tests * spotless ran * updated tests * WIP tests updated * resolved feedback * spotess ran * Upgrade FHIR SDK depenencies ⬆️ * Upragde SDC library * Replace JWT token parser library * Fix CQL Content Test * Fix unit tests ✅ * Refactor to remove Dispatch Provider * Fix unit test ✅ * Refactor Knowledge Manager Resources Persistance * Refactor CQL Content tests * Fix AppSettingModel unit tests ✅ * Refactor Cancel previous worflow to use native commands * Upgrade CI API level to 34 * Clean up Translations * Fix measure reporting * Fix Workflow Configuration * Fix QuestionnaireViewModel unit tests ✅ * Clean up WorkManager after running unit tests * Remove skyscreamer test dependency * Fix build 💚 * Clean up gradle dependencies configuration * Move measure reporting evaluation to BG thread * Fix MeasureReportRepositoryTest * Fix MeasureReportRepositoryTest * Fix MeasureReportViewModel unit tests ✅ Co-authored-by: Roy Munge * Fix Measure Reporting * Migrate Engine and Workflow libraries - Fix Measure reporting - Optimization PRs added * Refactor register filter with REL tags Signed-off-by: Elly Kitoto * Update default pageSize to 15 Signed-off-by: Elly Kitoto * Fix loading locations on map Signed-off-by: Elly Kitoto * Refactor data structure used on base resource search results Signed-off-by: Elly Kitoto * Process saveCredentials in the background * Refactor code Signed-off-by: Elly Kitoto * Delete unnecessary code Signed-off-by: Elly Kitoto * Refactor retrieving related resources Signed-off-by: Elly Kitoto * Optimize data structures and perform parallel processing Signed-off-by: Elly Kitoto * Use recent version of rules engine library Signed-off-by: Elly Kitoto * Refactor implementation for decoding image resources to bitmap Signed-off-by: Elly Kitoto * Fix related resource count on register Signed-off-by: Elly Kitoto * Fix loading related resources This fix ensures all the nested related resources are loaded too. Signed-off-by: Elly Kitoto * Batch related resource queries Signed-off-by: Elly Kitoto * Map resources to RepositoryResourceData with async map Signed-off-by: Elly Kitoto * Make infinite scroll the default register behavior Signed-off-by: Elly Kitoto * Disable automatic intialization of emoji2 A lot of memory was used in heap during the allocation. Emojis are not used in the app so intializing them automatically is unnecessary. Signed-off-by: Elly Kitoto * Run spotlessApply Signed-off-by: Elly Kitoto * Update tests for displaying images (#3506) * Refactor load images tests for different views. Signed-off-by: Lentumunai-Mark * Remove unutilized imports. Signed-off-by: Lentumunai-Mark * Run spotlessApply Signed-off-by: Elly Kitoto Signed-off-by: Lentumunai-Mark * Refactor load images tests for different views. Signed-off-by: Lentumunai-Mark * Resolve conflicts. Signed-off-by: Lentumunai-Mark --------- Signed-off-by: Lentumunai-Mark Signed-off-by: Elly Kitoto * Refactor navigation to GeowidgetLauncher workflow Signed-off-by: Elly Kitoto * Use dipatcher IO to handle questionnaire submission * Hotfix space_asterisk * Upgrade engine to v1.0.0-preview14.1-SNAPSHOT * Update infiniteScroll to not be default * Update sdk versions * Update integration Faker to fix error * Revert upgrade on workflow and knowledge libs * Upgrade FHIR SDK depenencies ⬆️ * Upragde SDC library * Replace JWT token parser library * Fix CQL Content Test * Fix unit tests ✅ * Refactor to remove Dispatch Provider * Fix unit test ✅ * Refactor Knowledge Manager Resources Persistance * Refactor CQL Content tests * Fix AppSettingModel unit tests ✅ * Refactor Cancel previous worflow to use native commands * Upgrade CI API level to 34 * Clean up Translations * Fix measure reporting * Fix Workflow Configuration * Fix QuestionnaireViewModel unit tests ✅ * Clean up WorkManager after running unit tests * Remove skyscreamer test dependency * Fix build 💚 * Clean up gradle dependencies configuration * Move measure reporting evaluation to BG thread * Fix MeasureReportRepositoryTest * Fix MeasureReportRepositoryTest * Fix MeasureReportViewModel unit tests ✅ Co-authored-by: Roy Munge * Fix Measure Reporting * Migrate Engine and Workflow libraries - Fix Measure reporting - Optimization PRs added * Update Workflow library - Fix build - Fix reporting NPE * Fix evaluate Population Measure * Update SDC snapshot to 14.1 * Remove unrecommended forced portrait format * Refactor from using deprecated KnowledgeManager methods loadResources * Clean up TOML catalog file * Revert Knowledge Manager and Workflow Library Upgrades * Display symbol instead of unicode * Refactor usage of FHIR JSONParser to support concurrency * Update FHIR SDK library versions * Geowidget configuration - Update Kujaku library version - Revert offline map downloads configuration via Kujaku network change receiver * Fix build 💚 - Fix code coverage reporting * SDK Engine to RC3 * Fix build * Fix failing ci tests * Update data-capture lib to v1.1.0-preview14-rc2-SNAPSHOT * Fix errors in tests * 🐛 Readd the eusm mg and bi flavour * 🔥 Remove unnecessary files * 🍻 Removing double flavour defination * Fix failing QuestionnaireViewModel tests * rename content cache to util.helper.CacheHelper * only 2 dots * remove unused cache var * use assign if null operator * format fixes * remove left over cache * update signature to require resourcetype * fix test call and remove dup test * refactor with setup and teardown * Revert "Caching questionnaires and their SM" This reverts commit 8129afdfcbfa09f4d9bf10d4441902751c1f50bb. * Clean up 🗑 * Clean up caching to reset to main brach state --------- Signed-off-by: Elly Kitoto Signed-off-by: Lentumunai-Mark Co-authored-by: L≡ZRS <12814349+LZRS@users.noreply.github.com> Co-authored-by: Aurangzaib Umer Co-authored-by: aurangzaibumer <35099184+aurangzaibumer@users.noreply.github.com> Co-authored-by: Martin Ndegwa Co-authored-by: Roy Munge Co-authored-by: Elly Kitoto Co-authored-by: Simon Njoroge Co-authored-by: Lentumunai Mark <90028422+Lentumunai-Mark@users.noreply.github.com> Co-authored-by: fikrimilano Co-authored-by: Simon Kiarie <696759+qiarie@users.noreply.github.com> Co-authored-by: Peter Lubell-Doughtie --- .../buildSrc/src/main/kotlin/BuildConfigs.kt | 5 +- .../engine/data/local/DefaultRepository.kt | 4 + .../data/remote/shared/TokenAuthenticator.kt | 7 +- .../ui/appsetting/AppSettingViewModel.kt | 1 - .../questionnaire/QuestionnaireViewModel.kt | 162 +++++++++------- .../quest/StructureMapUtilitiesTest.kt | 176 +++--------------- .../quest/ui/profile/ProfileViewModelTest.kt | 3 +- .../QuestionnaireViewModelTest.kt | 15 +- 8 files changed, 146 insertions(+), 227 deletions(-) diff --git a/android/buildSrc/src/main/kotlin/BuildConfigs.kt b/android/buildSrc/src/main/kotlin/BuildConfigs.kt index 78176a7a61..b4ac17129a 100644 --- a/android/buildSrc/src/main/kotlin/BuildConfigs.kt +++ b/android/buildSrc/src/main/kotlin/BuildConfigs.kt @@ -3,7 +3,7 @@ object BuildConfigs { const val compileSdk = 34 const val targetSdk = 34 const val versionCode = 11 - const val versionName = "2.0.0" + const val versionName = "2.0.1" const val applicationId = "org.smartregister.opensrp" const val jvmToolchain = 17 const val kotlinCompilerExtensionVersion = "1.5.8" @@ -11,4 +11,5 @@ object BuildConfigs { const val ktLintVersion = "0.49.0" const val enableUnitTestCoverage = true const val enableAndroidTestCoverage = false -} \ No newline at end of file +} + diff --git a/android/engine/src/main/java/org/smartregister/fhircore/engine/data/local/DefaultRepository.kt b/android/engine/src/main/java/org/smartregister/fhircore/engine/data/local/DefaultRepository.kt index d4e4b069bc..9563ceef29 100644 --- a/android/engine/src/main/java/org/smartregister/fhircore/engine/data/local/DefaultRepository.kt +++ b/android/engine/src/main/java/org/smartregister/fhircore/engine/data/local/DefaultRepository.kt @@ -264,6 +264,10 @@ constructor( fhirEngine.update(resource) } + suspend fun applyDbTransaction(block: suspend () -> Unit) { + fhirEngine.withTransaction { block.invoke() } + } + suspend fun loadManagingEntity(group: Group) = group.managingEntity?.let { reference -> fhirEngine diff --git a/android/engine/src/main/java/org/smartregister/fhircore/engine/data/remote/shared/TokenAuthenticator.kt b/android/engine/src/main/java/org/smartregister/fhircore/engine/data/remote/shared/TokenAuthenticator.kt index a3daf5035a..757bb0a355 100644 --- a/android/engine/src/main/java/org/smartregister/fhircore/engine/data/remote/shared/TokenAuthenticator.kt +++ b/android/engine/src/main/java/org/smartregister/fhircore/engine/data/remote/shared/TokenAuthenticator.kt @@ -40,6 +40,8 @@ import java.util.Base64 import javax.inject.Inject import javax.inject.Singleton import javax.net.ssl.SSLHandshakeException +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import org.smartregister.fhircore.engine.configuration.app.ConfigService import org.smartregister.fhircore.engine.data.remote.auth.OAuthService @@ -215,8 +217,11 @@ constructor( addAccountExplicitly(newAccount, oAuthResponse.refreshToken, null) setAuthToken(newAccount, AUTH_TOKEN_TYPE, oAuthResponse.accessToken) } + // Save credentials - secureSharedPreference.saveCredentials(username, password) + CoroutineScope(dispatcherProvider.io()).launch { + secureSharedPreference.saveCredentials(username, password) + } } } diff --git a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/appsetting/AppSettingViewModel.kt b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/appsetting/AppSettingViewModel.kt index a099937789..f6f2ff9eb4 100644 --- a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/appsetting/AppSettingViewModel.kt +++ b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/appsetting/AppSettingViewModel.kt @@ -29,7 +29,6 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import okhttp3.RequestBody.Companion.toRequestBody import org.apache.commons.lang3.StringUtils -import org.hl7.fhir.r4.model.Binary import org.hl7.fhir.r4.model.Bundle import org.hl7.fhir.r4.model.Composition import org.hl7.fhir.r4.model.ResourceType diff --git a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/questionnaire/QuestionnaireViewModel.kt b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/questionnaire/QuestionnaireViewModel.kt index 2fedb834e6..b2430fe56e 100644 --- a/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/questionnaire/QuestionnaireViewModel.kt +++ b/android/quest/src/main/java/org/smartregister/fhircore/quest/ui/questionnaire/QuestionnaireViewModel.kt @@ -195,73 +195,93 @@ constructor( context = context, ) - saveExtractedResources( - bundle = bundle, - questionnaire = questionnaire, - questionnaireConfig = questionnaireConfig, - questionnaireResponse = currentQuestionnaireResponse, - context = context, + defaultRepository.applyDbTransaction { + performSave( + bundle, + questionnaire, + questionnaireConfig, + currentQuestionnaireResponse, + context, + actionParameters, + ) + } + + val idTypes = + bundle.entry?.map { IdType(it.resource.resourceType.name, it.resource.logicalId) } + ?: emptyList() + + onSuccessfulSubmission( + idTypes, + currentQuestionnaireResponse, ) + } + } - updateResourcesLastUpdatedProperty(actionParameters) + private suspend fun performSave( + bundle: Bundle, + questionnaire: Questionnaire, + questionnaireConfig: QuestionnaireConfig, + currentQuestionnaireResponse: QuestionnaireResponse, + context: Context, + actionParameters: List, + ) { + saveExtractedResources( + bundle = bundle, + questionnaire = questionnaire, + questionnaireConfig = questionnaireConfig, + questionnaireResponse = currentQuestionnaireResponse, + context = context, + ) - // Important to load subject resource to retrieve ID (as reference) correctly - val subjectIdType: IdType? = - if (currentQuestionnaireResponse.subject.reference.isNullOrEmpty()) { - null - } else { - IdType(currentQuestionnaireResponse.subject.reference) - } + updateResourcesLastUpdatedProperty(actionParameters) - if (subjectIdType != null) { - val subject = - loadResource( - ResourceType.valueOf(subjectIdType.resourceType), - subjectIdType.idPart, - ) + // Important to load subject resource to retrieve ID (as reference) correctly + val subjectIdType: IdType? = + if (currentQuestionnaireResponse.subject.reference.isNullOrEmpty()) { + null + } else { + IdType(currentQuestionnaireResponse.subject.reference) + } - if (subject != null && !questionnaireConfig.isReadOnly()) { - val newBundle = bundle.copyBundle(currentQuestionnaireResponse) + if (subjectIdType != null) { + val subject = + loadResource( + ResourceType.valueOf(subjectIdType.resourceType), + subjectIdType.idPart, + ) - val extractedResources = newBundle.entry.map { it.resource } - validateWithFhirValidator(*extractedResources.toTypedArray()) + if (subject != null && !questionnaireConfig.isReadOnly()) { + val newBundle = bundle.copyBundle(currentQuestionnaireResponse) - generateCarePlan( - subject = subject, - bundle = newBundle, - questionnaireConfig = questionnaireConfig, - ) + val extractedResources = newBundle.entry.map { it.resource } + validateWithFhirValidator(*extractedResources.toTypedArray()) - withContext(dispatcherProvider.io()) { - executeCql( - subject = subject, - bundle = newBundle, - questionnaire = questionnaire, - questionnaireConfig = questionnaireConfig, - ) - } + generateCarePlan( + subject = subject, + bundle = newBundle, + questionnaireConfig = questionnaireConfig, + ) - fhirCarePlanGenerator.conditionallyUpdateResourceStatus( - questionnaireConfig = questionnaireConfig, + withContext(dispatcherProvider.io()) { + executeCql( subject = subject, bundle = newBundle, + questionnaire = questionnaire, + questionnaireConfig = questionnaireConfig, ) } - } - - softDeleteResources(questionnaireConfig) - retireUsedQuestionnaireUniqueId(questionnaireConfig, currentQuestionnaireResponse) + fhirCarePlanGenerator.conditionallyUpdateResourceStatus( + questionnaireConfig = questionnaireConfig, + subject = subject, + bundle = newBundle, + ) + } + } - val idTypes = - bundle.entry?.map { IdType(it.resource.resourceType.name, it.resource.logicalId) } - ?: emptyList() + softDeleteResources(questionnaireConfig) - onSuccessfulSubmission( - idTypes, - currentQuestionnaireResponse, - ) - } + retireUsedQuestionnaireUniqueId(questionnaireConfig, currentQuestionnaireResponse) } fun validateWithFhirValidator(vararg resource: Resource) { @@ -642,27 +662,25 @@ constructor( ): Bundle = kotlin .runCatching { - withContext(dispatcherProvider.default()) { - if (extractByStructureMap) { - ResourceMapper.extract( - questionnaire = questionnaire, - questionnaireResponse = questionnaireResponse, - structureMapExtractionContext = - StructureMapExtractionContext( - transformSupportServices = transformSupportServices, - structureMapProvider = { structureMapUrl: String?, _: IWorkerContext -> - structureMapUrl?.substringAfterLast("/")?.let { structureMapId -> - defaultRepository.loadResourceFromCache(structureMapId) - } - }, - ), - ) - } else { - ResourceMapper.extract( - questionnaire = questionnaire, - questionnaireResponse = questionnaireResponse, - ) - } + if (extractByStructureMap) { + ResourceMapper.extract( + questionnaire = questionnaire, + questionnaireResponse = questionnaireResponse, + structureMapExtractionContext = + StructureMapExtractionContext( + transformSupportServices = transformSupportServices, + structureMapProvider = { structureMapUrl: String?, _: IWorkerContext -> + structureMapUrl?.substringAfterLast("/")?.let { structureMapId -> + defaultRepository.loadResourceFromCache(structureMapId) + } + }, + ), + ) + } else { + ResourceMapper.extract( + questionnaire = questionnaire, + questionnaireResponse = questionnaireResponse, + ) } } .onFailure { exception -> diff --git a/android/quest/src/test/java/org/smartregister/fhircore/quest/StructureMapUtilitiesTest.kt b/android/quest/src/test/java/org/smartregister/fhircore/quest/StructureMapUtilitiesTest.kt index d6cfc4eb3b..4b893f97fe 100644 --- a/android/quest/src/test/java/org/smartregister/fhircore/quest/StructureMapUtilitiesTest.kt +++ b/android/quest/src/test/java/org/smartregister/fhircore/quest/StructureMapUtilitiesTest.kt @@ -33,7 +33,9 @@ import org.hl7.fhir.r4.model.QuestionnaireResponse import org.hl7.fhir.r4.model.RelatedPerson import org.hl7.fhir.r4.model.ResourceType import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager +import org.junit.After import org.junit.Assert +import org.junit.Before import org.junit.Test import org.smartregister.fhircore.engine.util.helper.TransformSupportServices import org.smartregister.fhircore.quest.robolectric.RobolectricTest @@ -45,25 +47,40 @@ import org.smartregister.fhircore.quest.robolectric.RobolectricTest * This should be removed at a later point once we have a more clear way of doing this */ class StructureMapUtilitiesTest : RobolectricTest() { - - @Test - fun `perform family extraction`() { - val registrationQuestionnaireResponseString: String = - "content/general/family/questionnaire-response-standard.json".readFile() - val registrationStructureMap = "content/general/family/family-registration.map".readFile() - val packageCacheManager = FilesystemPackageCacheManager(true) - val contextR4 = + private lateinit var packageCacheManager: FilesystemPackageCacheManager + private lateinit var contextR4: SimpleWorkerContext + private lateinit var transformSupportServices: TransformSupportServices + private lateinit var structureMapUtilities: org.hl7.fhir.r4.utils.StructureMapUtilities + private lateinit var iParser: IParser + + @Before + fun setUp() { + packageCacheManager = FilesystemPackageCacheManager(true) + contextR4 = SimpleWorkerContext.fromPackage(packageCacheManager.loadPackage("hl7.fhir.r4.core", "4.0.1")) .apply { setExpansionProfile(Parameters()) isCanRunWithoutTerminology = true } - val transformSupportServices = TransformSupportServices(contextR4) - val structureMapUtilities = + transformSupportServices = TransformSupportServices(contextR4) + structureMapUtilities = org.hl7.fhir.r4.utils.StructureMapUtilities(contextR4, transformSupportServices) + iParser = FhirContext.forCached(FhirVersionEnum.R4).newJsonParser() + } + + @After + fun packageTearDown() { + // Clean up resources or reset states here + packageCacheManager.clear() + } + + @Test + fun `perform family extraction`() { + val registrationQuestionnaireResponseString: String = + "content/general/family/questionnaire-response-standard.json".readFile() + val registrationStructureMap = "content/general/family/family-registration.map".readFile() val structureMap = structureMapUtilities.parse(registrationStructureMap, "eCBIS Family Registration") - val iParser: IParser = FhirContext.forCached(FhirVersionEnum.R4).newJsonParser() val targetResource = Bundle() val baseElement = iParser.parseResource( @@ -84,19 +101,8 @@ class StructureMapUtilitiesTest : RobolectricTest() { "content/general/disease-registration-resources/questionnaire_response.json".readFile() val immunizationStructureMap = "content/general/disease-registration-resources/structure-map.txt".readFile() - val packageCacheManager = FilesystemPackageCacheManager(true) - val contextR4 = - SimpleWorkerContext.fromPackage(packageCacheManager.loadPackage("hl7.fhir.r4.core", "4.0.1")) - .apply { - setExpansionProfile(Parameters()) - isCanRunWithoutTerminology = true - } - val transformSupportServices = TransformSupportServices(contextR4) - val structureMapUtilities = - org.hl7.fhir.r4.utils.StructureMapUtilities(contextR4, transformSupportServices) val structureMap = structureMapUtilities.parse(immunizationStructureMap, "eCBIS Disease Registration") - val iParser: IParser = FhirContext.forCached(FhirVersionEnum.R4).newJsonParser() val targetResource = Bundle() val baseElement = iParser.parseResource( @@ -118,19 +124,8 @@ class StructureMapUtilitiesTest : RobolectricTest() { val immunizationJson = "content/eir/immunization/immunization-1.json".readFile() val immunizationStructureMap = "content/eir/immunization/structure-map.txt".readFile() val questionnaireJson = "content/eir/immunization/questionnaire.json".readFile() - val packageCacheManager = FilesystemPackageCacheManager(true) - val contextR4 = - SimpleWorkerContext.fromPackage(packageCacheManager.loadPackage("hl7.fhir.r4.core", "4.0.1")) - .apply { - setExpansionProfile(Parameters()) - isCanRunWithoutTerminology = true - } - val transformSupportServices = TransformSupportServices(contextR4) - val structureMapUtilities = - org.hl7.fhir.r4.utils.StructureMapUtilities(contextR4, transformSupportServices) val structureMap = structureMapUtilities.parse(immunizationStructureMap, "ImmunizationRegistration") - val iParser: IParser = FhirContext.forCached(FhirVersionEnum.R4).newJsonParser() val targetResource = Bundle() val patient = iParser.parseResource(Patient::class.java, patientJson) val immunization = iParser.parseResource(Immunization::class.java, immunizationJson) @@ -182,16 +177,6 @@ class StructureMapUtilitiesTest : RobolectricTest() { ) } - val packageCacheManager = FilesystemPackageCacheManager(true) - val contextR4 = - SimpleWorkerContext.fromPackage(packageCacheManager.loadPackage("hl7.fhir.r4.core", "4.0.1")) - .apply { - setExpansionProfile(Parameters()) - isCanRunWithoutTerminology = true - } - val transformSupportServices = TransformSupportServices(contextR4) - val structureMapUtilities = - org.hl7.fhir.r4.utils.StructureMapUtilities(contextR4, transformSupportServices) val structureMap = structureMapUtilities.parse(patientRegistrationStructureMap, "PatientRegistration") val targetResource = Bundle() @@ -224,16 +209,6 @@ class StructureMapUtilitiesTest : RobolectricTest() { ) } - val packageCacheManager = FilesystemPackageCacheManager(true) - val contextR4 = - SimpleWorkerContext.fromPackage(packageCacheManager.loadPackage("hl7.fhir.r4.core", "4.0.1")) - .apply { - setExpansionProfile(Parameters()) - isCanRunWithoutTerminology = true - } - val transformSupportServices = TransformSupportServices(contextR4) - val structureMapUtilities = - org.hl7.fhir.r4.utils.StructureMapUtilities(contextR4, transformSupportServices) val structureMap = structureMapUtilities.parse(adverseEventStructureMap, "AdverseEvent") val targetResource = Bundle() @@ -248,14 +223,8 @@ class StructureMapUtilitiesTest : RobolectricTest() { fun `convert StructureMap to JSON`() { val patientRegistrationStructureMap = "patient-registration-questionnaire/structure-map.txt".readFile() - val packageCacheManager = FilesystemPackageCacheManager(true) - val contextR4 = - SimpleWorkerContext.fromPackage(packageCacheManager.loadPackage("hl7.fhir.r4.core", "4.0.1")) - .apply { isCanRunWithoutTerminology = true } - val structureMapUtilities = org.hl7.fhir.r4.utils.StructureMapUtilities(contextR4) val structureMap = structureMapUtilities.parse(patientRegistrationStructureMap, "PatientRegistration") - val iParser: IParser = FhirContext.forCached(FhirVersionEnum.R4).newJsonParser() val mapString = iParser.encodeResourceToString(structureMap) Assert.assertNotNull(mapString) @@ -267,19 +236,8 @@ class StructureMapUtilitiesTest : RobolectricTest() { "patient-registration-questionnaire/questionnaire-response.json".readFile() val patientRegistrationStructureMap = "patient-registration-questionnaire/structure-map.txt".readFile() - val packageCacheManager = FilesystemPackageCacheManager(true) - val contextR4 = - SimpleWorkerContext.fromPackage(packageCacheManager.loadPackage("hl7.fhir.r4.core", "4.0.1")) - .apply { - setExpansionProfile(Parameters()) - isCanRunWithoutTerminology = true - } - val transformSupportServices = TransformSupportServices(contextR4) - val structureMapUtilities = - org.hl7.fhir.r4.utils.StructureMapUtilities(contextR4, transformSupportServices) val structureMap = structureMapUtilities.parse(patientRegistrationStructureMap, "PatientRegistration") - val iParser: IParser = FhirContext.forCached(FhirVersionEnum.R4).newJsonParser() val targetResource = Bundle() val baseElement = iParser.parseResource( @@ -298,18 +256,7 @@ class StructureMapUtilitiesTest : RobolectricTest() { val adverseEventQuestionnaireResponse = "content/eir/adverse-event/questionnaire-response.json".readFile() val adverseEventStructureMap = "content/eir/adverse-event/structure-map.txt".readFile() - val packageCacheManager = FilesystemPackageCacheManager(true) - val contextR4 = - SimpleWorkerContext.fromPackage(packageCacheManager.loadPackage("hl7.fhir.r4.core", "4.0.1")) - .apply { - setExpansionProfile(Parameters()) - isCanRunWithoutTerminology = true - } - val transformSupportServices = TransformSupportServices(contextR4) - val structureMapUtilities = - org.hl7.fhir.r4.utils.StructureMapUtilities(contextR4, transformSupportServices) val structureMap = structureMapUtilities.parse(adverseEventStructureMap, "AdverseEvent") - val iParser: IParser = FhirContext.forCached(FhirVersionEnum.R4).newJsonParser() val targetResource = Bundle() val baseElement = @@ -327,18 +274,7 @@ class StructureMapUtilitiesTest : RobolectricTest() { val vitalSignQuestionnaireResponse = "content/anc/vital-signs/metric/questionnaire-response-pulse-rate.json".readFile() val vitalSignStructureMap = "content/anc/vital-signs/metric/structure-map.txt".readFile() - val packageCacheManager = FilesystemPackageCacheManager(true) - val contextR4 = - SimpleWorkerContext.fromPackage(packageCacheManager.loadPackage("hl7.fhir.r4.core", "4.0.1")) - .apply { - setExpansionProfile(Parameters()) - isCanRunWithoutTerminology = true - } - val transformSupportServices = TransformSupportServices(contextR4) - val structureMapUtilities = - org.hl7.fhir.r4.utils.StructureMapUtilities(contextR4, transformSupportServices) val structureMap = structureMapUtilities.parse(vitalSignStructureMap, "VitalSigns") - val iParser: IParser = FhirContext.forCached(FhirVersionEnum.R4).newJsonParser() val targetResource = Bundle() val baseElement = iParser.parseResource(QuestionnaireResponse::class.java, vitalSignQuestionnaireResponse) @@ -356,18 +292,7 @@ class StructureMapUtilitiesTest : RobolectricTest() { "content/anc/vital-signs/standard/questionnaire-response-pulse-rate.json".readFile() val vitalSignStructureMap = "content/anc/vital-signs/standard/structure-map.txt".readFile() - val packageCacheManager = FilesystemPackageCacheManager(true) - val contextR4 = - SimpleWorkerContext.fromPackage(packageCacheManager.loadPackage("hl7.fhir.r4.core", "4.0.1")) - .apply { - setExpansionProfile(Parameters()) - isCanRunWithoutTerminology = true - } - val transformSupportServices = TransformSupportServices(contextR4) - val structureMapUtilities = - org.hl7.fhir.r4.utils.StructureMapUtilities(contextR4, transformSupportServices) val structureMap = structureMapUtilities.parse(vitalSignStructureMap, "VitalSigns") - val iParser: IParser = FhirContext.forCached(FhirVersionEnum.R4).newJsonParser() val targetResource = Bundle() val baseElement = iParser.parseResource(QuestionnaireResponse::class.java, vitalSignQuestionnaireResponse) @@ -377,6 +302,7 @@ class StructureMapUtilitiesTest : RobolectricTest() { Assert.assertEquals(2, targetResource.entry.size) Assert.assertEquals("Encounter", targetResource.entry[0].resource.resourceType.toString()) Assert.assertEquals("Observation", targetResource.entry[1].resource.resourceType.toString()) + packageCacheManager.clear() } @Test @@ -384,18 +310,7 @@ class StructureMapUtilitiesTest : RobolectricTest() { val locationQuestionnaireResponseString: String = "content/general/location/location-response-sample.json".readFile() val locationStructureMap = "content/general/location/location-structure-map.txt".readFile() - val packageCacheManager = FilesystemPackageCacheManager(true) - val contextR4 = - SimpleWorkerContext.fromPackage(packageCacheManager.loadPackage("hl7.fhir.r4.core", "4.0.1")) - .apply { - setExpansionProfile(Parameters()) - isCanRunWithoutTerminology = true - } - val transformSupportServices = TransformSupportServices(contextR4) - val structureMapUtilities = - org.hl7.fhir.r4.utils.StructureMapUtilities(contextR4, transformSupportServices) val structureMap = structureMapUtilities.parse(locationStructureMap, "LocationRegistration") - val iParser: IParser = FhirContext.forCached(FhirVersionEnum.R4).newJsonParser() val targetResource = Bundle() val baseElement = iParser.parseResource(QuestionnaireResponse::class.java, locationQuestionnaireResponseString) @@ -412,22 +327,11 @@ class StructureMapUtilitiesTest : RobolectricTest() { "content/general/supply-chain/questionnaire-response-standard.json".readFile() val physicalInventoryCountStructureMap = "content/general/supply-chain/physical_inventory_count_and_stock.map".readFile() - val packageCacheManager = FilesystemPackageCacheManager(true) - val contextR4 = - SimpleWorkerContext.fromPackage(packageCacheManager.loadPackage("hl7.fhir.r4.core", "4.0.1")) - .apply { - setExpansionProfile(Parameters()) - isCanRunWithoutTerminology = true - } - val transformSupportServices = TransformSupportServices(contextR4) - val structureMapUtilities = - org.hl7.fhir.r4.utils.StructureMapUtilities(contextR4, transformSupportServices) val structureMap = structureMapUtilities.parse( physicalInventoryCountStructureMap, "Physical Inventory Count and Stock Supply", ) - val iParser: IParser = FhirContext.forCached(FhirVersionEnum.R4).newJsonParser() val targetResource = Bundle() val baseElement = iParser.parseResource( @@ -450,19 +354,8 @@ class StructureMapUtilitiesTest : RobolectricTest() { val vitalSignQuestionnaireResponse = "content/anc/preg-outcome/questionnaire-response.json".readFile() val vitalSignStructureMap = "content/anc/preg-outcome/structure-map.txt".readFile() - val packageCacheManager = FilesystemPackageCacheManager(true) - val contextR4 = - SimpleWorkerContext.fromPackage(packageCacheManager.loadPackage("hl7.fhir.r4.core", "4.0.1")) - .apply { - setExpansionProfile(Parameters()) - isCanRunWithoutTerminology = true - } - val transformSupportServices = TransformSupportServices(contextR4) - val structureMapUtilities = - org.hl7.fhir.r4.utils.StructureMapUtilities(contextR4, transformSupportServices) val structureMap = structureMapUtilities.parse(vitalSignStructureMap, "PregnancyOutcomeRegistration") - val iParser: IParser = FhirContext.forCached(FhirVersionEnum.R4).newJsonParser() val targetResource = Bundle() val baseElement = iParser.parseResource(QuestionnaireResponse::class.java, vitalSignQuestionnaireResponse) @@ -483,18 +376,7 @@ class StructureMapUtilitiesTest : RobolectricTest() { "content/general/who-eir/patient_registration_questionnaire_response.json".readFile() val locationStructureMap = "content/general/who-eir/patient_registration_structure_map.txt".readFile() - val packageCacheManager = FilesystemPackageCacheManager(true) - val contextR4 = - SimpleWorkerContext.fromPackage(packageCacheManager.loadPackage("hl7.fhir.r4.core", "4.0.1")) - .apply { - setExpansionProfile(Parameters()) - isCanRunWithoutTerminology = true - } - val transformSupportServices = TransformSupportServices(contextR4) - val structureMapUtilities = - org.hl7.fhir.r4.utils.StructureMapUtilities(contextR4, transformSupportServices) val structureMap = structureMapUtilities.parse(locationStructureMap, "IMMZ-C-QRToPatient") - val iParser: IParser = FhirContext.forCached(FhirVersionEnum.R4).newJsonParser() val targetResource = Bundle() val baseElement = iParser.parseResource(QuestionnaireResponse::class.java, locationQuestionnaireResponseString) diff --git a/android/quest/src/test/java/org/smartregister/fhircore/quest/ui/profile/ProfileViewModelTest.kt b/android/quest/src/test/java/org/smartregister/fhircore/quest/ui/profile/ProfileViewModelTest.kt index 9c63ea2390..408d98b3b0 100644 --- a/android/quest/src/test/java/org/smartregister/fhircore/quest/ui/profile/ProfileViewModelTest.kt +++ b/android/quest/src/test/java/org/smartregister/fhircore/quest/ui/profile/ProfileViewModelTest.kt @@ -54,7 +54,6 @@ import org.smartregister.fhircore.engine.domain.model.OverflowMenuItemConfig import org.smartregister.fhircore.engine.domain.model.RepositoryResourceData import org.smartregister.fhircore.engine.domain.model.ResourceData import org.smartregister.fhircore.engine.rulesengine.ResourceDataRulesExecutor -import org.smartregister.fhircore.engine.util.DefaultDispatcherProvider import org.smartregister.fhircore.engine.util.DispatcherProvider import org.smartregister.fhircore.engine.util.extension.BLACK_COLOR_HEX_CODE import org.smartregister.fhircore.engine.util.extension.getActivity @@ -99,7 +98,6 @@ class ProfileViewModelTest : RobolectricTest() { spyk( RegisterRepository( fhirEngine = mockk(), - dispatcherProvider = DefaultDispatcherProvider(), sharedPreferencesHelper = mockk(), configurationRegistry = configurationRegistry, configService = mockk(), @@ -107,6 +105,7 @@ class ProfileViewModelTest : RobolectricTest() { fhirPathDataExtractor = mockk(), parser = parser, context = ApplicationProvider.getApplicationContext(), + dispatcherProvider = dispatcherProvider, ), ) coEvery { diff --git a/android/quest/src/test/java/org/smartregister/fhircore/quest/ui/questionnaire/QuestionnaireViewModelTest.kt b/android/quest/src/test/java/org/smartregister/fhircore/quest/ui/questionnaire/QuestionnaireViewModelTest.kt index e897d4b8a7..90c7753ab7 100644 --- a/android/quest/src/test/java/org/smartregister/fhircore/quest/ui/questionnaire/QuestionnaireViewModelTest.kt +++ b/android/quest/src/test/java/org/smartregister/fhircore/quest/ui/questionnaire/QuestionnaireViewModelTest.kt @@ -150,7 +150,6 @@ class QuestionnaireViewModelTest : RobolectricTest() { @Inject lateinit var knowledgeManager: KnowledgeManager @Inject lateinit var contentCache: ContentCache - private lateinit var samplePatientRegisterQuestionnaire: Questionnaire private lateinit var questionnaireConfig: QuestionnaireConfig private lateinit var questionnaireViewModel: QuestionnaireViewModel @@ -250,6 +249,10 @@ class QuestionnaireViewModelTest : RobolectricTest() { extractionQuestionnaire().apply { extension = samplePatientRegisterQuestionnaire.extension } val questionnaireResponse = extractionQuestionnaireResponse() val actionParameters = emptyList() + coEvery { defaultRepository.applyDbTransaction(any()) } answers + { + runBlocking { (firstArg() as suspend () -> Unit).invoke() } + } val onSuccessfulSubmission = spyk({ idsTypes: List, _: QuestionnaireResponse -> Timber.i(idsTypes.toString()) }) coEvery { @@ -326,7 +329,7 @@ class QuestionnaireViewModelTest : RobolectricTest() { // TODO Write integration test for QuestionnaireActivity to compliment this unit test; @Test - fun testHandleQuestionnaireSubmission() { + fun testHandleQuestionnaireSubmission() = runTest { mockkObject(ResourceMapper) val questionnaire = extractionQuestionnaire().apply { @@ -360,6 +363,10 @@ class QuestionnaireViewModelTest : RobolectricTest() { ResourceNotFoundException("QuestionnaireResponse", "") coEvery { fhirEngine.create(resource = anyVararg()) } returns listOf(patient.logicalId) coEvery { fhirEngine.update(resource = anyVararg()) } just runs + coEvery { defaultRepository.applyDbTransaction(any()) } answers + { + runBlocking { (firstArg() as suspend () -> Unit).invoke() } + } // Mock returned bundle after extraction refer to FhirExtractionTest.kt for extraction test coEvery { @@ -658,6 +665,7 @@ class QuestionnaireViewModelTest : RobolectricTest() { questionnaireViewModel.retrieveQuestionnaire( questionnaireConfig = questionnaireConfig, ) + Assert.assertEquals( samplePatientRegisterQuestionnaire.idPart, contentCache.getResource(ResourceType.Questionnaire, questionnaireConfig.id)?.idPart, @@ -701,8 +709,10 @@ class QuestionnaireViewModelTest : RobolectricTest() { configurationRegistry = configurationRegistry, ) val patientAgeLinkId = "patient-age" + val newQuestionnaireId = "new-${questionnaireConfig.id}" val newQuestionnaireConfig = questionnaireConfig.copy( + id = newQuestionnaireId, resourceIdentifier = patient.id, resourceType = patient.resourceType, barcodeLinkId = "patient-barcode", @@ -724,6 +734,7 @@ class QuestionnaireViewModelTest : RobolectricTest() { ) coEvery { fhirEngine.get(ResourceType.Questionnaire, newQuestionnaireConfig.id) } returns samplePatientRegisterQuestionnaire.apply { + id = newQuestionnaireId addItem( Questionnaire.QuestionnaireItemComponent().apply { linkId = patientAgeLinkId