修改mybatis版本启动报错,swagger注解问题

This commit is contained in:
wh
2026-04-12 00:15:59 +08:00
parent c3308e069d
commit a489e2b204
25 changed files with 510 additions and 64 deletions

View File

@@ -1,7 +1,12 @@
package com.label;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
class LabelBackendApplicationTests {
@Test
void contextLoads() {
}
}

View File

@@ -0,0 +1,55 @@
package com.label.unit;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.boot.env.YamlPropertySourceLoader;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.ClassPathResource;
import java.nio.charset.StandardCharsets;
import static org.assertj.core.api.Assertions.assertThat;
@DisplayName("应用配置单元测试")
class ApplicationConfigTest {
@Test
@DisplayName("application.yml 提供 Swagger 和 shiro.auth 测试开关配置")
void applicationYaml_containsSwaggerAndShiroAuthToggle() throws Exception {
PropertySource<?> source = new YamlPropertySourceLoader()
.load("application", new ClassPathResource("application.yml"))
.get(0);
assertThat(source.getProperty("springdoc.api-docs.enabled")).isEqualTo(true);
assertThat(source.getProperty("springdoc.api-docs.path")).isEqualTo("/v3/api-docs");
assertThat(source.getProperty("springdoc.swagger-ui.enabled")).isEqualTo(true);
assertThat(source.getProperty("springdoc.swagger-ui.path")).isEqualTo("/swagger-ui.html");
assertThat(source.getProperty("shiro.auth.enabled")).isEqualTo(true);
assertThat(source.getProperty("shiro.auth.mock-company-id")).isEqualTo(1);
assertThat(source.getProperty("shiro.auth.mock-user-id")).isEqualTo(1);
assertThat(source.getProperty("shiro.auth.mock-role")).isEqualTo("ADMIN");
assertThat(source.getProperty("logging.level.com.label")).isEqualTo("INFO");
}
@Test
@DisplayName("application.yml 默认值不指向公网服务或携带真实默认密码")
void applicationYaml_doesNotShipPublicInfrastructureDefaults() throws Exception {
String yaml = new ClassPathResource("application.yml")
.getContentAsString(StandardCharsets.UTF_8);
assertThat(yaml).doesNotContain("39.107.112.174");
assertThat(yaml).doesNotContain("postgres!Pw");
assertThat(yaml).doesNotContain("jsti@2024");
}
@Test
@DisplayName("logback.xml 启用 60 MB 滚动文件日志")
void logback_enablesRollingFileAppender() throws Exception {
String xml = new ClassPathResource("logback.xml")
.getContentAsString(StandardCharsets.UTF_8);
assertThat(xml).contains("<maxFileSize>60MB</maxFileSize>");
assertThat(xml).contains("<appender-ref ref=\"FILE\"/>");
assertThat(xml).doesNotContain("<!-- <appender-ref ref=\"FILE\"/> -->");
}
}

View File

@@ -0,0 +1,98 @@
package com.label.unit;
import com.label.module.annotation.controller.ExtractionController;
import com.label.module.annotation.controller.QaController;
import com.label.module.config.controller.SysConfigController;
import com.label.module.export.controller.ExportController;
import com.label.module.source.controller.SourceController;
import com.label.module.source.dto.SourceResponse;
import com.label.module.task.controller.TaskController;
import com.label.module.task.dto.TaskResponse;
import com.label.module.user.controller.AuthController;
import com.label.module.user.controller.UserController;
import com.label.module.user.dto.LoginRequest;
import com.label.module.user.dto.LoginResponse;
import com.label.module.user.dto.UserInfoResponse;
import com.label.module.video.controller.VideoController;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
@DisplayName("OpenAPI 注解覆盖测试")
class OpenApiAnnotationTest {
private static final List<Class<?>> CONTROLLERS = List.of(
AuthController.class,
UserController.class,
SourceController.class,
TaskController.class,
ExtractionController.class,
QaController.class,
ExportController.class,
SysConfigController.class,
VideoController.class
);
private static final List<Class<?>> DTOS = List.of(
LoginRequest.class,
LoginResponse.class,
UserInfoResponse.class,
TaskResponse.class,
SourceResponse.class
);
@Test
@DisplayName("所有 REST Controller 都声明 @Tag")
void allControllersHaveTag() {
assertThat(CONTROLLERS)
.allSatisfy(controller ->
assertThat(controller.getAnnotation(Tag.class))
.as(controller.getSimpleName() + " should have @Tag")
.isNotNull());
}
@Test
@DisplayName("所有 REST endpoint 方法都声明 @Operation")
void allEndpointMethodsHaveOperation() {
for (Class<?> controller : CONTROLLERS) {
Arrays.stream(controller.getDeclaredMethods())
.filter(method -> !Modifier.isPrivate(method.getModifiers()))
.filter(OpenApiAnnotationTest::isEndpointMethod)
.forEach(method -> assertThat(method.getAnnotation(Operation.class))
.as(controller.getSimpleName() + "." + method.getName() + " should have @Operation")
.isNotNull());
}
}
@Test
@DisplayName("核心 DTO 都声明 @Schema")
void coreDtosHaveSchema() {
assertThat(DTOS)
.allSatisfy(dto ->
assertThat(dto.getAnnotation(Schema.class))
.as(dto.getSimpleName() + " should have @Schema")
.isNotNull());
}
private static boolean isEndpointMethod(Method method) {
return method.isAnnotationPresent(GetMapping.class)
|| method.isAnnotationPresent(PostMapping.class)
|| method.isAnnotationPresent(PutMapping.class)
|| method.isAnnotationPresent(DeleteMapping.class)
|| method.isAnnotationPresent(RequestMapping.class);
}
}

