Skip to content

Commit

Permalink
Merge pull request #751 from MeasureAuthoringTool/MAT-7933/updatingSt…
Browse files Browse the repository at this point in the history
…ratificationAssociationInTestCasesWhenItIsChangedInGroups

MAT-7933 updating stratification association in test cases when it is changed in groups
  • Loading branch information
sb-prateekkeerthi authored Nov 29, 2024
2 parents f0f84b6 + 1517847 commit 31e9f2b
Show file tree
Hide file tree
Showing 4 changed files with 281 additions and 31 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package cms.gov.madie.measure.config;

import cms.gov.madie.measure.repositories.MeasureRepository;
import gov.cms.madie.models.common.ModelType;
import gov.cms.madie.models.measure.Measure;
import gov.cms.madie.models.measure.Stratification;
import gov.cms.madie.models.measure.TestCasePopulationValue;
import io.mongock.api.annotations.ChangeUnit;
import io.mongock.api.annotations.Execution;
import io.mongock.api.annotations.RollbackExecution;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Slf4j
@ChangeUnit(id = "qi_core_testcase_strat_update", order = "1", author = "madie_dev")
public class UpdateQICoreTestCaseStratificationsChangeUnit {
@Setter @Getter private List<Measure> tempMeasures;

@Execution
public void updateQICoreTestCaseStratifications(MeasureRepository measureRepository)
throws Exception {
log.debug("Entering updateQICoreTestCaseStratifications()");
List<Measure> measureList = measureRepository.findAllByModel(ModelType.QI_CORE.getValue());
log.info("found QI Core measures: {}", measureList.size());

measureList.forEach(
measure -> {
if (!measure.isActive()
|| CollectionUtils.isEmpty(measure.getGroups())
|| CollectionUtils.isEmpty(measure.getTestCases())) {
return;
}
for (var testCase : measure.getTestCases()) {
if (CollectionUtils.isEmpty(testCase.getGroupPopulations())) {
continue;
}
for (var groupPopulation : testCase.getGroupPopulations()) {
if (CollectionUtils.isEmpty(groupPopulation.getStratificationValues())) {
continue;
}
for (var stratificationValue : groupPopulation.getStratificationValues()) {
Optional<Stratification> matchingGroupStratification =
measure.getGroups().stream()
.flatMap(group -> group.getStratifications().stream())
.filter(strat -> strat.getId().equals(stratificationValue.getId()))
.findFirst();

if (matchingGroupStratification.isPresent()
&& stratificationValue.getPopulationValues() != null) {
List<TestCasePopulationValue> filteredStratifiedPopulationValues =
stratificationValue.getPopulationValues().stream()
.filter(
populationValue ->
matchingGroupStratification.get().getAssociations().stream()
.anyMatch(
validAssociation ->
validAssociation
.getDisplay()
.equalsIgnoreCase(
populationValue.getName().getDisplay())))
.collect(Collectors.toList());
stratificationValue.setPopulationValues(filteredStratifiedPopulationValues);
}
}
}
}

measure.setTestCases(measure.getTestCases());
measureRepository.save(measure);
});
}

@RollbackExecution
public void rollbackExecution(MeasureRepository measureRepository) throws Exception {
log.debug("Entering rollbackExecution() ");
if (CollectionUtils.isNotEmpty(tempMeasures)) {
tempMeasures.forEach(measureRepository::save);
}
}
}
62 changes: 50 additions & 12 deletions src/main/java/cms/gov/madie/measure/services/GroupService.java
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public Group createOrUpdateGroup(Group group, String measureId, String username)
measure.getGroups().add(group);
}
}
updateGroupForTestCases(group, measure.getTestCases());
updateGroupForTestCases(group, measure.getTestCases(), measure.getModel());

