/* * This file is part of vospace-file-service * Copyright (C) 2021 Istituto Nazionale di Astrofisica * SPDX-License-Identifier: GPL-3.0-or-later */ package it.inaf.ia2.transfer.controller; import it.inaf.ia2.transfer.persistence.FileDAO; import it.inaf.ia2.transfer.persistence.JobDAO; import it.inaf.ia2.transfer.persistence.ListOfFilesDAO; import java.io.File; import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.util.Collections; import java.util.Optional; import java.util.UUID; import net.ivoa.xml.uws.v1.ExecutionPhase; import org.assertj.core.util.Files; import org.junit.jupiter.api.AfterAll; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.argThat; 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.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockMultipartFile; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMultipartHttpServletRequestBuilder; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.request.RequestPostProcessor; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import org.springframework.util.FileSystemUtils; @SpringBootTest @AutoConfigureMockMvc public class PutFileControllerTest { @MockBean private FileDAO fileDao; @MockBean private JobDAO jobDAO; @MockBean private ListOfFilesDAO listOfFilesDAO; @Autowired private MockMvc mockMvc; private static File temporaryDirectory; @BeforeAll public static void setUp() { temporaryDirectory = Files.newTemporaryFolder(); } @AfterAll public static void tearDown() { FileSystemUtils.deleteRecursively(temporaryDirectory); } @Test public void putGenericFile() throws Exception { String randomFileName = UUID.randomUUID().toString(); createBaseFileInfo(randomFileName); MockMultipartFile fakeFile = new MockMultipartFile("file", "test.txt", "text/plain", "content".getBytes()); mockMvc.perform(putMultipart("/path/to/test.txt") .file(fakeFile)) .andDo(print()) .andExpect(status().isOk()); File file = Path.of(getTestFilePath(randomFileName)).toFile(); assertTrue(file.exists()); assertEquals("content", Files.contentOf(file, StandardCharsets.UTF_8)); assertTrue(file.delete()); } @Test public void putGenericFileWithNameConflictExtension() throws Exception { putGenericFileWithNameConflict("test.txt", "test-1.txt", "test-2.txt"); } @Test public void putGenericFileWithNameConflictNoExtension() throws Exception { putGenericFileWithNameConflict("test", "test-1", "test-2"); } public void putGenericFileWithNameConflict(String name1, String name2, String name3) throws Exception { createBaseFileInfo(name1); MockMultipartFile fakeFile = new MockMultipartFile("file", "test.txt", "text/plain", "content".getBytes()); mockMvc.perform(putMultipart("/path/to/test.txt") .file(fakeFile)) .andDo(print()) .andExpect(status().isOk()); File file = Path.of(getTestFilePath(name1)).toFile(); assertTrue(file.exists()); assertEquals("content", Files.contentOf(file, StandardCharsets.UTF_8)); MockMultipartFile fakeFile2 = new MockMultipartFile("file", "test.txt", "text/plain", "content2".getBytes()); mockMvc.perform(putMultipart("/path/to/test.txt") .file(fakeFile2)) .andDo(print()) .andExpect(status().isOk()); File file2 = Path.of(getTestFilePath(name2)).toFile(); assertTrue(file2.exists()); assertEquals("content2", Files.contentOf(file2, StandardCharsets.UTF_8)); MockMultipartFile fakeFile3 = new MockMultipartFile("file", "test.txt", "text/plain", "content3".getBytes()); mockMvc.perform(putMultipart("/path/to/test.txt") .file(fakeFile3)) .andDo(print()) .andExpect(status().isOk()); File file3 = Path.of(getTestFilePath(name3)).toFile(); assertTrue(file3.exists()); assertEquals("content3", Files.contentOf(file3, StandardCharsets.UTF_8)); assertTrue(file.delete()); assertTrue(file2.delete()); assertTrue(file3.delete()); } @Test public void putGenericFileWithJobId() throws Exception { when(jobDAO.isJobExisting("pippo10")).thenReturn(false); when(jobDAO.isJobExisting("pippo5")).thenReturn(true); String randomFileName = UUID.randomUUID().toString(); createBaseFileInfo(randomFileName); MockMultipartFile fakeFile = new MockMultipartFile("file", "test.txt", "text/plain", "content".getBytes()); // Try with invalid jobid mockMvc.perform(putMultipart("/path/to/test.txt") .file(fakeFile).param("jobid", "pippo10")) .andDo(print()) .andExpect(status().is4xxClientError()); verify(jobDAO, times(1)).isJobExisting(eq("pippo10")); // Retry with valid jobid mockMvc.perform(putMultipart("/path/to/test.txt") .file(fakeFile).param("jobid", "pippo5")) .andDo(print()) .andExpect(status().is2xxSuccessful()); verify(jobDAO, times(1)).isJobExisting(eq("pippo5")); verify(jobDAO, times(1)).updateJobPhase(eq(ExecutionPhase.COMPLETED), any()); File file = Path.of(getTestFilePath(randomFileName)).toFile(); assertTrue(file.exists()); assertEquals("content", Files.contentOf(file, StandardCharsets.UTF_8)); assertTrue(file.delete()); } @Test public void putListOfFiles() throws Exception { String randomFileName = UUID.randomUUID().toString(); FileInfo fileInfo = createBaseFileInfo(randomFileName); fileInfo.setAcceptViews(Collections.singletonList("urn:list-of-files")); String content = "/path/to/file1\n/path/to/file2"; MockMultipartFile fakeFile = new MockMultipartFile("file", "test.txt", "text/plain", content.getBytes()); mockMvc.perform(putMultipart("/path/to/test.txt") .file(fakeFile)) .andDo(print()) .andExpect(status().isOk()); verify(listOfFilesDAO, times(1)).createList(any(), argThat(list -> list.size() == 2)); } private FileInfo createBaseFileInfo(String fileName) { FileInfo fileInfo = new FileInfo(); fileInfo.setOsPath(getTestFilePath(fileName)); fileInfo.setIsPublic(false); when(fileDao.getFileInfo(any())).thenReturn(Optional.of(fileInfo)); return fileInfo; } private String getTestFilePath(String fileName) { return temporaryDirectory.toPath().resolve(fileName).toFile().getAbsolutePath(); } private MockMultipartHttpServletRequestBuilder putMultipart(String uri) { MockMultipartHttpServletRequestBuilder builder = MockMvcRequestBuilders.multipart(uri); builder.with(new RequestPostProcessor() { @Override public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) { request.setMethod("PUT"); return request; } }); return builder; } }