package gov.samhsa.consent2share.web.controller; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyLong; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.mockito.Mockito.times; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.fileUpload; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; import gov.samhsa.acs.common.validation.XmlValidation; import gov.samhsa.consent2share.common.AuthenticatedUser; import gov.samhsa.consent2share.common.UserContext; import gov.samhsa.consent2share.infrastructure.eventlistener.EventService; import gov.samhsa.consent2share.infrastructure.security.AccessReferenceMapper; import gov.samhsa.consent2share.infrastructure.security.ClamAVClientNotAvailableException; import gov.samhsa.consent2share.infrastructure.security.ClamAVService; import gov.samhsa.consent2share.infrastructure.security.RecaptchaService; import gov.samhsa.consent2share.service.clinicaldata.ClinicalDocumentService; import gov.samhsa.consent2share.service.dto.ClinicalDocumentDto; import gov.samhsa.consent2share.service.dto.LookupDto; import gov.samhsa.consent2share.service.dto.PatientProfileDto; import gov.samhsa.consent2share.service.patient.PatientService; import gov.samhsa.consent2share.service.reference.ClinicalDocumentTypeCodeService; import gov.samhsa.consent2share.web.controller.ClinicalDocumentController; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import org.owasp.esapi.errors.AccessControlException; import org.slf4j.Logger; import org.springframework.mock.web.MockMultipartFile; import org.springframework.test.util.ReflectionTestUtils; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; @RunWith(MockitoJUnitRunner.class) public class ClinicalDocumentControllerTest { @Mock ClinicalDocumentService clinicalDocumentService; @Mock PatientService patientService; @Mock ClinicalDocumentTypeCodeService clinicalDocumentTypeCodeService; @Mock UserContext userContext; @Mock AuthenticatedUser authenticatedUser; @Mock AccessReferenceMapper accessReferenceMapper; @Mock ClamAVService clamAVUtil; @Mock RecaptchaService recaptchaUtil; @Mock XmlValidation xmlValidator; @Mock EventService eventService; @Mock private Logger logger; ClinicalDocumentController sut; ClinicalDocumentController clinicalDocumentController; MockMvc mockMvc; @Before public void before() throws AccessControlException { clinicalDocumentController=new ClinicalDocumentController(clinicalDocumentService, patientService, clinicalDocumentTypeCodeService, userContext, accessReferenceMapper, clamAVUtil, recaptchaUtil, eventService, xmlValidator); ReflectionTestUtils.setField(clinicalDocumentController, "logger", logger); sut=spy(clinicalDocumentController); mockMvc = MockMvcBuilders.standaloneSetup( this.sut).build(); doReturn((long)1).when(accessReferenceMapper).getDirectReference("ScrambledText"); when(userContext.getCurrentUser()).thenReturn(authenticatedUser); when(authenticatedUser.getUsername()).thenReturn("albert.smith"); } @Test public void testDocumentHome() throws Exception { mockMvc.perform(get("/patients/medicalinfo.html")).andExpect( view().name("views/clinicaldocuments/mymedicalinfo")); } @Test public void testShowClinicalDocuments() throws Exception { PatientProfileDto patientProfileDto = mock(PatientProfileDto.class); List<ClinicalDocumentDto> clinicaldocumentDtos = new ArrayList<ClinicalDocumentDto>(); ClinicalDocumentDto notNullClinicalDocumentDto=mock(ClinicalDocumentDto.class); LookupDto lookupDto=mock(LookupDto.class); when(notNullClinicalDocumentDto.getClinicalDocumentTypeCode()).thenReturn(lookupDto); clinicaldocumentDtos.add(notNullClinicalDocumentDto); for (int i = 0; i < 3; i++) { ClinicalDocumentDto clinicalDocumentDto = mock(ClinicalDocumentDto.class); clinicaldocumentDtos.add(clinicalDocumentDto); } List<LookupDto> allDocumentTypeCodes = new ArrayList<LookupDto>(); for (int i = 0; i < 3; i++) { LookupDto clinicalDocumentTypeCode = mock(LookupDto.class); allDocumentTypeCodes.add(clinicalDocumentTypeCode); } when(patientService.findPatientProfileByUsername(anyString())) .thenReturn(patientProfileDto); when(clinicalDocumentService.findDtoByPatientDto(patientProfileDto)) .thenReturn(clinicaldocumentDtos); when(clinicalDocumentTypeCodeService.findAllClinicalDocumentTypeCodes()) .thenReturn(allDocumentTypeCodes); mockMvc.perform(get("/patients/clinicaldocuments.html")).andExpect( view().name("views/clinicaldocuments/secureClinicalDocuments")); } @Test public void testDownload_when_authentication_succeeds() throws Exception { ClinicalDocumentDto clinicalDocumentDto = mock(ClinicalDocumentDto.class); String s = "mock string"; byte[] byteArray = s.getBytes(); when(clinicalDocumentService.findClinicalDocumentDto(anyLong())) .thenReturn(clinicalDocumentDto); when( clinicalDocumentService .isDocumentBelongsToThisUser(clinicalDocumentDto)) .thenReturn(true); when(clinicalDocumentDto.getContent()).thenReturn(byteArray); mockMvc.perform( post("/patients/downloaddoc.html").param("download_id", "ScrambledText")) .andExpect(status().isOk()) .andExpect(header().string("Content-Type", "application/null")); } @Test public void testDownload_when_authentication_fails() throws Exception { ClinicalDocumentDto clinicalDocumentDto = mock(ClinicalDocumentDto.class); String s = "mock string"; byte[] byteArray = s.getBytes(); when(clinicalDocumentService.findClinicalDocumentDto(anyLong())) .thenReturn(clinicalDocumentDto); when( clinicalDocumentService .isDocumentBelongsToThisUser(clinicalDocumentDto)) .thenReturn(false); when(clinicalDocumentDto.getContent()).thenReturn(byteArray); mockMvc.perform( post("/patients/downloaddoc.html").param("download_id", "ScrambledText")) .andExpect(status().isOk()); verify(clinicalDocumentDto,never()).getContent(); } @Test public void testRemove_when_authentication_fails() throws Exception { ClinicalDocumentDto clinicalDocumentDto = mock(ClinicalDocumentDto.class); when(clinicalDocumentService.findClinicalDocumentDto(anyLong())) .thenReturn(clinicalDocumentDto); when( clinicalDocumentService .isDocumentBelongsToThisUser(clinicalDocumentDto)) .thenReturn(false); mockMvc.perform( post("/patients/deletedoc.html").param("delete_id", "ScrambledText")) .andExpect(redirectedUrl("/patients/clinicaldocuments.html")); verify (clinicalDocumentService,never()).deleteClinicalDocument(any(ClinicalDocumentDto.class)); } @Test public void testRemove_when_authentication_succeeds() throws Exception { ClinicalDocumentDto clinicalDocumentDto = mock(ClinicalDocumentDto.class); when(clinicalDocumentService.findClinicalDocumentDto(anyLong())) .thenReturn(clinicalDocumentDto); when( clinicalDocumentService .isDocumentBelongsToThisUser(clinicalDocumentDto)) .thenReturn(true); mockMvc.perform( post("/patients/deletedoc.html").param("delete_id", "ScrambledText")) .andExpect(redirectedUrl("/patients/clinicaldocuments.html")); verify (clinicalDocumentService).deleteClinicalDocument(any(ClinicalDocumentDto.class)); } @Test public void testSecureClinicalDocumentsUploadWhenAllChecksSucced() throws Exception { MockMultipartFile file = new MockMultipartFile("file", "orig", null, "bar".getBytes()); doReturn(true).when(xmlValidator).validate(any(InputStream.class)); doReturn("true").when(sut).scanMultipartFile(file); doReturn(false).when(clinicalDocumentService).isDocumentOversized(file); doReturn(true).when(clinicalDocumentService).isDocumentExtensionPermitted(file); doReturn(true).when(recaptchaUtil).checkAnswer(anyString(), anyString(), anyString()); mockMvc.perform(fileUpload("/patients/clinicaldocuments.html").file(file) .param("name", "mocked_name") .param("description", "mocked_description") .param("documentType", "mocked_type") .param("recaptcha_challenge_field", "recaptcha_challenge_field") .param("recaptcha_response_field", "recaptcha_response_field")) .andExpect(view().name("redirect:/patients/clinicaldocuments.html")); } // @Test // public void testSecureClinicalDocumentsUploadWhenFileIsMalicious() throws Exception { // MockMultipartFile file = new MockMultipartFile("file", "orig", null, "bar".getBytes()); // doReturn("false").when(sut).scanMultipartFile(file); // doReturn(false).when(clinicalDocumentService).isDocumentOversized(file); // doReturn(true).when(clinicalDocumentService).isDocumentExtensionPermitted(file); // doReturn(true).when(recaptchaUtil).checkAnswer(anyString(), anyString(), anyString()); // mockMvc.perform(fileUpload("/patients/clinicaldocuments.html").file(file) // .param("name", "mocked_name") // .param("description", "mocked_description") // .param("documentType", "mocked_type")) // .andExpect(view().name("redirect:/patients/clinicaldocuments.html?notify=virus_detected")); // } /*@Test public void testSecureClinicalDocumentsUploadWhenClamAVNotWork() throws Exception { MockMultipartFile file = new MockMultipartFile("file", "orig", null, "bar".getBytes()); doReturn("error").when(sut).scanMultipartFile(file); doReturn(false).when(clinicalDocumentService).isDocumentOversized(file); doReturn(true).when(clinicalDocumentService).isDocumentExtensionPermitted(file); doReturn(true).when(recaptchaUtil).checkAnswer(anyString(), anyString(), anyString()); mockMvc.perform(fileUpload("/patients/clinicaldocuments.html").file(file) .param("name", "mocked_name") .param("description", "mocked_description") .param("documentType", "mocked_type")) .andExpect(view().name("redirect:/patients/clinicaldocuments.html?notify=error")); } @Test public void testSecureClinicalDocumentsUploadWhenClamAVNotWork_Throws_ClamAVClientNotAvailableException() throws Exception { MockMultipartFile file = new MockMultipartFile("file", "orig", null, "bar".getBytes()); when(clamAVUtil.fileScanner(any(InputStream.class))).thenThrow(ClamAVClientNotAvailableException.class); doReturn(false).when(clinicalDocumentService).isDocumentOversized(file); doReturn(true).when(clinicalDocumentService).isDocumentExtensionPermitted(file); doReturn(true).when(recaptchaUtil).checkAnswer(anyString(), anyString(), anyString()); mockMvc.perform(fileUpload("/patients/clinicaldocuments.html").file(file) .param("name", "mocked_name") .param("description", "mocked_description") .param("documentType", "mocked_type")) .andExpect(view().name("redirect:/patients/clinicaldocuments.html?notify=error")); verify(logger, times(1)).error(anyString()); } @Test public void testSecureClinicalDocumentsUploadWhenClamAVNotWork_Throws_Exception() throws Exception { MockMultipartFile file = new MockMultipartFile("file", "orig", null, "bar".getBytes()); when(clamAVUtil.fileScanner(any(InputStream.class))).thenThrow(Exception.class); doReturn(false).when(clinicalDocumentService).isDocumentOversized(file); doReturn(true).when(clinicalDocumentService).isDocumentExtensionPermitted(file); doReturn(true).when(recaptchaUtil).checkAnswer(anyString(), anyString(), anyString()); mockMvc.perform(fileUpload("/patients/clinicaldocuments.html").file(file) .param("name", "mocked_name") .param("description", "mocked_description") .param("documentType", "mocked_type")) .andExpect(view().name("redirect:/patients/clinicaldocuments.html?notify=error")); verify(logger, times(1)).error(anyString()); }*/ @Test public void testSecureClinicalDocumentsUploadWhenFileIsOversized() throws Exception { MockMultipartFile file = new MockMultipartFile("file", "orig", null, "bar".getBytes()); doReturn("true").when(sut).scanMultipartFile(file); doReturn(true).when(clinicalDocumentService).isDocumentOversized(file); doReturn(true).when(clinicalDocumentService).isDocumentExtensionPermitted(file); doReturn(true).when(recaptchaUtil).checkAnswer(anyString(), anyString(), anyString()); mockMvc.perform(fileUpload("/patients/clinicaldocuments.html").file(file) .param("name", "mocked_name") .param("description", "mocked_description") .param("documentType", "mocked_type")) .andExpect(view().name("redirect:/patients/clinicaldocuments.html?notify=size_over_limits")); } @Test public void testSecureClinicalDocumentsUploadWhenFileExtensionIsNotPermitted() throws Exception { MockMultipartFile file = new MockMultipartFile("file", "orig", null, "bar".getBytes()); doReturn("true").when(sut).scanMultipartFile(file); doReturn(false).when(clinicalDocumentService).isDocumentOversized(file); doReturn(false).when(clinicalDocumentService).isDocumentExtensionPermitted(file); doReturn(true).when(recaptchaUtil).checkAnswer(anyString(), anyString(), anyString()); mockMvc.perform(fileUpload("/patients/clinicaldocuments.html").file(file) .param("name", "mocked_name") .param("description", "mocked_description") .param("documentType", "mocked_type")) .andExpect(view().name("redirect:/patients/clinicaldocuments.html?notify=extension_not_permitted")); } @Test public void testSecureClinicalDocumentsUploadWhenWrongCaptchaIsEnterred() throws Exception { MockMultipartFile file = new MockMultipartFile("file", "orig", null, "bar".getBytes()); doReturn("true").when(sut).scanMultipartFile(file); doReturn(false).when(clinicalDocumentService).isDocumentOversized(file); doReturn(true).when(clinicalDocumentService).isDocumentExtensionPermitted(file); doReturn(false).when(recaptchaUtil).checkAnswer(anyString(), anyString(), anyString()); mockMvc.perform(fileUpload("/patients/clinicaldocuments.html").file(file) .param("name", "mocked_name") .param("description", "mocked_description") .param("documentType", "mocked_type")) .andExpect(view().name("redirect:/patients/clinicaldocuments.html?notify=wrong_captcha")); } @Test public void testScanMultipartFileWhenFileIsClean() throws Exception { MockMultipartFile file = new MockMultipartFile("file", "orig", null, "bar".getBytes()); doReturn(true).when(clamAVUtil).fileScanner(any(InputStream.class)); assertTrue(clinicalDocumentController.scanMultipartFile(file).toString().equals("true")); } @Test public void testScanMultipartFileWhenFileIsNotClean() throws Exception { MockMultipartFile file = new MockMultipartFile("file", "orig", null, "bar".getBytes()); doReturn(false).when(clamAVUtil).fileScanner(any(InputStream.class)); assertFalse(clinicalDocumentController.scanMultipartFile(file).toString().equals("true")); } @Test public void testShowSecureClinicalDocuments() throws Exception { PatientProfileDto patientProfileDto = mock(PatientProfileDto.class); List<ClinicalDocumentDto> clinicaldocumentDtos = new ArrayList<ClinicalDocumentDto>(); ClinicalDocumentDto notNullClinicalDocumentDto=mock(ClinicalDocumentDto.class); LookupDto lookupDto=mock(LookupDto.class); when(notNullClinicalDocumentDto.getClinicalDocumentTypeCode()).thenReturn(lookupDto); clinicaldocumentDtos.add(notNullClinicalDocumentDto); for (int i = 0; i < 3; i++) { ClinicalDocumentDto clinicalDocumentDto = mock(ClinicalDocumentDto.class); clinicaldocumentDtos.add(clinicalDocumentDto); } List<LookupDto> allDocumentTypeCodes = new ArrayList<LookupDto>(); for (int i = 0; i < 3; i++) { LookupDto clinicalDocumentTypeCode = mock(LookupDto.class); allDocumentTypeCodes.add(clinicalDocumentTypeCode); } when(patientService.findPatientProfileByUsername(anyString())) .thenReturn(patientProfileDto); when(clinicalDocumentService.findDtoByPatientDto(patientProfileDto)) .thenReturn(clinicaldocumentDtos); when(clinicalDocumentTypeCodeService.findAllClinicalDocumentTypeCodes()) .thenReturn(allDocumentTypeCodes); mockMvc.perform(get("/patients/clinicaldocuments.html")).andExpect( view().name("views/clinicaldocuments/secureClinicalDocuments")); } }