package cn.iocoder.yudao.module.infra.service.file; import cn.hutool.core.io.resource.ResourceUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; import cn.iocoder.yudao.framework.test.core.util.AssertUtils; import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FilePageReqVO; import cn.iocoder.yudao.module.infra.dal.dataobject.file.FileDO; import cn.iocoder.yudao.module.infra.dal.mysql.file.FileMapper; import cn.iocoder.yudao.module.infra.framework.file.core.client.FileClient; import jakarta.annotation.Resource; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.context.annotation.Import; import org.springframework.test.context.bean.override.mockito.MockitoBean; import java.time.LocalDateTime; import java.util.concurrent.atomic.AtomicReference; import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.FILE_NOT_EXISTS; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.same; import static org.mockito.Mockito.*; @Import({FileServiceImpl.class}) public class FileServiceImplTest extends BaseDbUnitTest { @Resource private FileServiceImpl fileService; @Resource private FileMapper fileMapper; @MockitoBean private FileConfigService fileConfigService; @BeforeEach public void setUp() { FileServiceImpl.PATH_PREFIX_DATE_ENABLE = true; FileServiceImpl.PATH_SUFFIX_TIMESTAMP_ENABLE = true; FileServiceImpl.PATH_SUFFIX_AS_DIRECTORY = true; } @Test public void testGetFilePage() { // mock 数据 FileDO dbFile = randomPojo(FileDO.class, o -> { // 等会查询到 o.setPath("yunai"); o.setType("image/jpg"); o.setCreateTime(buildTime(2021, 1, 15)); }); fileMapper.insert(dbFile); // 测试 path 不匹配 fileMapper.insert(ObjectUtils.cloneIgnoreId(dbFile, o -> o.setPath("tudou"))); // 测试 type 不匹配 fileMapper.insert(ObjectUtils.cloneIgnoreId(dbFile, o -> { o.setType("image/png"); })); // 测试 createTime 不匹配 fileMapper.insert(ObjectUtils.cloneIgnoreId(dbFile, o -> { o.setCreateTime(buildTime(2020, 1, 15)); })); // 准备参数 FilePageReqVO reqVO = new FilePageReqVO(); reqVO.setPath("yunai"); reqVO.setType("jp"); reqVO.setCreateTime((new LocalDateTime[]{buildTime(2021, 1, 10), buildTime(2021, 1, 20)})); // 调用 PageResult pageResult = fileService.getFilePage(reqVO); // 断言 assertEquals(1, pageResult.getTotal()); assertEquals(1, pageResult.getList().size()); AssertUtils.assertPojoEquals(dbFile, pageResult.getList().get(0)); } /** * content、name、directory、type 都非空 */ @Test public void testCreateFile_success_01() throws Exception { // 准备参数 byte[] content = ResourceUtil.readBytes("file/erweima.jpg"); String name = "单测文件名"; String directory = randomString(); String type = "image/jpeg"; // mock Master 文件客户端 FileClient client = mock(FileClient.class); when(fileConfigService.getMasterFileClient()).thenReturn(client); String url = randomString(); AtomicReference pathRef = new AtomicReference<>(); when(client.upload(same(content), argThat(path -> { assertTrue(path.matches(directory + "/\\d{8}/\\d+/" + name + ".jpg")); pathRef.set(path); return true; }), eq(type))).thenReturn(url); when(client.getId()).thenReturn(10L); // 调用 String result = fileService.createFile(content, name, directory, type); // 断言 assertEquals(result, url); // 校验数据 FileDO file = fileMapper.selectOne(FileDO::getUrl, url); assertEquals(10L, file.getConfigId()); assertEquals(pathRef.get(), file.getPath()); assertEquals(url, file.getUrl()); assertEquals(type, file.getType()); assertEquals(content.length, file.getSize()); } /** * content 非空,其它都空 */ @Test public void testCreateFile_success_02() throws Exception { // 准备参数 byte[] content = ResourceUtil.readBytes("file/erweima.jpg"); // mock Master 文件客户端 String type = "image/jpeg"; FileClient client = mock(FileClient.class); when(fileConfigService.getMasterFileClient()).thenReturn(client); String url = randomString(); AtomicReference pathRef = new AtomicReference<>(); when(client.upload(same(content), argThat(path -> { assertTrue(path.matches("\\d{8}/\\d+/6318848e882d8a7e7e82789d87608f684ee52d41966bfc8cad3ce15aad2b970e\\.jpg")); pathRef.set(path); return true; }), eq(type))).thenReturn(url); when(client.getId()).thenReturn(10L); // 调用 String result = fileService.createFile(content, null, null, null); // 断言 assertEquals(result, url); // 校验数据 FileDO file = fileMapper.selectOne(FileDO::getUrl, url); assertEquals(10L, file.getConfigId()); assertEquals(pathRef.get(), file.getPath()); assertEquals(url, file.getUrl()); assertEquals(type, file.getType()); assertEquals(content.length, file.getSize()); } @Test public void testDeleteFile_success() throws Exception { // mock 数据 FileDO dbFile = randomPojo(FileDO.class, o -> o.setConfigId(10L).setPath("tudou.jpg")); fileMapper.insert(dbFile);// @Sql: 先插入出一条存在的数据 // mock Master 文件客户端 FileClient client = mock(FileClient.class); when(fileConfigService.getFileClient(eq(10L))).thenReturn(client); // 准备参数 Long id = dbFile.getId(); // 调用 fileService.deleteFile(id); // 校验数据不存在了 assertNull(fileMapper.selectById(id)); // 校验调用 verify(client).delete(eq("tudou.jpg")); } @Test public void testDeleteFile_notExists() { // 准备参数 Long id = randomLongId(); // 调用, 并断言异常 assertServiceException(() -> fileService.deleteFile(id), FILE_NOT_EXISTS); } @Test public void testGetFileContent() throws Exception { // 准备参数 Long configId = 10L; String path = "tudou.jpg"; // mock 方法 FileClient client = mock(FileClient.class); when(fileConfigService.getFileClient(eq(10L))).thenReturn(client); byte[] content = new byte[]{}; when(client.getContent(eq("tudou.jpg"))).thenReturn(content); // 调用 byte[] result = fileService.getFileContent(configId, path); // 断言 assertSame(result, content); } @Test public void testGenerateUploadPath_AllEnabled() { // 准备参数 String name = "test.jpg"; String directory = "avatar"; FileServiceImpl.PATH_PREFIX_DATE_ENABLE = true; FileServiceImpl.PATH_SUFFIX_TIMESTAMP_ENABLE = true; // 调用 String path = fileService.generateUploadPath(name, directory); // 断言 // 格式为:avatar/yyyyMMdd/{时间戳+随机数}/test.jpg assertTrue(path.startsWith(directory + "/")); // 包含日期格式:8 位数字,如 20240517 assertTrue(path.matches(directory + "/\\d{8}/\\d+/test\\.jpg")); } @Test public void testGenerateUploadPath_PrefixEnabled_SuffixDisabled() { // 准备参数 String name = "test.jpg"; String directory = "avatar"; FileServiceImpl.PATH_PREFIX_DATE_ENABLE = true; FileServiceImpl.PATH_SUFFIX_TIMESTAMP_ENABLE = false; // 调用 String path = fileService.generateUploadPath(name, directory); // 断言 // 格式为:avatar/yyyyMMdd/test.jpg assertTrue(path.startsWith(directory + "/")); // 包含日期格式:8 位数字,如 20240517 assertTrue(path.matches(directory + "/\\d{8}/test\\.jpg")); } @Test public void testGenerateUploadPath_PrefixDisabled_SuffixEnabled() { // 准备参数 String name = "test.jpg"; String directory = "avatar"; FileServiceImpl.PATH_PREFIX_DATE_ENABLE = false; FileServiceImpl.PATH_SUFFIX_TIMESTAMP_ENABLE = true; // 调用 String path = fileService.generateUploadPath(name, directory); // 断言 // 格式为:avatar/{时间戳+随机数}/test.jpg assertTrue(path.startsWith(directory + "/")); assertTrue(path.matches(directory + "/\\d+/test\\.jpg")); } @Test public void testGenerateUploadPath_AllDisabled() { // 准备参数 String name = "test.jpg"; String directory = "avatar"; FileServiceImpl.PATH_PREFIX_DATE_ENABLE = false; FileServiceImpl.PATH_SUFFIX_TIMESTAMP_ENABLE = false; // 调用 String path = fileService.generateUploadPath(name, directory); // 断言 // 格式为:avatar/test.jpg assertEquals(directory + "/" + name, path); } @Test public void testGenerateUploadPath_NoExtension() { // 准备参数 String name = "test"; String directory = "avatar"; FileServiceImpl.PATH_PREFIX_DATE_ENABLE = true; FileServiceImpl.PATH_SUFFIX_TIMESTAMP_ENABLE = true; // 调用 String path = fileService.generateUploadPath(name, directory); // 断言 // 格式为:avatar/yyyyMMdd/{时间戳+随机数}/test assertTrue(path.startsWith(directory + "/")); assertTrue(path.matches(directory + "/\\d{8}/\\d+/test")); } @Test public void testGenerateUploadPath_DirectoryNull() { // 准备参数 String name = "test.jpg"; String directory = null; FileServiceImpl.PATH_PREFIX_DATE_ENABLE = true; FileServiceImpl.PATH_SUFFIX_TIMESTAMP_ENABLE = true; // 调用 String path = fileService.generateUploadPath(name, directory); // 断言 // 格式为:yyyyMMdd/{时间戳+随机数}/test.jpg assertTrue(path.matches("\\d{8}/\\d+/test\\.jpg")); } @Test public void testGenerateUploadPath_SuffixAsName_AllEnabled() { // 准备参数 String name = "test.jpg"; String directory = "avatar"; FileServiceImpl.PATH_PREFIX_DATE_ENABLE = true; FileServiceImpl.PATH_SUFFIX_TIMESTAMP_ENABLE = true; FileServiceImpl.PATH_SUFFIX_AS_DIRECTORY = false; // 调用 String path = fileService.generateUploadPath(name, directory); // 断言 // 格式为:avatar/yyyyMMdd/test_{时间戳+随机数}.jpg assertTrue(path.matches(directory + "/\\d{8}/test_\\d+\\.jpg")); } @Test public void testGenerateUploadPath_SuffixAsName_PrefixDisabled() { // 准备参数 String name = "test.jpg"; String directory = "avatar"; FileServiceImpl.PATH_PREFIX_DATE_ENABLE = false; FileServiceImpl.PATH_SUFFIX_TIMESTAMP_ENABLE = true; FileServiceImpl.PATH_SUFFIX_AS_DIRECTORY = false; // 调用 String path = fileService.generateUploadPath(name, directory); // 断言 // 格式为:avatar/test_{时间戳+随机数}.jpg assertTrue(path.matches(directory + "/test_\\d+\\.jpg")); } @Test public void testGenerateUploadPath_SuffixAsName_NoExtension() { // 准备参数 String name = "test"; String directory = "avatar"; FileServiceImpl.PATH_PREFIX_DATE_ENABLE = true; FileServiceImpl.PATH_SUFFIX_TIMESTAMP_ENABLE = true; FileServiceImpl.PATH_SUFFIX_AS_DIRECTORY = false; // 调用 String path = fileService.generateUploadPath(name, directory); // 断言 // 格式为:avatar/yyyyMMdd/test_{时间戳+随机数} assertTrue(path.matches(directory + "/\\d{8}/test_\\d+")); } @Test public void testGenerateUploadPath_DirectoryEmpty() { // 准备参数 String name = "test.jpg"; String directory = ""; FileServiceImpl.PATH_PREFIX_DATE_ENABLE = true; FileServiceImpl.PATH_SUFFIX_TIMESTAMP_ENABLE = true; // 调用 String path = fileService.generateUploadPath(name, directory); // 断言 // 格式为:yyyyMMdd/{时间戳+随机数}/test.jpg assertTrue(path.matches("\\d{8}/\\d+/test\\.jpg")); } }