package com.baiyue.eventbridge.service; import com.baiyue.eventbridge.domain.BridgeDeliveryAttempt; import com.baiyue.eventbridge.domain.BridgeInbox; import com.baiyue.eventbridge.mapper.BridgeDeliveryAttemptMapper; import com.baiyue.eventbridge.mapper.BridgeInboxMapper; import com.baiyue.eventbridge.metrics.EventBridgeMetrics; import io.micrometer.core.instrument.simple.SimpleMeterRegistry; import org.junit.jupiter.api.Test; import org.springframework.test.util.ReflectionTestUtils; import org.apache.ibatis.annotations.Update; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.*; class EventReplayServiceTest { private final BridgeInboxMapper mapper = mock(BridgeInboxMapper.class); private final BridgeDeliveryAttemptMapper attemptMapper = mock(BridgeDeliveryAttemptMapper.class); private final SimpleMeterRegistry registry = new SimpleMeterRegistry(); private final EventBridgeMetrics metrics = new EventBridgeMetrics(registry); private final EventReplayService service = service(); @Test void requeuesDeadEventWithAuditReason() { when(mapper.replayDead(eq("event-1"), contains("incident-42"))).thenReturn(1); BridgeInbox event = new BridgeInbox(); event.setEventId("event-1"); event.setSourceRegion("CN"); event.setTargetRegion("OVERSEAS"); event.setEventType(com.baiyue.common.event.EventTypes.FIRST_LEG_LOADING_PLAN_COMPLETED); when(mapper.selectById("event-1")).thenReturn(event); when(mapper.nextAttemptNo("event-1")).thenReturn(4); service.replayDead("event-1", "operator-7", "incident-42 approved"); verify(mapper).replayDead(eq("event-1"), contains("operator-7")); var captor = org.mockito.ArgumentCaptor.forClass(BridgeDeliveryAttempt.class); verify(attemptMapper).insert(captor.capture()); assertThat(captor.getValue().getAttemptNo()).isEqualTo(4); assertThat(captor.getValue().getStatus()).isEqualTo("MANUAL_REPLAY"); assertThat(captor.getValue().getErrorMessage()).contains("operator-7", "incident-42"); assertThat(registry.get(EventBridgeMetrics.TRANSPORT_METRIC) .tags("target_region", "OVERSEAS", "event_type", event.getEventType(), "result", "MANUAL_REPLAY").counter().count()).isEqualTo(1.0); } @Test void rejectsEventThatIsNotDead() { when(mapper.replayDead(anyString(), anyString())).thenReturn(0); assertThatThrownBy(() -> service.replayDead("event-1", "operator-7", "retry")) .isInstanceOf(IllegalStateException.class); } @Test void replayOnlyRequeuesDeadStateAndDoesNotRewriteFrozenEvent() throws Exception { String sql = String.join(" ", BridgeInboxMapper.class .getMethod("replayDead", String.class, String.class) .getAnnotation(Update.class).value()).replaceAll("\\s+", " "); assertThat(sql).contains("status='RETRY'", "retry_count=0", "status='DEAD'") .doesNotContain("payload_json=", "payload_hash="); } private EventReplayService service() { EventReplayService service = new EventReplayService(); ReflectionTestUtils.setField(service, "inboxMapper", mapper); ReflectionTestUtils.setField(service, "attemptMapper", attemptMapper); ReflectionTestUtils.setField(service, "metrics", metrics); return service; } }