init aop log

This commit is contained in:
Chuck1sn
2025-07-07 16:13:52 +08:00
parent 5c685d4f74
commit 36d285a61d
22 changed files with 1741 additions and 44 deletions

View File

@@ -0,0 +1,440 @@
package com.zl.mjga.integration.aspect;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zl.mjga.annotation.SkipAopLog;
import com.zl.mjga.aspect.LoggingAspect;
import com.zl.mjga.repository.UserRepository;
import com.zl.mjga.service.AopLogService;
import jakarta.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.jooq.generated.mjga.tables.pojos.AopLog;
import org.jooq.generated.mjga.tables.pojos.User;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
class LoggingAspectTest {
@Mock private AopLogService aopLogService;
@Mock private ObjectMapper objectMapper;
@Mock private UserRepository userRepository;
@Mock private ProceedingJoinPoint joinPoint;
@Mock private MethodSignature methodSignature;
@Mock private SecurityContext securityContext;
@Mock private Authentication authentication;
@Mock private ServletRequestAttributes servletRequestAttributes;
@Mock private HttpServletRequest httpServletRequest;
private LoggingAspect loggingAspect;
@BeforeEach
void setUp() {
loggingAspect = new LoggingAspect(aopLogService, objectMapper, userRepository);
SecurityContextHolder.setContext(securityContext);
}
@AfterEach
void tearDown() {
SecurityContextHolder.clearContext();
}
@Test
void logController_givenSuccessfulExecution_shouldSaveSuccessLog() throws Throwable {
// arrange
TestController target = new TestController();
Object[] args = {"arg1", "arg2"};
String expectedResult = "success";
User mockUser = createMockUser(123L, "testUser");
setupAuthenticatedUser("testUser", mockUser);
setupJoinPoint(target, "testMethod", args, expectedResult);
setupSerialization("[\"arg1\",\"arg2\"]", "\"success\"");
try (MockedStatic<RequestContextHolder> mockedRequestContextHolder =
setupRequestContext("192.168.1.1", "Test-Agent")) {
// action
Object result = loggingAspect.logController(joinPoint);
// assert
assertThat(result).isEqualTo(expectedResult);
verifyLogSaved(
log -> {
assertThat(log.getClassName()).isEqualTo("TestController");
assertThat(log.getMethodName()).isEqualTo("testMethod");
assertThat(log.getMethodArgs()).isEqualTo("[\"arg1\",\"arg2\"]");
assertThat(log.getReturnValue()).isEqualTo("\"success\"");
assertThat(log.getSuccess()).isTrue();
assertThat(log.getUserId()).isEqualTo(123L);
assertThat(log.getIpAddress()).isEqualTo("192.168.1.1");
assertThat(log.getUserAgent()).isEqualTo("Test-Agent");
assertThat(log.getExecutionTime()).isGreaterThanOrEqualTo(0L);
});
}
}
@Test
void logController_givenFailedExecution_shouldSaveFailLog() throws Throwable {
// arrange
TestController target = new TestController();
Object[] args = {"arg1"};
RuntimeException exception = new RuntimeException("Test error");
User mockUser = createMockUser(123L, "testUser");
setupAuthenticatedUser("testUser", mockUser);
setupJoinPoint(target, "failMethod", args, exception);
setupSerialization("[\"arg1\"]", null);
try (MockedStatic<RequestContextHolder> mockedRequestContextHolder =
setupRequestContext("192.168.1.1", "Test-Agent")) {
// action & assert
assertThatThrownBy(() -> loggingAspect.logController(joinPoint))
.isInstanceOf(RuntimeException.class)
.hasMessage("Test error");
verifyLogSaved(
log -> {
assertThat(log.getClassName()).isEqualTo("TestController");
assertThat(log.getMethodName()).isEqualTo("failMethod");
assertThat(log.getSuccess()).isFalse();
assertThat(log.getErrorMessage()).isEqualTo("Test error");
assertThat(log.getReturnValue()).isNull();
assertThat(log.getUserId()).isEqualTo(123L);
});
}
}
@Test
void logService_givenSuccessfulExecution_shouldSaveSuccessLogWithoutRequestInfo()
throws Throwable {
// arrange
TestService target = new TestService();
Object[] args = {"serviceArg"};
String expectedResult = "serviceResult";
User mockUser = createMockUser(123L, "testUser");
setupAuthenticatedUser("testUser", mockUser);
setupJoinPoint(target, "serviceMethod", args, expectedResult);
setupSerialization("[\"serviceArg\"]", "\"serviceResult\"");
// action
Object result = loggingAspect.logService(joinPoint);
// assert
assertThat(result).isEqualTo(expectedResult);
verifyLogSaved(
log -> {
assertThat(log.getClassName()).isEqualTo("TestService");
assertThat(log.getMethodName()).isEqualTo("serviceMethod");
assertThat(log.getSuccess()).isTrue();
assertThat(log.getUserId()).isEqualTo(123L);
// Service层不应该有请求信息
assertThat(log.getIpAddress()).isNull();
assertThat(log.getUserAgent()).isNull();
});
}
@Test
void logRepository_givenSuccessfulExecution_shouldSaveSuccessLogWithoutRequestInfo()
throws Throwable {
// arrange
TestRepository target = new TestRepository();
Object[] args = {1L};
Object expectedResult = new Object();
User mockUser = createMockUser(123L, "testUser");
setupAuthenticatedUser("testUser", mockUser);
setupJoinPoint(target, "findById", args, expectedResult);
setupSerialization("[1]", "{}");
// action
Object result = loggingAspect.logRepository(joinPoint);
// assert
assertThat(result).isEqualTo(expectedResult);
verifyLogSaved(
log -> {
assertThat(log.getClassName()).isEqualTo("TestRepository");
assertThat(log.getMethodName()).isEqualTo("findById");
assertThat(log.getSuccess()).isTrue();
assertThat(log.getUserId()).isEqualTo(123L);
// Repository层不应该有请求信息
assertThat(log.getIpAddress()).isNull();
assertThat(log.getUserAgent()).isNull();
});
}
@Test
void logController_givenUnauthenticatedUser_shouldNotLog() throws Throwable {
// arrange
TestController target = new TestController();
String expectedResult = "success";
Method testMethod = TestController.class.getMethod("testMethod");
when(joinPoint.getTarget()).thenReturn(target);
when(joinPoint.proceed()).thenReturn(expectedResult);
when(joinPoint.getSignature()).thenReturn(methodSignature);
when(methodSignature.getMethod()).thenReturn(testMethod);
// Mock SecurityContextHolder to return null authentication
when(securityContext.getAuthentication()).thenReturn(null);
try (MockedStatic<RequestContextHolder> mockedRequestContextHolder =
mockStatic(RequestContextHolder.class)) {
mockedRequestContextHolder.when(RequestContextHolder::getRequestAttributes).thenReturn(null);
// action
Object result = loggingAspect.logController(joinPoint);
// assert
assertThat(result).isEqualTo(expectedResult);
verify(aopLogService, never()).saveLogAsync(any());
}
}
@Test
void logController_givenAnonymousUser_shouldNotLog() throws Throwable {
// arrange
TestController target = new TestController();
String expectedResult = "success";
Method testMethod = TestController.class.getMethod("testMethod");
when(authentication.isAuthenticated()).thenReturn(true);
when(authentication.getName()).thenReturn("anonymousUser");
when(joinPoint.getTarget()).thenReturn(target);
when(joinPoint.proceed()).thenReturn(expectedResult);
when(joinPoint.getSignature()).thenReturn(methodSignature);
when(methodSignature.getMethod()).thenReturn(testMethod);
// Mock SecurityContextHolder to return anonymous authentication
when(securityContext.getAuthentication()).thenReturn(authentication);
try (MockedStatic<RequestContextHolder> mockedRequestContextHolder =
mockStatic(RequestContextHolder.class)) {
mockedRequestContextHolder.when(RequestContextHolder::getRequestAttributes).thenReturn(null);
// action
Object result = loggingAspect.logController(joinPoint);
// assert
assertThat(result).isEqualTo(expectedResult);
verify(aopLogService, never()).saveLogAsync(any());
}
}
@Test
void logController_givenSkipAopLogAnnotation_shouldNotLog() throws Throwable {
// arrange
TestController target = new TestController();
String expectedResult = "success";
when(joinPoint.getTarget()).thenReturn(target);
when(joinPoint.getSignature()).thenReturn(methodSignature);
when(methodSignature.getMethod()).thenReturn(getSkipLogMethod());
when(joinPoint.proceed()).thenReturn(expectedResult);
// action
Object result = loggingAspect.logController(joinPoint);
// assert
assertThat(result).isEqualTo(expectedResult);
verify(aopLogService, never()).saveLogAsync(any());
}
@Test
void logController_givenNullArgs_shouldHandleGracefully() throws Throwable {
// arrange
TestController target = new TestController();
User mockUser = createMockUser(123L, "testUser");
setupAuthenticatedUser("testUser", mockUser);
setupJoinPoint(target, "noArgsMethod", null, "result");
setupSerialization(null, "\"result\"");
try (MockedStatic<RequestContextHolder> mockedRequestContextHolder =
setupRequestContext("127.0.0.1", "Test-Agent")) {
// action
Object result = loggingAspect.logController(joinPoint);
// assert
assertThat(result).isEqualTo("result");
verifyLogSaved(
log -> {
assertThat(log.getMethodArgs()).isNull();
assertThat(log.getSuccess()).isTrue();
});
}
}
@Test
void logController_givenEmptyArgs_shouldHandleGracefully() throws Throwable {
// arrange
TestController target = new TestController();
Object[] emptyArgs = {};
User mockUser = createMockUser(123L, "testUser");
setupAuthenticatedUser("testUser", mockUser);
setupJoinPoint(target, "noArgsMethod", emptyArgs, "result");
setupSerialization(null, "\"result\"");
try (MockedStatic<RequestContextHolder> mockedRequestContextHolder =
setupRequestContext("127.0.0.1", "Test-Agent")) {
// action
Object result = loggingAspect.logController(joinPoint);
// assert
assertThat(result).isEqualTo("result");
verifyLogSaved(
log -> {
assertThat(log.getMethodArgs()).isNull();
assertThat(log.getSuccess()).isTrue();
});
}
}
@Test
void logController_givenSerializationError_shouldHandleGracefully() throws Throwable {
// arrange
TestController target = new TestController();
Object[] args = {"arg1"};
String expectedResult = "success";
User mockUser = createMockUser(123L, "testUser");
setupAuthenticatedUser("testUser", mockUser);
setupJoinPoint(target, "testMethod", args, expectedResult);
// Mock serialization error
when(objectMapper.writeValueAsString(args))
.thenThrow(new JsonProcessingException("Serialization failed") {});
when(objectMapper.writeValueAsString(expectedResult)).thenReturn("\"success\"");
try (MockedStatic<RequestContextHolder> mockedRequestContextHolder =
setupRequestContext("127.0.0.1", "Test-Agent")) {
// action
Object result = loggingAspect.logController(joinPoint);
// assert
assertThat(result).isEqualTo(expectedResult);
verifyLogSaved(
log -> {
assertThat(log.getMethodArgs()).isEqualTo("Serialization failed");
assertThat(log.getSuccess()).isTrue();
});
}
}
// Helper methods
private User createMockUser(Long id, String username) {
User user = new User();
user.setId(id);
user.setUsername(username);
return user;
}
private void setupAuthenticatedUser(String username, User user) {
when(securityContext.getAuthentication()).thenReturn(authentication);
when(authentication.isAuthenticated()).thenReturn(true);
when(authentication.getName()).thenReturn(username);
when(authentication.getPrincipal()).thenReturn(username);
when(userRepository.fetchOneByUsername(username)).thenReturn(user);
}
private void setupJoinPoint(Object target, String methodName, Object[] args, Object result)
throws Throwable {
when(joinPoint.getTarget()).thenReturn(target);
when(joinPoint.getSignature()).thenReturn(methodSignature);
when(methodSignature.getName()).thenReturn(methodName);
when(methodSignature.getMethod()).thenReturn(getTestMethod());
when(joinPoint.getArgs()).thenReturn(args);
if (result instanceof Throwable) {
when(joinPoint.proceed()).thenThrow((Throwable) result);
} else {
when(joinPoint.proceed()).thenReturn(result);
}
}
private void setupSerialization(String argsJson, String resultJson)
throws JsonProcessingException {
if (argsJson != null) {
when(objectMapper.writeValueAsString(any(Object[].class))).thenReturn(argsJson);
}
if (resultJson != null) {
when(objectMapper.writeValueAsString(argThat(arg -> !(arg instanceof Object[]))))
.thenReturn(resultJson);
}
}
private MockedStatic<RequestContextHolder> setupRequestContext(
String ipAddress, String userAgent) {
MockedStatic<RequestContextHolder> mockedRequestContextHolder =
mockStatic(RequestContextHolder.class);
mockedRequestContextHolder
.when(RequestContextHolder::getRequestAttributes)
.thenReturn(servletRequestAttributes);
when(servletRequestAttributes.getRequest()).thenReturn(httpServletRequest);
when(httpServletRequest.getHeader("X-Forwarded-For")).thenReturn(ipAddress);
when(httpServletRequest.getHeader("User-Agent")).thenReturn(userAgent);
when(httpServletRequest.getRemoteAddr()).thenReturn("127.0.0.1");
return mockedRequestContextHolder;
}
private void verifyLogSaved(java.util.function.Consumer<AopLog> logVerifier) {
ArgumentCaptor<AopLog> logCaptor = ArgumentCaptor.forClass(AopLog.class);
verify(aopLogService, times(1)).saveLogAsync(logCaptor.capture());
logVerifier.accept(logCaptor.getValue());
}
private java.lang.reflect.Method getTestMethod() throws NoSuchMethodException {
return TestController.class.getMethod("testMethod");
}
private java.lang.reflect.Method getSkipLogMethod() throws NoSuchMethodException {
return TestController.class.getMethod("skipLogMethod");
}
// Test classes for mocking
private static class TestController {
public String testMethod() {
return "test";
}
@SkipAopLog(reason = "测试跳过日志记录")
public String skipLogMethod() {
return "test";
}
}
private static class TestService {
public String testMethod() {
return "test";
}
}
private static class TestRepository {
public String testMethod() {
return "test";
}
}
}

