package it.inaf.oats.vospace; import it.inaf.ia2.aa.data.User; import static it.inaf.oats.vospace.VOSpaceXmlTestUtil.loadDocument; import it.inaf.oats.vospace.persistence.JobDAO; import it.inaf.oats.vospace.persistence.NodeDAO; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.Optional; import net.ivoa.xml.uws.v1.ExecutionPhase; import net.ivoa.xml.uws.v1.JobSummary; import net.ivoa.xml.vospace.v2.DataNode; import net.ivoa.xml.vospace.v2.Node; import net.ivoa.xml.vospace.v2.Property; import net.ivoa.xml.vospace.v2.Protocol; import net.ivoa.xml.vospace.v2.Transfer; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.matchesPattern; import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestPropertySource; import org.springframework.test.web.servlet.MockMvc; 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.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import org.w3c.dom.Document; @SpringBootTest @AutoConfigureMockMvc @ContextConfiguration(classes = {TokenFilterConfig.class}) @TestPropertySource(properties = "spring.main.allow-bean-definition-overriding=true") public class TransferControllerTest { @MockBean private JobDAO jobDao; @MockBean private NodeDAO nodeDao; @MockBean private TapeService tapeService; @Autowired private MockMvc mockMvc; @Test public void testPullFromVoSpaceAsync() throws Exception { Node node = mockPublicDataNode(); when(nodeDao.listNode(eq("/mynode"))).thenReturn(Optional.of(node)); String requestBody = getResourceFileContent("pullFromVoSpace.xml"); String redirect = mockMvc.perform(post("/transfers?PHASE=RUN") .content(requestBody) .contentType(MediaType.APPLICATION_XML) .accept(MediaType.APPLICATION_XML)) .andDo(print()) .andExpect(status().is3xxRedirection()) .andReturn().getResponse().getHeader("Location"); assertThat(redirect, matchesPattern("^/transfers/.*")); } @Test public void testPullFromVoSpaceSync() throws Exception { Node node = mockPublicDataNode(); when(nodeDao.listNode(eq("/mynode"))).thenReturn(Optional.of(node)); String requestBody = getResourceFileContent("pullFromVoSpace.xml"); String redirect = mockMvc.perform(post("/synctrans") .content(requestBody) .contentType(MediaType.APPLICATION_XML) .accept(MediaType.APPLICATION_XML)) .andDo(print()) .andExpect(status().is3xxRedirection()) .andReturn().getResponse().getHeader("Location"); assertThat(redirect, matchesPattern("^/transfers/.*/results/transferDetails")); } @Test public void testPullToVoSpace() throws Exception { String requestBody = getResourceFileContent("pullToVoSpace.xml"); String redirect = mockMvc.perform(post("/transfers?PHASE=RUN") .content(requestBody) .contentType(MediaType.APPLICATION_XML) .accept(MediaType.APPLICATION_XML)) .andDo(print()) .andExpect(status().is3xxRedirection()) .andReturn().getResponse().getHeader("Location"); assertThat(redirect, matchesPattern("^/transfers/.*")); verify(tapeService, times(1)).startJob(any()); } @Test public void testSetJobPhase() throws Exception { Node node = mockPublicDataNode(); when(nodeDao.listNode(eq("/mynode"))).thenReturn(Optional.of(node)); JobSummary job = getFakePendingJob(); when(jobDao.getJob(eq("123"))).thenReturn(Optional.of(job)); User user = new User(); user.setUserId("ownerId"); String redirect = mockMvc.perform(post("/transfers/123/phase") .header("Authorization", "Bearer user1_token") .param("PHASE", "RUN") .accept(MediaType.APPLICATION_XML)) .andDo(print()) .andExpect(status().is3xxRedirection()) .andReturn().getResponse().getHeader("Location"); verify(jobDao, times(1)).updateJob(any()); assertThat(redirect, matchesPattern("^/transfers/.*")); } @Test public void testGetTransferDetails() throws Exception { JobSummary job = getFakePendingJob(); when(jobDao.getJob(eq("123"))).thenReturn(Optional.of(job)); mockMvc.perform(get("/transfers/123/results/transferDetails") .header("Authorization", "Bearer user1_token") .accept(MediaType.APPLICATION_XML)) .andDo(print()) .andExpect(status().isOk()); } @Test public void testGetJobPhase() throws Exception { JobSummary job = getFakePendingJob(); when(jobDao.getJob(eq("123"))).thenReturn(Optional.of(job)); String phase = mockMvc.perform(get("/transfers/123/phase") .header("Authorization", "Bearer user1_token")) .andDo(print()) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(); assertEquals("PENDING", phase); } private Node mockPublicDataNode() { Node node = new DataNode(); Property property = new Property(); property.setUri("ivo://ivoa.net/vospace/core#publicread"); property.setValue("true"); node.getProperties().add(property); return node; } @Test public void testGetJob() throws Exception { JobSummary job = new JobSummary(); when(jobDao.getJob(eq("123"))).thenReturn(Optional.of(job)); String xml = mockMvc.perform(get("/transfers/123") .accept(MediaType.APPLICATION_XML)) .andDo(print()) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(); Document doc = loadDocument(xml); assertEquals("uws:job", doc.getDocumentElement().getNodeName()); verify(jobDao, times(1)).getJob(eq("123")); } private JobSummary getFakePendingJob() { JobSummary job = new JobSummary(); job.setPhase(ExecutionPhase.PENDING); job.setOwnerId("user1"); Transfer transfer = new Transfer(); transfer.setDirection("pullFromVoSpace"); transfer.setTarget("vos://example.com!vospace/mynode"); Protocol protocol = new Protocol(); protocol.setUri("ivo://ivoa.net/vospace/core#httpget"); transfer.getProtocols().add(protocol); JobSummary.JobInfo jobInfo = new JobSummary.JobInfo(); jobInfo.getAny().add(transfer); job.setJobInfo(jobInfo); return job; } protected static String getResourceFileContent(String fileName) throws Exception { try ( InputStream in = TransferControllerTest.class.getClassLoader().getResourceAsStream(fileName)) { return new String(in.readAllBytes(), StandardCharsets.UTF_8); } } }