View File

@@ -0,0 +1,143 @@
package com.label.unit;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.label.common.context.CompanyContext;
import com.label.common.redis.RedisKeyManager;
import com.label.common.redis.RedisService;
import com.label.common.shiro.BearerToken;
import com.label.common.shiro.TokenFilter;
import com.label.common.shiro.TokenPrincipal;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ThreadContext;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.util.ReflectionTestUtils;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.*;
@DisplayName("TokenFilter 单元测试")
class TokenFilterTest {
private RedisService redisService;
private TestableTokenFilter filter;
@BeforeEach
void setUp() {
redisService = mock(RedisService.class);
filter = new TestableTokenFilter(redisService, new ObjectMapper());
SecurityUtils.setSecurityManager(new DefaultSecurityManager(new BearerTokenRealm()));
}
@AfterEach
void tearDown() {
CompanyContext.clear();
ThreadContext.remove();
}
@Test
@DisplayName("有效 Token 请求会刷新 token TTL实现滑动过期")
void validToken_refreshesTokenTtl() throws Exception {
ReflectionTestUtils.setField(filter, "authEnabled", true);
ReflectionTestUtils.setField(filter, "tokenTtlSeconds", 7200L);
String token = "valid-token";
when(redisService.hGetAll(RedisKeyManager.tokenKey(token))).thenReturn(Map.of(
"userId", "10",
"role", "ADMIN",
"companyId", "20",
"username", "admin"
));
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/api/tasks");
request.addHeader("Authorization", "Bearer " + token);
MockHttpServletResponse response = new MockHttpServletResponse();
RecordingChain chain = new RecordingChain();
filter.invoke(request, response, chain);
assertThat(response.getStatus()).isEqualTo(200);
assertThat(chain.principal).isInstanceOf(TokenPrincipal.class);
verify(redisService).expire(RedisKeyManager.tokenKey(token), 7200L);
}
@Test
@DisplayName("shiro.auth.enabled=false 时注入 mock Principal 并跳过 Redis 校验")
void authDisabled_injectsMockPrincipalWithoutRedisLookup() throws Exception {
ReflectionTestUtils.setField(filter, "authEnabled", false);
ReflectionTestUtils.setField(filter, "mockCompanyId", 3L);
ReflectionTestUtils.setField(filter, "mockUserId", 4L);
ReflectionTestUtils.setField(filter, "mockRole", "ADMIN");
ReflectionTestUtils.setField(filter, "mockUsername", "mock-admin");
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/api/tasks");
MockHttpServletResponse response = new MockHttpServletResponse();
RecordingChain chain = new RecordingChain();
filter.invoke(request, response, chain);
assertThat(response.getStatus()).isEqualTo(200);
TokenPrincipal principal = chain.principal;
assertThat(principal.getCompanyId()).isEqualTo(3L);
assertThat(principal.getUserId()).isEqualTo(4L);
assertThat(principal.getRole()).isEqualTo("ADMIN");
assertThat(principal.getUsername()).isEqualTo("mock-admin");
verify(redisService, never()).hGetAll(anyString());
}
private static final class BearerTokenRealm extends AuthorizingRealm {
@Override
public boolean supports(AuthenticationToken token) {
return token instanceof BearerToken;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) {
return new SimpleAuthenticationInfo(token.getPrincipal(), token.getCredentials(), getName());
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
TokenPrincipal principal = (TokenPrincipal) principals.getPrimaryPrincipal();
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addRole(principal.getRole());
return info;
}
}
private static final class RecordingChain implements FilterChain {
private TokenPrincipal principal;
@Override
public void doFilter(ServletRequest request, ServletResponse response) {
principal = (TokenPrincipal) request.getAttribute("__token_principal__");
}
}
private static final class TestableTokenFilter extends TokenFilter {
private TestableTokenFilter(RedisService redisService, ObjectMapper objectMapper) {
super(redisService, objectMapper);
}
private void invoke(MockHttpServletRequest request, MockHttpServletResponse response, FilterChain chain)
throws Exception {
super.doFilterInternal(request, response, chain);
}
}
}