114 lines
4.2 KiB
Java
114 lines
4.2 KiB
Java
package com.baiyue.common.audit;
|
|
|
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
import jakarta.annotation.Resource;
|
|
import org.apache.rocketmq.spring.core.RocketMQTemplate;
|
|
import org.junit.jupiter.api.Test;
|
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
|
import org.springframework.context.annotation.Bean;
|
|
import org.springframework.context.annotation.Configuration;
|
|
import org.springframework.messaging.Message;
|
|
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
|
import org.springframework.transaction.support.TransactionOperations;
|
|
|
|
import java.time.Instant;
|
|
import java.util.List;
|
|
|
|
import static org.mockito.ArgumentMatchers.any;
|
|
import static org.mockito.ArgumentMatchers.anyLong;
|
|
import static org.mockito.ArgumentMatchers.anyString;
|
|
import static org.mockito.ArgumentMatchers.eq;
|
|
import static org.mockito.Mockito.doThrow;
|
|
import static org.mockito.Mockito.verify;
|
|
import static org.mockito.Mockito.when;
|
|
|
|
@SpringJUnitConfig(ReliableAuditDeliveryTest.Config.class)
|
|
class ReliableAuditDeliveryTest {
|
|
@MockBean
|
|
private AuditOutboxRepository repository;
|
|
@MockBean
|
|
private RocketMQTemplate rocketMQ;
|
|
@MockBean
|
|
private TransactionOperations transactions;
|
|
@Resource
|
|
private OutboxAuditSink sink;
|
|
@Resource
|
|
private AuditOutboxPublisher publisher;
|
|
|
|
@Test
|
|
void storesEventBeforeDelivery() {
|
|
AuditEvent event = event("audit-1");
|
|
org.mockito.Mockito.doAnswer(invocation -> {
|
|
java.util.function.Consumer<?> callback = invocation.getArgument(0);
|
|
((java.util.function.Consumer<Object>) callback).accept(null);
|
|
return null;
|
|
}).when(transactions).executeWithoutResult(any());
|
|
|
|
sink.publish(event);
|
|
|
|
verify(repository).append(eq(event), anyString());
|
|
}
|
|
|
|
@Test
|
|
void marksDeliveredMessageSent() {
|
|
when(repository.publishableIds(50)).thenReturn(List.of("audit-1"));
|
|
when(repository.claim("audit-1", "test-owner", 60)).thenReturn(true);
|
|
when(repository.find("audit-1"))
|
|
.thenReturn(new AuditOutboxRepository.OutboxRow("audit-1", "{}", 1));
|
|
|
|
publisher.publish();
|
|
|
|
verify(rocketMQ).syncSend(anyString(), any(Message.class), anyLong());
|
|
verify(repository).sent("audit-1", "test-owner");
|
|
}
|
|
|
|
@Test
|
|
void schedulesRetryAfterMqFailure() {
|
|
when(repository.publishableIds(50)).thenReturn(List.of("audit-2"));
|
|
when(repository.claim("audit-2", "test-owner", 60)).thenReturn(true);
|
|
when(repository.find("audit-2"))
|
|
.thenReturn(new AuditOutboxRepository.OutboxRow("audit-2", "{}", 1));
|
|
doThrow(new IllegalStateException("broker unavailable"))
|
|
.when(rocketMQ).syncSend(anyString(), any(Message.class), anyLong());
|
|
|
|
publisher.publish();
|
|
|
|
verify(repository).failed("audit-2", "test-owner", 5, 5, "broker unavailable");
|
|
}
|
|
|
|
private static AuditEvent event(String id) {
|
|
return new AuditEvent(id, "ROLE_UPDATE", "ROLE", "1", "修改角色",
|
|
"request-1", "trace-1", 1L, 1L, 1L, "admin", "PLATFORM", "WEB",
|
|
"PUT", "/roles/1", "127.0.0.1", 10, true, null, null,
|
|
null, null, Instant.parse("2026-08-05T00:00:00Z"), "iam-service");
|
|
}
|
|
|
|
@Configuration
|
|
static class Config {
|
|
@Bean
|
|
ObjectMapper objectMapper() { return new ObjectMapper().findAndRegisterModules(); }
|
|
|
|
@Bean
|
|
AuditProperties properties() {
|
|
AuditProperties value = new AuditProperties();
|
|
value.getOutbox().setBatchSize(50);
|
|
value.getOutbox().setLeaseSeconds(60);
|
|
value.getOutbox().setMaxAttempts(5);
|
|
value.getRocketmq().setTopic("test-baiyue-audit-event-v1");
|
|
return value;
|
|
}
|
|
|
|
@Bean
|
|
OutboxAuditSink sink(AuditOutboxRepository repository, ObjectMapper json,
|
|
TransactionOperations transactions) {
|
|
return new OutboxAuditSink(repository, json, transactions);
|
|
}
|
|
|
|
@Bean
|
|
AuditOutboxPublisher publisher(AuditOutboxRepository repository, RocketMQTemplate rocketMQ,
|
|
AuditProperties properties) {
|
|
return new AuditOutboxPublisher(repository, rocketMQ, properties, "test-owner");
|
|
}
|
|
}
|
|
}
|