refactor: 统一实体/限流AOP化/精简日志/文件归位

This commit is contained in:
Ray.Hao committed 2026-06-24 08:11:23 +08:00
1 parent 0dce433849
commit 6b6c06370f
71 files changed
+751 -914

No files matched your search

@@ -0,0 +1,61 @@
package com.youlai.boot.auth.service.impl;
import com.youlai.boot.common.exception.BusinessException;
import com.youlai.boot.common.result.ResultCode;
import com.youlai.boot.framework.captcha.service.CaptchaService;
import com.youlai.boot.framework.integration.sms.enums.SmsTypeEnum;
import com.youlai.boot.framework.integration.sms.service.SmsService;
import com.youlai.boot.framework.security.token.TokenManager;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class AuthServiceImplTest {
@Mock
private AuthenticationManager authenticationManager;
@Mock
private TokenManager tokenManager;
@Mock
private SmsService smsService;
@Mock
private RedisTemplate<String, Object> redisTemplate;
@Mock
private CaptchaService captchaService;
@Test
void should_not_cache_sms_code_when_send_fails() {
when(smsService.sendSms(eq("13800138000"), eq(SmsTypeEnum.LOGIN), any(Map.class))).thenReturn(false);
AuthServiceImpl authService = new AuthServiceImpl(
authenticationManager,
tokenManager,
smsService,
redisTemplate,
captchaService
);
assertThatThrownBy(() -> authService.sendSmsCode("13800138000"))
.isInstanceOf(BusinessException.class)
.hasMessage("短信验证码发送失败");
verify(redisTemplate, never()).opsForValue();
}
}
@@ -0,0 +1,27 @@
package com.youlai.boot.file.service.impl;
import com.youlai.boot.common.exception.BusinessException;
import com.youlai.boot.file.config.LocalFileProperties;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import java.nio.file.Path;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
class LocalFileServiceTest {
@TempDir
Path storagePath;
@Test
void should_reject_path_outside_storage_root() {
LocalFileProperties properties = new LocalFileProperties();
properties.setStoragePath(storagePath.toString());
LocalFileService fileService = new LocalFileService(properties);
assertThatThrownBy(() -> fileService.deleteFile("../secret.txt"))
.isInstanceOf(BusinessException.class)
.hasMessage("文件路径不属于当前本地存储配置");
}
}
@@ -0,0 +1,20 @@
package com.youlai.boot.framework.web.advice;
import com.youlai.boot.common.result.Result;
import com.youlai.boot.common.result.ResultCode;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
class GlobalExceptionHandlerTest {
@Test
void should_not_expose_unknown_exception_message() throws Exception {
GlobalExceptionHandler handler = new GlobalExceptionHandler();
Result<Void> result = handler.handleException(new IllegalStateException("database password leaked"));
assertThat(result.getCode()).isEqualTo(ResultCode.SYSTEM_ERROR.getCode());
assertThat(result.getMsg()).isEqualTo("系统异常,请稍后重试");
}
}
@@ -0,0 +1,28 @@
package com.youlai.boot.framework.web.config;
import org.junit.jupiter.api.Test;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
import static org.assertj.core.api.Assertions.assertThat;
class OperationLogExecutorConfigTest {
@Test
void should_create_operation_log_executor() {
Executor executor = new OperationLogExecutorConfig().operationLogExecutor();
assertThat(executor).isInstanceOf(ThreadPoolTaskExecutor.class);
ThreadPoolTaskExecutor taskExecutor = (ThreadPoolTaskExecutor) executor;
assertThat(taskExecutor.getThreadNamePrefix()).isEqualTo("operation-log-");
assertThat(taskExecutor.getCorePoolSize()).isEqualTo(1);
assertThat(taskExecutor.getMaxPoolSize()).isEqualTo(2);
assertThat(taskExecutor.getThreadPoolExecutor().getQueue().remainingCapacity()).isEqualTo(1000);
assertThat(taskExecutor.getThreadPoolExecutor().getRejectedExecutionHandler())
.isInstanceOf(ThreadPoolExecutor.CallerRunsPolicy.class);
taskExecutor.shutdown();
}
}
@@ -0,0 +1,48 @@
package com.youlai.boot.security.filter;
import com.youlai.boot.common.constant.SecurityConstants;
import com.youlai.boot.common.result.ResultCode;
import com.youlai.boot.framework.security.filter.TokenAuthenticationFilter;
import com.youlai.boot.framework.security.token.TokenManager;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.http.HttpHeaders;
import org.springframework.mock.web.MockFilterChain;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.core.context.SecurityContextHolder;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class TokenAuthenticationFilterTest {
@Mock
private TokenManager tokenManager;
@AfterEach
void tearDown() {
SecurityContextHolder.clearContext();
}
@Test
void should_clear_context_and_return_unauthorized_when_token_validation_fails() throws Exception {
String token = "invalid-token";
when(tokenManager.validateToken(token)).thenThrow(new IllegalStateException("token store unavailable"));
SecurityContextHolder.getContext().setAuthentication(new org.springframework.security.authentication.TestingAuthenticationToken("old", null));
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/api/v1/users");
request.addHeader(HttpHeaders.AUTHORIZATION, SecurityConstants.BEARER_TOKEN_PREFIX + token);
MockHttpServletResponse response = new MockHttpServletResponse();
new TokenAuthenticationFilter(tokenManager).doFilter(request, response, new MockFilterChain());
assertThat(response.getStatus()).isEqualTo(401);
assertThat(response.getContentAsString()).contains(ResultCode.ACCESS_TOKEN_INVALID.getCode());
assertThat(SecurityContextHolder.getContext().getAuthentication()).isNull();
}
}