View File

@@ -0,0 +1,186 @@
package com.zl.mjga.integration.mvc;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zl.mjga.config.minio.MinIoConfig;
import com.zl.mjga.config.security.HttpFireWallConfig;
import com.zl.mjga.controller.AopLogController;
import com.zl.mjga.dto.PageRequestDto;
import com.zl.mjga.dto.PageResponseDto;
import com.zl.mjga.dto.aoplog.AopLogQueryDto;
import com.zl.mjga.dto.aoplog.AopLogRespDto;
import com.zl.mjga.repository.AopLogRepository;
import com.zl.mjga.repository.PermissionRepository;
import com.zl.mjga.repository.RoleRepository;
import com.zl.mjga.repository.UserRepository;
import com.zl.mjga.service.AopLogService;
import io.minio.MinioClient;
import java.time.OffsetDateTime;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import org.springframework.http.MediaType;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.web.servlet.MockMvc;
@WebMvcTest(value = {AopLogController.class})
@Import({HttpFireWallConfig.class})
public class AopLogControllerTest {
@Autowired private MockMvc mockMvc;
@Autowired private ObjectMapper objectMapper;
@MockBean private AopLogService aopLogService;
@MockBean private AopLogRepository aopLogRepository;
@MockBean private UserRepository userRepository;
@MockBean private RoleRepository roleRepository;
@MockBean private PermissionRepository permissionRepository;
@MockBean private MinioClient minioClient;
@MockBean private MinIoConfig minIoConfig;
@Test
@WithMockUser(authorities = "READ_USER_ROLE_PERMISSION")
void pageQueryAopLogs_givenValidRequest_shouldReturnOk() throws Exception {
// arrange
PageResponseDto<List<AopLogRespDto>> mockResponse =
new PageResponseDto<>(1L, List.of(createTestAopLogRespDto()));
when(aopLogService.pageQueryAopLogs(any(PageRequestDto.class), any(AopLogQueryDto.class)))
.thenReturn(mockResponse);
// action & assert
mockMvc
.perform(
get("/aop-log/page-query")
.param("page", "1")
.param("size", "10")
.param("className", "TestController"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.total").value(1))
.andExpect(jsonPath("$.data").isArray())
.andExpect(jsonPath("$.data[0].className").value("TestController"));
}
@Test
void pageQueryAopLogs_givenNoAuth_shouldReturnUnauthorized() throws Exception {
// action & assert
mockMvc
.perform(get("/aop-log/page-query").param("page", "1").param("size", "10"))
.andExpect(status().isUnauthorized());
}
@Test
@WithMockUser(authorities = "READ_USER_ROLE_PERMISSION")
void getAopLogById_givenValidId_shouldReturnOk() throws Exception {
// arrange
Long id = 1L;
AopLogRespDto mockResponse = createTestAopLogRespDto();
when(aopLogService.getAopLogById(id)).thenReturn(mockResponse);
// action & assert
mockMvc
.perform(get("/aop-log/{id}", id))
.andExpect(status().isOk())
.andExpect(jsonPath("$.id").value(1))
.andExpect(jsonPath("$.className").value("TestController"))
.andExpect(jsonPath("$.methodName").value("testMethod"));
}
@Test
@WithMockUser(authorities = "READ_USER_ROLE_PERMISSION")
void getAopLogById_givenNonExistingId_shouldReturnOkWithNull() throws Exception {
// arrange
Long id = 999L;
when(aopLogService.getAopLogById(id)).thenReturn(null);
// action & assert
mockMvc
.perform(get("/aop-log/{id}", id))
.andExpect(status().isOk())
.andExpect(content().string(""));
}
@Test
@WithMockUser(authorities = "WRITE_USER_ROLE_PERMISSION")
void deleteAopLogs_givenValidIds_shouldReturnOk() throws Exception {
// arrange
List<Long> ids = List.of(1L, 2L, 3L);
when(aopLogRepository.deleteByIds(ids)).thenReturn(3);
// action & assert
mockMvc
.perform(
delete("/aop-log/batch")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(ids))
.with(csrf()))
.andExpect(status().isOk())
.andExpect(content().string("3"));
}
@Test
void deleteAopLogs_givenNoAuth_shouldReturnUnauthorized() throws Exception {
// arrange
List<Long> ids = List.of(1L, 2L, 3L);
// action & assert
mockMvc
.perform(
delete("/aop-log/batch")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(ids))
.with(csrf()))
.andExpect(status().isUnauthorized());
}
@Test
@WithMockUser(authorities = "WRITE_USER_ROLE_PERMISSION")
void deleteAopLog_givenValidId_shouldReturnOk() throws Exception {
// arrange
Long id = 1L;
when(aopLogRepository.deleteByIds(List.of(id))).thenReturn(1);
// action & assert
mockMvc.perform(delete("/aop-log/{id}", id).with(csrf())).andExpect(status().isOk());
}
@Test
@WithMockUser(authorities = "WRITE_USER_ROLE_PERMISSION")
void deleteLogsBeforeTime_givenValidTime_shouldReturnOk() throws Exception {
// arrange
OffsetDateTime beforeTime = OffsetDateTime.now().minusDays(7);
when(aopLogService.deleteLogsBeforeTime(beforeTime)).thenReturn(5);
// action & assert
mockMvc
.perform(delete("/aop-log/before").param("beforeTime", beforeTime.toString()).with(csrf()))
.andExpect(status().isOk())
.andExpect(content().string("5"));
}
private AopLogRespDto createTestAopLogRespDto() {
return AopLogRespDto.builder()
.id(1L)
.className("TestController")
.methodName("testMethod")
.methodArgs("[\"arg1\"]")
.returnValue("\"result\"")
.executionTime(100L)
.success(true)
.userId(1L)
.username("testUser")
.ipAddress("127.0.0.1")
.userAgent("Test Agent")
.createTime(OffsetDateTime.now())
.build();
}
}