Measure errors = measureUtil.validateAllMeasureDependencies(measure);
measure.setErrors(errors.getErrors());
Expand All @@ -117,7 +117,7 @@ public Group createOrUpdateGroup(Group group, String measureId, String username)
* @param group Group being changed
* @param testCases TestCases to iterate over and update
*/
public void updateGroupForTestCases(Group group, List<TestCase> testCases) {
public void updateGroupForTestCases(Group group, List<TestCase> testCases, String measureModel) {
if (group != null && !CollectionUtils.isEmpty(testCases)) {
testCases.forEach(
testCase -> {
Expand All @@ -137,7 +137,7 @@ public void updateGroupForTestCases(Group group, List<TestCase> testCases) {
if (StringUtils.equals(testCaseGroupPopulation.getScoring(), group.getScoring())
&& StringUtils.equals(
testCaseGroupPopulation.getPopulationBasis(), group.getPopulationBasis())) {
updateTestCaseGroupWithMeasureGroup(testCaseGroupPopulation, group);
updateTestCaseGroupWithMeasureGroup(testCaseGroupPopulation, group, measureModel);
} else {
removeGroupFromTestCase(group.getId(), testCase);
}
Expand Down Expand Up @@ -188,7 +188,7 @@ public Measure deleteMeasureGroup(String measureId, String groupId, String usern
}

public void updateTestCaseGroupWithMeasureGroup(
TestCaseGroupPopulation testCaseGroup, Group measureGroup) {
TestCaseGroupPopulation testCaseGroup, Group measureGroup, String measureModel) {
// update test case populations based on measure group population
List<TestCasePopulationValue> populations =
measureGroup.getPopulations().stream()
Expand Down Expand Up @@ -235,10 +235,12 @@ public void updateTestCaseGroupWithMeasureGroup(
String.format(
"Strata-%d %s",
count.getAndIncrement(), measureStrata.getAssociation().getDisplay());
return updateTestCaseStratification(measureStrata, testCaseGroup, strataName);
return updateTestCaseStratification(
measureStrata, testCaseGroup, strataName, measureModel);
} else {
String strataName = String.format("Strata-%d", count.getAndIncrement());
return updateTestCaseStratification(measureStrata, testCaseGroup, strataName);
return updateTestCaseStratification(
measureStrata, testCaseGroup, strataName, measureModel);
}
})
.filter(Objects::nonNull)
Expand Down Expand Up @@ -282,7 +284,10 @@ private TestCasePopulationValue updateTestCasePopulation(
}

protected TestCaseStratificationValue updateTestCaseStratification(
Stratification stratification, TestCaseGroupPopulation testCaseGroup, String strataName) {
Stratification stratification,
TestCaseGroupPopulation testCaseGroup,
String strataName,
String measureModel) {
// if no cql definition(optional), no need to consider stratification
if (StringUtils.isEmpty(stratification.getCqlDefinition())) {
return null;
Expand All @@ -307,13 +312,16 @@ protected TestCaseStratificationValue updateTestCaseStratification(
.build();
}
testCaseStrata.setName(strataName);
handlePopulationChange(testCaseStrata, testCaseGroup);
handlePopulationChange(testCaseStrata, testCaseGroup, measureModel, stratification);

return testCaseStrata;
}

private void handlePopulationChange(
TestCaseStratificationValue testCaseStrata, TestCaseGroupPopulation testCaseGroup) {
TestCaseStratificationValue testCaseStrata,
TestCaseGroupPopulation testCaseGroup,
String measureModel,
Stratification stratification) {
List<TestCasePopulationValue> testCasePopulationValues = testCaseStrata.getPopulationValues();
List<TestCasePopulationValue> testCasePopulationValuesFromGroup =
testCaseGroup.getPopulationValues();
Expand All @@ -330,9 +338,18 @@ private void handlePopulationChange(
// delete any that is not in testCasePopulationValuesFromGroup
List<TestCasePopulationValue> tempTestCasePopulationValues = new ArrayList<>();
for (TestCasePopulationValue tempTestCasePopulationValue : testCasePopulationValues) {
if (findExistsTestCasePopulationValue(
tempTestCasePopulationValue.getId(), testCasePopulationValuesFromGroup)) {
tempTestCasePopulationValues.add(tempTestCasePopulationValue);
if (StringUtils.equals(measureModel, ModelType.QDM_5_6.getValue())) {
if (findExistsTestCasePopulationValue(
tempTestCasePopulationValue.getId(), testCasePopulationValuesFromGroup)) {
tempTestCasePopulationValues.add(tempTestCasePopulationValue);
}
} else {
// remove association from testcases when stratifications are changed in measure
// groups
if (handleStratificationAssociationChange(
tempTestCasePopulationValue, stratification)) {
tempTestCasePopulationValues.add(tempTestCasePopulationValue);
}
}
}
testCaseStrata.setPopulationValues(tempTestCasePopulationValues);
Expand All @@ -344,6 +361,27 @@ private void handlePopulationChange(
}
}

private boolean handleStratificationAssociationChange(
TestCasePopulationValue tempTestCasePopulationValue, Stratification stratification) {
if (stratification.getAssociations() != null) {
PopulationType populationAsocciation =
stratification.getAssociations().stream()
.filter(
association -> {
return association
.getDisplay()
.equalsIgnoreCase(tempTestCasePopulationValue.getName().getDisplay());
})
.findFirst()
.orElse(null);

if (populationAsocciation != null) {
return true;
}
}
return false;
}

private boolean findExistsTestCasePopulationValue(
String id, List<TestCasePopulationValue> testCasePopulationValues) {
return testCasePopulationValues.stream()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package cms.gov.madie.measure.config;

import cms.gov.madie.measure.repositories.MeasureRepository;
import gov.cms.madie.models.common.ModelType;
import gov.cms.madie.models.measure.*;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import java.util.List;

import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
public class UpdateQICoreTestCaseStratificationsChangeUnitTest {

@Mock private MeasureRepository measureRepository;

@Captor private ArgumentCaptor<Measure> measureArgumentCaptor;

@InjectMocks
UpdateQICoreTestCaseStratificationsChangeUnit updateQICoreTestCaseStratificationsChangeUnit;

@Test
void testStratsAreUpdatedInTestCasesAndRollbackHoldsMeasures() throws Exception {
List<TestCasePopulationValue> testCaseStratificationPopulationValues =
List.of(
TestCasePopulationValue.builder()
.name(PopulationType.INITIAL_POPULATION)
.expected(true)
.build(),
TestCasePopulationValue.builder()
.name(PopulationType.DENOMINATOR)
.expected(true)
.build(),
TestCasePopulationValue.builder()
.name(PopulationType.NUMERATOR)
.expected(true)
.build());

final TestCaseGroupPopulation tcGroupPop =
TestCaseGroupPopulation.builder()
.groupId("group-1")
.scoring(MeasureScoring.CONTINUOUS_VARIABLE.toString())
.stratificationValues(
List.of(
TestCaseStratificationValue.builder()
.id("strat-1")
.populationValues(testCaseStratificationPopulationValues)
.build()))
.build();

List<Measure> qiCoreMeasures =
List.of(
Measure.builder().measureName("M0_DEAD").active(false).build(),
Measure.builder().measureName("M0_NOGROUPS").active(true).groups(List.of()).build(),
Measure.builder()
.measureName("M1")
.active(true)
.model(ModelType.QI_CORE.getValue())
.groups(
List.of(
Group.builder()
.id("group-1")
.stratifications(
List.of(
Stratification.builder()
.id("strat-1")
.associations(
List.of(
PopulationType.INITIAL_POPULATION,
PopulationType.NUMERATOR))
.build()))
.build()))
.testCases(
List.of(TestCase.builder().groupPopulations(List.of(tcGroupPop)).build()))
.build());

when(measureRepository.findAllByModel(anyString())).thenReturn(qiCoreMeasures);
updateQICoreTestCaseStratificationsChangeUnit.updateQICoreTestCaseStratifications(
measureRepository);
verify(measureRepository, times(1)).save(measureArgumentCaptor.capture());
List<Measure> allUpdatedMeasures = measureArgumentCaptor.getAllValues();
assertThat(allUpdatedMeasures, is(notNullValue()));
assertThat(allUpdatedMeasures.size(), is(equalTo(1)));
}

@Test
void testRollbackDoesNothingForNullTempMeasures() throws Exception {
updateQICoreTestCaseStratificationsChangeUnit.setTempMeasures(null);
updateQICoreTestCaseStratificationsChangeUnit.rollbackExecution(measureRepository);
verifyNoInteractions(measureRepository);
}

@Test
void testRollbackDoesNothingForEmptyTempMeasures() throws Exception {
updateQICoreTestCaseStratificationsChangeUnit.setTempMeasures(List.of());
updateQICoreTestCaseStratificationsChangeUnit.rollbackExecution(measureRepository);
verifyNoInteractions(measureRepository);
}

@Test
void testRollbackHandlesRollback() throws Exception {
updateQICoreTestCaseStratificationsChangeUnit.setTempMeasures(
List.of(Measure.builder().build(), Measure.builder().build()));
updateQICoreTestCaseStratificationsChangeUnit.rollbackExecution(measureRepository);
verify(measureRepository, times(2)).save(measureArgumentCaptor.capture());
}
}
Loading

0 comments on commit 31e9f2b

Please sign in to comment.