Skip to content

Commit

Permalink
Add test cases for FhirOperator.kt (google#1290)
Browse files Browse the repository at this point in the history
* - Add test cases for FhirOperator.kt

* - connectedCheck

* - Ignore FhirOperatorPopulationTest

* - Add min-max heap size in gradle for test cases

* - Update gradle

* - Update gradle

* Update ci-gradle.properties

* Create blank.yml

* Delete blank.yml

* Update ci-gradle.properties

* - Testing commit

* - Testing commit changes reverted

* Increase heap size to 4GB

* - Revert changes

* - Modify build.gradle.kts

* - Modify build.gradle.kts

* - Add some more assertions to validate generated MeasureReport resource

* - Resolved requested changes

* - Resolved requested changes

* - Resolve requested changes

* - Added a comment to trigger CI workflow.

Co-authored-by: Ephraim Kigamba <[email protected]>
Co-authored-by: Ephraim Kigamba <[email protected]>
Co-authored-by: Francis Odhiambo Otieno <[email protected]>
  • Loading branch information
4 people committed Apr 21, 2022
1 parent ac93433 commit 9539332
Show file tree
Hide file tree
Showing 4 changed files with 257 additions and 32 deletions.
6 changes: 6 additions & 0 deletions workflow/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ android {

sourceSets { getByName("test").apply { resources.setSrcDirs(listOf("testdata")) } }

// Added this for fixing out of memory issue in running test cases
tasks.withType<Test>().configureEach {
maxParallelForks = (Runtime.getRuntime().availableProcessors() - 1).takeIf { it > 0 } ?: 1
setForkEvery(100)
}

buildTypes {
getByName("release") {
isMinifyEnabled = false
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright 2021 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http:https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.android.fhir.workflow

import java.time.LocalDate
import org.hl7.fhir.r4.model.DateType

val DateType.toLocalDate: LocalDate
get() =
LocalDate.of(
year,
month + 1,
day,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/*
* Copyright 2021 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http:https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.android.fhir.workflow

import androidx.test.core.app.ApplicationProvider
import ca.uhn.fhir.context.FhirContext
import com.google.android.fhir.FhirEngineProvider
import com.google.common.truth.Truth.assertThat
import java.util.Date
import kotlinx.coroutines.runBlocking
import org.hl7.fhir.r4.model.Bundle
import org.hl7.fhir.r4.model.DateType
import org.hl7.fhir.r4.model.Library
import org.hl7.fhir.r4.model.MeasureReport
import org.hl7.fhir.r4.model.Resource
import org.hl7.fhir.r4.model.ResourceType
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner

@RunWith(RobolectricTestRunner::class)
class FhirOperatorPopulationTest {
private val fhirEngine =
FhirEngineProvider.getInstance(ApplicationProvider.getApplicationContext())
private val fhirContext = FhirContext.forR4()
private val jsonParser = fhirContext.newJsonParser()
private val xmlParser = fhirContext.newXmlParser()
private val fhirOperator = FhirOperator(fhirContext, fhirEngine)

@Before
fun setUp() = runBlocking {
loadBundle("/ANCIND01-bundle.json")
loadBundle("/tests-Reportable-bundle.json")
loadBundle("/tests-NotReportable-bundle.json")

// TODO Fix the FHIRHelpers library
// loadBundle("/RuleFilters-1.0.0-bundle.json")

loadFile("/first-contact/01-registration/patient-charity-otala-1.json")
loadFile("/first-contact/02-enrollment/careplan-charity-otala-1-pregnancy-plan.xml")
loadFile("/first-contact/02-enrollment/episodeofcare-charity-otala-1-pregnancy-episode.xml")
loadFile("/first-contact/03-contact/encounter-anc-encounter-charity-otala-1.xml")
}

@Test
fun evaluatePopulationMeasure() = runBlocking {
val measureReport =
fhirOperator.evaluateMeasure(
measureUrl = "http:https://fhir.org/guides/who/anc-cds/Measure/ANCIND01",
start = "2019-01-01",
end = "2021-12-31",
reportType = "population",
subject = null,
practitioner = "jane",
lastReceivedOn = null
)
val measureReportJSON =
FhirContext.forR4().newJsonParser().encodeResourceToString(measureReport)

assertThat(MeasureReport.MeasureReportStatus.COMPLETE).isEqualTo(measureReport.status)
assertThat(MeasureReport.MeasureReportType.SUMMARY).isEqualTo(measureReport.type)
assertThat("2019-01-01").isEqualTo(DateType(measureReport.period.start).toLocalDate.toString())
assertThat("2021-12-31").isEqualTo(DateType(measureReport.period.end).toLocalDate.toString())
assertThat(DateType(Date()).toLocalDate).isEqualTo(DateType(measureReport.date).toLocalDate)

assertThat(measureReportJSON).isNotNull()
assertThat(measureReport).isNotNull()

assertThat(measureReport.extension[0].value.toString())
.isEqualTo(
"Percentage of pregnant women with first ANC contact in the first trimester (before 12 weeks of gestation)"
)
assertThat(measureReport.extension[0].url)
.isEqualTo(
"http:https://hl7.org/fhir/5.0/StructureDefinition/extension-MeasureReport.population.description"
)

assertThat(measureReport.measure.toString())
.isEqualTo("http:https://fhir.org/guides/who/anc-cds/Measure/ANCIND01")
assertThat(measureReport.improvementNotation.coding[0].system)
.isEqualTo("http:https://terminology.hl7.org/CodeSystem/measure-improvement-notation")
assertThat(measureReport.improvementNotation.coding[0].code.toString()).isEqualTo("increase")

val population = measureReport.group[0].population

assertThat(population[0].id).isEqualTo("initial-population")
assertThat(population[0].code.coding[0].code.toString()).isEqualTo("initial-population")
assertThat(population[0].code.coding[0].system)
.isEqualTo("http:https://terminology.hl7.org/CodeSystem/measure-population")

assertThat(population[1].id).isEqualTo("denominator")
assertThat(population[1].code.coding[0].code.toString()).isEqualTo("denominator")
assertThat(population[1].code.coding[0].system)
.isEqualTo("http:https://terminology.hl7.org/CodeSystem/measure-population")

assertThat(population[2].id).isEqualTo("numerator")
assertThat(population[2].code.coding[0].code.toString()).isEqualTo("numerator")
assertThat(population[2].code.coding[0].system)
.isEqualTo("http:https://terminology.hl7.org/CodeSystem/measure-population")

assertThat(measureReport.type.display).isEqualTo("Summary")
}

private suspend fun loadFile(path: String) {
if (path.endsWith(suffix = ".xml")) {
val resource = xmlParser.parseResource(javaClass.getResourceAsStream(path)) as Resource
fhirEngine.create(resource)
} else if (path.endsWith(".json")) {
val resource = jsonParser.parseResource(javaClass.getResourceAsStream(path)) as Resource
fhirEngine.create(resource)
}
}

private suspend fun loadBundle(path: String) {
val bundle = jsonParser.parseResource(javaClass.getResourceAsStream(path)) as Bundle
for (entry in bundle.entry) {
when (entry.resource.resourceType) {
ResourceType.Library -> fhirOperator.loadLib(entry.resource as Library)
ResourceType.Bundle -> Unit
else -> fhirEngine.create(entry.resource)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,12 @@ import androidx.test.core.app.ApplicationProvider
import ca.uhn.fhir.context.FhirContext
import com.google.android.fhir.FhirEngineProvider
import com.google.common.truth.Truth.assertThat
import java.util.Date
import kotlinx.coroutines.runBlocking
import org.hl7.fhir.r4.model.Bundle
import org.hl7.fhir.r4.model.DateType
import org.hl7.fhir.r4.model.Library
import org.hl7.fhir.r4.model.MeasureReport
import org.hl7.fhir.r4.model.Resource
import org.hl7.fhir.r4.model.ResourceType
import org.junit.Before
Expand All @@ -43,18 +46,32 @@ class FhirOperatorTest {
@Before
fun setUp() = runBlocking {
loadBundle("/ANCIND01-bundle.json")
loadBundle("/RuleFilters-1.0.0-bundle.json")
loadBundle("/tests-Reportable-bundle.json")
loadBundle("/tests-NotReportable-bundle.json")

// TODO Fix the FHIRHelpers library
// loadBundle("/RuleFilters-1.0.0-bundle.json")

loadFile("/first-contact/01-registration/patient-charity-otala-1.json")
loadFile("/first-contact/02-enrollment/careplan-charity-otala-1-pregnancy-plan.xml")
loadFile("/first-contact/02-enrollment/episodeofcare-charity-otala-1-pregnancy-episode.xml")
loadFile("/first-contact/03-contact/encounter-anc-encounter-charity-otala-1.xml")
}

@Test
@Ignore("Fix the FHIRHelpers library")
@Ignore("Refactor the API to accommodate local end points")
fun generateCarePlan() = runBlocking {
assertThat(
fhirOperator.generateCarePlan(
planDefinitionId = "plandefinition-RuleFilters-1.0.0",
patientId = "Reportable",
encounterId = "reportable-encounter"
)
)
.isNotNull()
}

@Test
fun evaluateIndividualSubjectMeasure() = runBlocking {
val measureReport =
fhirOperator.evaluateMeasure(
Expand All @@ -68,42 +85,77 @@ class FhirOperatorTest {
)
val measureReportJSON =
FhirContext.forR4().newJsonParser().encodeResourceToString(measureReport)
assertThat(MeasureReport.MeasureReportStatus.COMPLETE).isEqualTo(measureReport.status)
assertThat(MeasureReport.MeasureReportType.INDIVIDUAL).isEqualTo(measureReport.type)
assertThat(DateType(Date()).toLocalDate).isEqualTo(DateType(measureReport.date).toLocalDate)
assertThat("2020-01-01").isEqualTo(DateType(measureReport.period.start).toLocalDate.toString())
assertThat("2020-01-31").isEqualTo(DateType(measureReport.period.end).toLocalDate.toString())
assertThat("Patient/charity-otala-1").isEqualTo(measureReport.subject.reference)
assertThat(measureReportJSON).isNotNull()
assertThat(measureReport).isNotNull()
assertThat(measureReport.type.display).isEqualTo("Individual")
}

@Test
@Ignore("Fix OutOfMemoryException")
fun evaluatePopulationMeasure() = runBlocking {
val measureReport =
fhirOperator.evaluateMeasure(
measureUrl = "http:https://fhir.org/guides/who/anc-cds/Measure/ANCIND01",
start = "2019-01-01",
end = "2021-12-31",
reportType = "population",
subject = null,
practitioner = "jane",
lastReceivedOn = null
assertThat(measureReport.extension[0].value.toString())
.isEqualTo(
"Percentage of pregnant women with first ANC contact in the first trimester (before 12 weeks of gestation)"
)
assertThat(measureReport.extension[0].url)
.isEqualTo(
"http:https://hl7.org/fhir/5.0/StructureDefinition/extension-MeasureReport.population.description"
)
val measureReportJSON =
FhirContext.forR4().newJsonParser().encodeResourceToString(measureReport)
assertThat(measureReportJSON).isNotNull()
assertThat(measureReport).isNotNull()
assertThat(measureReport.type.display).isEqualTo("Summary")
}

@Test
@Ignore("Refactor the API to accommodate local end points")
fun generateCarePlan() = runBlocking {
assertThat(
fhirOperator.generateCarePlan(
planDefinitionId = "plandefinition-RuleFilters-1.0.0",
patientId = "Reportable",
encounterId = "reportable-encounter"
)
assertThat(measureReport.measure.toString())
.isEqualTo("http:https://fhir.org/guides/who/anc-cds/Measure/ANCIND01")
assertThat(measureReport.improvementNotation.coding[0].system)
.isEqualTo("http:https://terminology.hl7.org/CodeSystem/measure-improvement-notation")
assertThat(measureReport.improvementNotation.coding[0].code.toString()).isEqualTo("increase")

val evaluatedResource = measureReport.evaluatedResource

assertThat(evaluatedResource[0].reference).isEqualTo("Encounter/anc-encounter-charity-otala-1")
assertThat(evaluatedResource[0].extension[0].url)
.isEqualTo(
"http:https://hl7.org/fhir/us/davinci-deqm/StructureDefinition/extension-populationReference"
)
.isNotNull()
assertThat(evaluatedResource[0].extension[0].value.toString()).isEqualTo("denominator")

assertThat(evaluatedResource[1].reference)
.isEqualTo("EpisodeOfCare/charity-otala-1-pregnancy-episode")
assertThat(evaluatedResource[1].extension[0].url)
.isEqualTo(
"http:https://hl7.org/fhir/us/davinci-deqm/StructureDefinition/extension-populationReference"
)
assertThat(evaluatedResource[1].extension[0].value.toString()).isEqualTo("initial-population")

assertThat(evaluatedResource[2].reference).isEqualTo("Patient/charity-otala-1")
assertThat(evaluatedResource[2].extension[0].url)
.isEqualTo(
"http:https://hl7.org/fhir/us/davinci-deqm/StructureDefinition/extension-populationReference"
)
assertThat(evaluatedResource[2].extension[0].value.toString()).isEqualTo("initial-population")
assertThat(evaluatedResource[2].extension[1].url)
.isEqualTo(
"http:https://hl7.org/fhir/us/davinci-deqm/StructureDefinition/extension-populationReference"
)
assertThat(evaluatedResource[2].extension[1].value.toString()).isEqualTo("denominator")

val population = measureReport.group[0].population

assertThat(population[0].id).isEqualTo("initial-population")
assertThat(population[0].code.coding[0].code.toString()).isEqualTo("initial-population")
assertThat(population[0].code.coding[0].system)
.isEqualTo("http:https://terminology.hl7.org/CodeSystem/measure-population")

assertThat(population[1].id).isEqualTo("denominator")
assertThat(population[1].code.coding[0].code.toString()).isEqualTo("denominator")
assertThat(population[1].code.coding[0].system)
.isEqualTo("http:https://terminology.hl7.org/CodeSystem/measure-population")

assertThat(population[2].id).isEqualTo("numerator")
assertThat(population[2].code.coding[0].code.toString()).isEqualTo("numerator")
assertThat(population[2].code.coding[0].system)
.isEqualTo("http:https://terminology.hl7.org/CodeSystem/measure-population")

assertThat(measureReport.type.display).isEqualTo("Individual")
}

private suspend fun loadFile(path: String) {
Expand Down

0 comments on commit 9539332

Please sign in to comment.