Skip to content

Commit a44512d

Browse files
authored
Merge branch 'develop' into feature/MAT-8786/filter-on-cms-id
2 parents 049ed01 + 2d75acf commit a44512d

3 files changed

Lines changed: 294 additions & 4 deletions

File tree

src/main/java/cms/gov/madie/measure/resources/AdminController.java

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
public class AdminController {
4747
private final MeasureService measureService;
4848
private final TestCaseService testCaseService;
49+
private final TestCaseValidationService testCaseValidationService;
4950
private final MeasureSetService measureSetService;
5051
private final ActionLogService actionLogService;
5152
private final VersionService versionService;
@@ -123,6 +124,63 @@ public ResponseEntity<MeasureTestCaseValidationReportSummary> validateAllMeasure
123124
.build());
124125
}
125126

127+
// This endpoint is used to reset the validation queue for QI Core v6 measures test cases
128+
// that are in validating state
129+
@PutMapping("/measures/test-cases/restart-validation")
130+
@PreAuthorize("#request.getHeader('api-key') == #apiKey")
131+
public void resetTestCaseValidationQueue(
132+
HttpServletRequest request,
133+
@Value("${admin-api-key}") String apiKey,
134+
Principal principal,
135+
@RequestHeader("Authorization") String accessToken) {
136+
137+
log.info(
138+
"User [{}] - Starting admin task to place QI Core v6 testcases back on the validation queue",
139+
principal.getName());
140+
List<Measure> measureList =
141+
measureRepository.findAllByModel(ModelType.QI_CORE_6_0_0.getValue());
142+
143+
if (CollectionUtils.isNotEmpty(measureList)) {
144+
measureList.forEach(
145+
measure -> {
146+
if (CollectionUtils.isNotEmpty(measure.getTestCases())) {
147+
measure
148+
.getTestCases()
149+
.forEach(
150+
testCase -> {
151+
if (TestCaseValidationStatus.PENDING
152+
.toString()
153+
.equalsIgnoreCase(testCase.getValidationStatus())) {
154+
// Submit test case already in PENDING status
155+
testCaseValidationService.submitOnSaveValidationTask(
156+
measure.getId(),
157+
testCase,
158+
accessToken,
159+
ModelType.valueOfName(measure.getModel()));
160+
} else if (TestCaseValidationStatus.VALIDATING
161+
.toString()
162+
.equalsIgnoreCase(testCase.getValidationStatus())) {
163+
Measure updatedMeasure =
164+
measureRepository.setValidationStatusToPending(
165+
testCase.getId(), measure.getId());
166+
if (updatedMeasure != null) {
167+
// submit the test case after updating its status
168+
testCaseValidationService.submitOnSaveValidationTask(
169+
measure.getId(),
170+
testCase,
171+
accessToken,
172+
ModelType.valueOfName(measure.getModel()));
173+
}
174+
}
175+
});
176+
}
177+
});
178+
log.info(
179+
"User [{}] - Successfully placed QI Core v6 test cases back on the validation queue",
180+
principal.getName());
181+
}
182+
}
183+
126184
@DeleteMapping("/measures/{id}")
127185
@PreAuthorize("#request.getHeader('api-key') == #apiKey")
128186
public ResponseEntity<Measure> permDeleteMeasure(

src/main/java/cms/gov/madie/measure/services/TestCaseValidationService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public void populateValidationQueue() {
6666
// as "Pending" in the database.
6767
}
6868

69-
void submitOnSaveValidationTask(
69+
public void submitOnSaveValidationTask(
7070
String measureId, TestCase testCase, String accessToken, ModelType modelType) {
7171
UUID taskId = UUID.randomUUID();
7272
log.info(

src/test/java/cms/gov/madie/measure/resources/AdminControllerMvcTest.java

Lines changed: 235 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,7 @@
1212
import gov.cms.madie.models.access.RoleEnum;
1313
import gov.cms.madie.models.common.ModelType;
1414
import gov.cms.madie.models.common.Version;
15-
import gov.cms.madie.models.measure.Measure;
16-
import gov.cms.madie.models.measure.MeasureMetaData;
17-
import gov.cms.madie.models.measure.MeasureSet;
15+
import gov.cms.madie.models.measure.*;
1816
import org.junit.jupiter.api.Test;
1917
import org.springframework.beans.factory.annotation.Autowired;
2018
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
@@ -24,11 +22,13 @@
2422
import org.springframework.test.web.servlet.MockMvc;
2523
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
2624

25+
import java.util.Collections;
2726
import java.util.List;
2827
import java.util.Set;
2928

3029
import static org.hamcrest.Matchers.empty;
3130
import static org.hamcrest.Matchers.equalTo;
31+
import static org.junit.jupiter.api.Assertions.assertEquals;
3232
import static org.mockito.ArgumentMatchers.any;
3333
import static org.mockito.ArgumentMatchers.anyString;
3434
import static org.mockito.ArgumentMatchers.eq;
@@ -49,6 +49,7 @@ public class AdminControllerMvcTest {
4949
@MockitoBean private MeasureService measureService;
5050
@MockitoBean private MeasureSetService measureSetService;
5151
@MockitoBean private TestCaseService testCaseService;
52+
@MockitoBean private TestCaseValidationService testCaseValidationService;
5253
@MockitoBean private ActionLogService actionLogService;
5354
@MockitoBean private VersionService versionService;
5455

@@ -722,4 +723,235 @@ public void testAdminMeasureChangeVersionSuccessfully() throws Exception {
722723
.findAllByMeasureSetIdInAndActiveAndMeasureMetaDataDraft(List.of("ms-123"), true, true);
723724
verify(measureRepository, times(1)).findAllByMeasureSetIdAndActive("ms-123", true);
724725
}
726+
727+
@Test
728+
public void updateTestCaseValidationStatusProcessesValidatingTestCases() throws Exception {
729+
Measure measure =
730+
Measure.builder()
731+
.id("M1")
732+
.model(ModelType.QI_CORE_6_0_0.getValue())
733+
.testCases(
734+
List.of(
735+
TestCase.builder()
736+
.id("TC1")
737+
.validationStatus(TestCaseValidationStatus.VALIDATING.toString())
738+
.build()))
739+
.build();
740+
741+
when(measureRepository.findAllByModel(ModelType.QI_CORE_6_0_0.getValue()))
742+
.thenReturn(List.of(measure));
743+
744+
doAnswer(
745+
invocation -> {
746+
String testCaseId = invocation.getArgument(0, String.class);
747+
String measureId = invocation.getArgument(1, String.class);
748+
if ("TC1".equals(testCaseId) && "M1".equals(measureId)) {
749+
measure
750+
.getTestCases()
751+
.get(0)
752+
.setValidationStatus(TestCaseValidationStatus.PENDING.toString());
753+
}
754+
return measure;
755+
})
756+
.when(measureRepository)
757+
.setValidationStatusToPending(anyString(), anyString());
758+
759+
mockMvc
760+
.perform(
761+
MockMvcRequestBuilders.put("/admin/measures/test-cases/restart-validation")
762+
.with(csrf())
763+
.with(user(TEST_USER_ID))
764+
.header(ADMIN_TEST_API_KEY_HEADER, ADMIN_TEST_API_KEY_HEADER_VALUE)
765+
.header("Authorization", "test-okta"))
766+
.andExpect(status().isOk());
767+
768+
verify(testCaseValidationService, times(1))
769+
.submitOnSaveValidationTask(
770+
eq("M1"),
771+
eq(measure.getTestCases().get(0)),
772+
eq("test-okta"),
773+
eq(ModelType.QI_CORE_6_0_0));
774+
assertEquals(
775+
TestCaseValidationStatus.PENDING.toString(),
776+
measure.getTestCases().get(0).getValidationStatus());
777+
}
778+
779+
@Test
780+
public void updateTestCaseValidationStatusProcessesPendingTestCases() throws Exception {
781+
Measure measure =
782+
Measure.builder()
783+
.id("M1")
784+
.model(ModelType.QI_CORE_6_0_0.getValue())
785+
.testCases(
786+
List.of(
787+
TestCase.builder()
788+
.id("TC1")
789+
.validationStatus(TestCaseValidationStatus.PENDING.toString())
790+
.build()))
791+
.build();
792+
793+
when(measureRepository.findAllByModel(ModelType.QI_CORE_6_0_0.getValue()))
794+
.thenReturn(List.of(measure));
795+
796+
mockMvc
797+
.perform(
798+
MockMvcRequestBuilders.put("/admin/measures/test-cases/restart-validation")
799+
.with(csrf())
800+
.with(user(TEST_USER_ID))
801+
.header(ADMIN_TEST_API_KEY_HEADER, ADMIN_TEST_API_KEY_HEADER_VALUE)
802+
.header("Authorization", "test-okta"))
803+
.andExpect(status().isOk());
804+
805+
verify(testCaseValidationService, times(1))
806+
.submitOnSaveValidationTask(
807+
eq("M1"), any(TestCase.class), eq("test-okta"), eq(ModelType.QI_CORE_6_0_0));
808+
}
809+
810+
@Test
811+
public void updateTestCaseValidationStatusSkipsNonValidatingOrPendingTestCases()
812+
throws Exception {
813+
Measure measure =
814+
Measure.builder()
815+
.id("M1")
816+
.model(ModelType.QI_CORE_6_0_0.getValue())
817+
.testCases(
818+
List.of(
819+
TestCase.builder()
820+
.id("TC1")
821+
.validationStatus(TestCaseValidationStatus.INVALID.toString())
822+
.build()))
823+
.build();
824+
825+
when(measureRepository.findAllByModel(ModelType.QI_CORE_6_0_0.getValue()))
826+
.thenReturn(List.of(measure));
827+
828+
mockMvc
829+
.perform(
830+
MockMvcRequestBuilders.put("/admin/measures/test-cases/restart-validation")
831+
.with(csrf())
832+
.with(user(TEST_USER_ID))
833+
.header(ADMIN_TEST_API_KEY_HEADER, ADMIN_TEST_API_KEY_HEADER_VALUE)
834+
.header("Authorization", "test-okta"))
835+
.andExpect(status().isOk());
836+
837+
verify(testCaseValidationService, never())
838+
.submitOnSaveValidationTask(
839+
anyString(), any(TestCase.class), anyString(), any(ModelType.class));
840+
}
841+
842+
@Test
843+
public void updateTestCaseValidationStatusHandlesEmptyMeasureList() throws Exception {
844+
when(measureRepository.findAllByModel(ModelType.QI_CORE_6_0_0.getValue()))
845+
.thenReturn(Collections.emptyList());
846+
847+
mockMvc
848+
.perform(
849+
MockMvcRequestBuilders.put("/admin/measures/test-cases/restart-validation")
850+
.with(csrf())
851+
.with(user(TEST_USER_ID))
852+
.header(ADMIN_TEST_API_KEY_HEADER, ADMIN_TEST_API_KEY_HEADER_VALUE)
853+
.header("Authorization", "test-okta"))
854+
.andExpect(status().isOk());
855+
856+
verifyNoInteractions(testCaseValidationService);
857+
}
858+
859+
@Test
860+
public void updateTestCaseValidationStatusHandlesMeasuresWithoutTestCases() throws Exception {
861+
Measure measure =
862+
Measure.builder()
863+
.id("M1")
864+
.model(ModelType.QI_CORE_6_0_0.getValue())
865+
.testCases(Collections.emptyList())
866+
.build();
867+
868+
when(measureRepository.findAllByModel(ModelType.QI_CORE_6_0_0.getValue()))
869+
.thenReturn(List.of(measure));
870+
871+
mockMvc
872+
.perform(
873+
MockMvcRequestBuilders.put("/admin/measures/test-cases/restart-validation")
874+
.with(csrf())
875+
.with(user(TEST_USER_ID))
876+
.header(ADMIN_TEST_API_KEY_HEADER, ADMIN_TEST_API_KEY_HEADER_VALUE)
877+
.header("Authorization", "test-okta"))
878+
.andExpect(status().isOk());
879+
880+
verifyNoInteractions(testCaseValidationService);
881+
}
882+
883+
@Test
884+
public void updateTestCaseValidationStatusProcessesMultipleTestCasesWithDifferentStatuses()
885+
throws Exception {
886+
Measure measure =
887+
Measure.builder()
888+
.id("M1")
889+
.model(ModelType.QI_CORE_6_0_0.getValue())
890+
.testCases(
891+
List.of(
892+
TestCase.builder()
893+
.id("TC1")
894+
.validationStatus(TestCaseValidationStatus.VALIDATING.toString())
895+
.build(),
896+
TestCase.builder()
897+
.id("TC2")
898+
.validationStatus(TestCaseValidationStatus.PENDING.toString())
899+
.build(),
900+
TestCase.builder()
901+
.id("TC3")
902+
.validationStatus(TestCaseValidationStatus.INVALID.toString())
903+
.build()))
904+
.build();
905+
906+
when(measureRepository.findAllByModel(ModelType.QI_CORE_6_0_0.getValue()))
907+
.thenReturn(List.of(measure));
908+
909+
// Mock the repository behavior to update the validation status to PENDING
910+
doAnswer(
911+
invocation -> {
912+
String testCaseId = invocation.getArgument(0, String.class);
913+
String measureId = invocation.getArgument(1, String.class);
914+
if ("TC1".equals(testCaseId) && "M1".equals(measureId)) {
915+
measure
916+
.getTestCases()
917+
.get(0)
918+
.setValidationStatus(TestCaseValidationStatus.PENDING.toString());
919+
}
920+
return null;
921+
})
922+
.when(measureRepository)
923+
.setValidationStatusToPending(anyString(), anyString());
924+
925+
mockMvc
926+
.perform(
927+
MockMvcRequestBuilders.put("/admin/measures/test-cases/restart-validation")
928+
.with(csrf())
929+
.with(user(TEST_USER_ID))
930+
.header(ADMIN_TEST_API_KEY_HEADER, ADMIN_TEST_API_KEY_HEADER_VALUE)
931+
.header("Authorization", "test-okta"))
932+
.andExpect(status().isOk());
933+
934+
verify(testCaseValidationService, times(1))
935+
.submitOnSaveValidationTask(
936+
eq("M1"),
937+
eq(measure.getTestCases().get(1)),
938+
eq("test-okta"),
939+
eq(ModelType.QI_CORE_6_0_0));
940+
verify(testCaseValidationService, never())
941+
.submitOnSaveValidationTask(
942+
eq("M1"),
943+
eq(measure.getTestCases().get(2)),
944+
eq("test-okta"),
945+
eq(ModelType.QI_CORE_6_0_0));
946+
947+
assertEquals(
948+
TestCaseValidationStatus.PENDING.toString(),
949+
measure.getTestCases().get(0).getValidationStatus());
950+
assertEquals(
951+
TestCaseValidationStatus.PENDING.toString(),
952+
measure.getTestCases().get(1).getValidationStatus());
953+
assertEquals(
954+
TestCaseValidationStatus.INVALID.toString(),
955+
measure.getTestCases().get(2).getValidationStatus());
956+
}
725957
}

0 commit comments

Comments
 (0)