View File

@@ -16,6 +16,7 @@ import com.zl.mjga.repository.PermissionRepository;
import com.zl.mjga.repository.RoleRepository;
import com.zl.mjga.repository.UserRepository;
import com.zl.mjga.service.IdentityAccessService;
import com.zl.mjga.service.UploadService;
import io.minio.MinioClient;
import java.util.List;
import org.junit.jupiter.api.Test;
@@ -38,6 +39,7 @@ public class JacksonAnnotationMvcTest {
@MockBean private PermissionRepository permissionRepository;
@MockBean private MinioClient minioClient;
@MockBean private MinIoConfig minIoConfig;
@MockBean private UploadService uploadService;
@Test
@WithMockUser

View File

@@ -17,6 +17,7 @@ import com.zl.mjga.repository.PermissionRepository;
import com.zl.mjga.repository.RoleRepository;
import com.zl.mjga.repository.UserRepository;
import com.zl.mjga.service.IdentityAccessService;
import com.zl.mjga.service.UploadService;
import io.minio.MinioClient;
import java.util.List;
import org.jooq.generated.mjga.tables.pojos.User;
@@ -40,6 +41,7 @@ class UserRolePermissionMvcTest {
@MockBean private PermissionRepository permissionRepository;
@MockBean private MinioClient minioClient;
@MockBean private MinIoConfig minIoConfig;
@MockBean private UploadService uploadService;
@Test
@WithMockUser

View File

@@ -0,0 +1,192 @@
package com.zl.mjga.integration.persistence;
import static org.assertj.core.api.Assertions.assertThat;
import com.zl.mjga.dto.PageRequestDto;
import com.zl.mjga.dto.aoplog.AopLogQueryDto;
import com.zl.mjga.repository.AopLogRepository;
import java.time.OffsetDateTime;
import java.util.List;
import org.jooq.Record;
import org.jooq.Result;
import org.jooq.generated.mjga.tables.pojos.AopLog;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.jdbc.Sql;
public class AopLogRepositoryTest extends AbstractDataAccessLayerTest {
@Autowired private AopLogRepository aopLogRepository;
@Test
@Sql(
statements = {
"INSERT INTO mjga.user (id, username, password) VALUES (1, 'testUser', 'password')",
"INSERT INTO mjga.aop_log (id, class_name, method_name, method_args, return_value,"
+ " execution_time, success, user_id, ip_address) VALUES (1, 'TestController',"
+ " 'testMethod', '[\"arg1\"]', '\"result\"', 100, true, 1, '127.0.0.1')",
"INSERT INTO mjga.aop_log (id, class_name, method_name, method_args, return_value,"
+ " execution_time, success, error_message) VALUES (2, 'TestService', 'failMethod',"
+ " '[\"arg2\"]', null, 200, false, 'Test error')",
"INSERT INTO mjga.aop_log (id, class_name, method_name, execution_time, success) VALUES (3,"
+ " 'TestRepository', 'queryMethod', 50, true)"
})
void pageFetchBy_givenValidQuery_shouldReturnCorrectResults() {
// arrange
AopLogQueryDto queryDto = new AopLogQueryDto();
queryDto.setClassName("Test");
PageRequestDto pageRequestDto = PageRequestDto.of(1, 10);
// action
Result<Record> result = aopLogRepository.pageFetchBy(pageRequestDto, queryDto);
// assert
assertThat(result).hasSize(3);
assertThat(result.get(0).getValue("total_count", Long.class)).isEqualTo(3L);
}
@Test
@Sql(
statements = {
"INSERT INTO mjga.aop_log (id, class_name, method_name, execution_time, success) VALUES (1,"
+ " 'TestController', 'method1', 100, true)",
"INSERT INTO mjga.aop_log (id, class_name, method_name, execution_time, success) VALUES (2,"
+ " 'TestService', 'method2', 200, false)",
"INSERT INTO mjga.aop_log (id, class_name, method_name, execution_time, success) VALUES (3,"
+ " 'TestRepository', 'method3', 50, true)"
})
void fetchBy_givenClassNameQuery_shouldReturnFilteredResults() {
// arrange
AopLogQueryDto queryDto = new AopLogQueryDto();
queryDto.setClassName("TestController");
// action
List<AopLog> result = aopLogRepository.fetchBy(queryDto);
// assert
assertThat(result).hasSize(1);
assertThat(result.get(0).getClassName()).isEqualTo("TestController");
assertThat(result.get(0).getMethodName()).isEqualTo("method1");
}
@Test
@Sql(
statements = {
"INSERT INTO mjga.aop_log (id, class_name, method_name, execution_time, success) VALUES (1,"
+ " 'TestController', 'method1', 100, true)",
"INSERT INTO mjga.aop_log (id, class_name, method_name, execution_time, success) VALUES (2,"
+ " 'TestService', 'method2', 200, false)"
})
void fetchBy_givenSuccessQuery_shouldReturnOnlySuccessfulLogs() {
// arrange
AopLogQueryDto queryDto = new AopLogQueryDto();
queryDto.setSuccess(true);
// action
List<AopLog> result = aopLogRepository.fetchBy(queryDto);
// assert
assertThat(result).hasSize(1);
assertThat(result.get(0).getSuccess()).isTrue();
}
@Test
@Sql(
statements = {
"INSERT INTO mjga.aop_log (id, class_name, method_name, execution_time, success) VALUES (1,"
+ " 'TestController', 'method1', 50, true)",
"INSERT INTO mjga.aop_log (id, class_name, method_name, execution_time, success) VALUES (2,"
+ " 'TestService', 'method2', 150, false)",
"INSERT INTO mjga.aop_log (id, class_name, method_name, execution_time, success) VALUES (3,"
+ " 'TestRepository', 'method3', 250, true)"
})
void fetchBy_givenExecutionTimeRange_shouldReturnFilteredResults() {
// arrange
AopLogQueryDto queryDto = new AopLogQueryDto();
queryDto.setMinExecutionTime(100L);
queryDto.setMaxExecutionTime(200L);
// action
List<AopLog> result = aopLogRepository.fetchBy(queryDto);
// assert
assertThat(result).hasSize(1);
assertThat(result.get(0).getExecutionTime()).isEqualTo(150L);
}
@Test
@Sql(
statements = {
"INSERT INTO mjga.aop_log (id, class_name, method_name, execution_time, success) VALUES (1,"
+ " 'TestController', 'method1', 100, true)",
"INSERT INTO mjga.aop_log (id, class_name, method_name, execution_time, success) VALUES (2,"
+ " 'TestService', 'method2', 200, false)",
"INSERT INTO mjga.aop_log (id, class_name, method_name, execution_time, success) VALUES (3,"
+ " 'TestRepository', 'method3', 50, true)"
})
void deleteByIds_givenValidIds_shouldDeleteCorrectRecords() {
// arrange
List<Long> idsToDelete = List.of(1L, 3L);
// action
int deletedCount = aopLogRepository.deleteByIds(idsToDelete);
// assert
assertThat(deletedCount).isEqualTo(2);
// verify remaining record
List<AopLog> remaining = aopLogRepository.findAll();
assertThat(remaining).hasSize(1);
assertThat(remaining.get(0).getId()).isEqualTo(2L);
}
@Test
@Sql(
statements = {
"INSERT INTO mjga.aop_log (id, class_name, method_name, execution_time, success,"
+ " create_time) VALUES (1, 'TestController', 'method1', 100, true, '2023-01-01"
+ " 00:00:00+00')",
"INSERT INTO mjga.aop_log (id, class_name, method_name, execution_time, success,"
+ " create_time) VALUES (2, 'TestService', 'method2', 200, false, '2023-06-01"
+ " 00:00:00+00')",
"INSERT INTO mjga.aop_log (id, class_name, method_name, execution_time, success,"
+ " create_time) VALUES (3, 'TestRepository', 'method3', 50, true, '2023-12-01"
+ " 00:00:00+00')"
})
void deleteBeforeTime_givenValidTime_shouldDeleteOldRecords() {
// arrange
OffsetDateTime cutoffTime = OffsetDateTime.parse("2023-07-01T00:00:00Z");
// action
int deletedCount = aopLogRepository.deleteBeforeTime(cutoffTime);
// assert
assertThat(deletedCount).isEqualTo(2);
// verify remaining record
List<AopLog> remaining = aopLogRepository.findAll();
assertThat(remaining).hasSize(1);
assertThat(remaining.get(0).getId()).isEqualTo(3L);
}
@Test
void deleteByIds_givenEmptyList_shouldReturnZero() {
// arrange
List<Long> emptyIds = List.of();
// action
int deletedCount = aopLogRepository.deleteByIds(emptyIds);
// assert
assertThat(deletedCount).isEqualTo(0);
}
@Test
void deleteByIds_givenNullList_shouldReturnZero() {
// arrange & action
int deletedCount = aopLogRepository.deleteByIds(null);
// assert
assertThat(deletedCount).isEqualTo(0);
}
}

View File

@@ -20,6 +20,7 @@ import com.zl.mjga.repository.RoleRepository;
import com.zl.mjga.repository.UserRepository;
import com.zl.mjga.service.IdentityAccessService;
import com.zl.mjga.service.SignService;
import com.zl.mjga.service.UploadService;
import io.minio.MinioClient;
import jakarta.servlet.http.HttpServletRequest;
import java.util.Collections;
@@ -53,6 +54,7 @@ public class AuthenticationAndAuthorityTest {
@MockBean private PermissionRepository permissionRepository;
@MockBean private MinioClient minioClient;
@MockBean private MinIoConfig minIoConfig;
@MockBean private UploadService uploadService;
@Test
public void givenRequestOnPublicService_shouldSucceedWith200() throws Exception {

View File

@@ -0,0 +1,134 @@
package com.zl.mjga.unit;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
import com.zl.mjga.dto.PageRequestDto;
import com.zl.mjga.dto.PageResponseDto;
import com.zl.mjga.dto.aoplog.AopLogQueryDto;
import com.zl.mjga.dto.aoplog.AopLogRespDto;
import com.zl.mjga.repository.AopLogRepository;
import com.zl.mjga.service.AopLogService;
import java.time.OffsetDateTime;
import java.util.List;
import org.jooq.Record;
import org.jooq.Result;
import org.jooq.generated.mjga.tables.pojos.AopLog;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class)
public class AopLogServiceTest {
@Mock private AopLogRepository aopLogRepository;
@Mock private Result<Record> mockResult;
@Mock private Record mockRecord;
@InjectMocks private AopLogService aopLogService;
@Test
void saveLogAsync_givenValidAopLog_shouldCallRepositoryInsert() {
// arrange
AopLog aopLog = createTestAopLog();
// action
aopLogService.saveLogAsync(aopLog);
// assert
verify(aopLogRepository, times(1)).insert(aopLog);
}
@Test
void pageQueryAopLogs_givenValidRequest_shouldReturnPageResponse() {
// arrange
PageRequestDto pageRequestDto = PageRequestDto.of(1, 10);
AopLogQueryDto queryDto = new AopLogQueryDto();
when(aopLogRepository.pageFetchBy(pageRequestDto, queryDto)).thenReturn(mockResult);
when(mockResult.isEmpty()).thenReturn(false);
when(mockResult.map(any())).thenReturn(List.of(createTestAopLogRespDto()));
when(mockResult.get(0)).thenReturn(mockRecord);
when(mockRecord.getValue("total_count", Long.class)).thenReturn(1L);
// action
PageResponseDto<List<AopLogRespDto>> result =
aopLogService.pageQueryAopLogs(pageRequestDto, queryDto);
// assert
assertThat(result).isNotNull();
assertThat(result.getTotal()).isEqualTo(1L);
assertThat(result.getData()).hasSize(1);
verify(aopLogRepository, times(1)).pageFetchBy(pageRequestDto, queryDto);
}
@Test
void pageQueryAopLogs_givenEmptyResult_shouldReturnEmptyPage() {
// arrange
PageRequestDto pageRequestDto = PageRequestDto.of(1, 10);
AopLogQueryDto queryDto = new AopLogQueryDto();
when(aopLogRepository.pageFetchBy(pageRequestDto, queryDto)).thenReturn(mockResult);
when(mockResult.isEmpty()).thenReturn(true);
// action
PageResponseDto<List<AopLogRespDto>> result =
aopLogService.pageQueryAopLogs(pageRequestDto, queryDto);
// assert
assertThat(result).isNotNull();
assertThat(result.getTotal()).isEqualTo(0L);
assertThat(result.getData()).isNull();
}
@Test
void deleteLogsBeforeTime_givenValidTime_shouldReturnDeletedCount() {
// arrange
OffsetDateTime beforeTime = OffsetDateTime.now().minusDays(30);
when(aopLogRepository.deleteBeforeTime(beforeTime)).thenReturn(10);
// action
int result = aopLogService.deleteLogsBeforeTime(beforeTime);
// assert
assertThat(result).isEqualTo(10);
verify(aopLogRepository, times(1)).deleteBeforeTime(beforeTime);
}
private AopLog createTestAopLog() {
AopLog aopLog = new AopLog();
aopLog.setClassName("TestController");
aopLog.setMethodName("testMethod");
aopLog.setMethodArgs("[\"arg1\"]");
aopLog.setReturnValue("\"result\"");
aopLog.setExecutionTime(100L);
aopLog.setSuccess(true);
aopLog.setUserId(1L);
aopLog.setIpAddress("127.0.0.1");
aopLog.setUserAgent("Test Agent");
aopLog.setCreateTime(OffsetDateTime.now());
return aopLog;
}
private AopLogRespDto createTestAopLogRespDto() {
return AopLogRespDto.builder()
.id(1L)
.className("TestController")
.methodName("testMethod")
.methodArgs("[\"arg1\"]")
.returnValue("\"result\"")
.executionTime(100L)
.success(true)
.userId(1L)
.username("testUser")
.ipAddress("127.0.0.1")
.userAgent("Test Agent")
.createTime(OffsetDateTime.now())
.build();
}
}