This commit is contained in:
2026-09-29 17:55:54 +08:00
parent 41d8387cd5
commit 54ad26c607
111 changed files with 1837 additions and 962 deletions
@@ -0,0 +1,77 @@
package com.baiyue.lastleg.client;
import com.baiyue.common.core.api.ApiResponse;
import com.baiyue.common.event.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import java.time.Instant;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
class DirectEventClientTest {
private final FirstlegEventClient firstleg = mock(FirstlegEventClient.class);
private final FinanceBusinessEventClient finance = mock(FinanceBusinessEventClient.class);
private final DirectEventClient client = new DirectEventClient(firstleg, finance);
@Test void walletIsSentOnlyToFinance() {
var event = event(EventTypes.WALLET_COMMAND_REQUESTED);
var ack = ApiResponse.success(DeliveryAck.of(event, DeliveryAck.Outcome.APPLIED));
when(finance.wallet("token", event)).thenReturn(ack);
assertThat(client.receive("token", event)).isSameAs(ack);
verify(finance).wallet("token", event);
verifyNoMoreInteractions(finance);
verifyNoInteractions(firstleg);
}
@Test void feeIsSentOnlyToFinance() {
var event = event(EventTypes.BUSINESS_FEE_SOURCE_CHANGED);
client.receive("token", event);
verify(finance).fee("token", event);
verifyNoMoreInteractions(finance);
verifyNoInteractions(firstleg);
}
@Test void fulfillmentEventsAreSentOnlyToFirstleg() {
for (String type : new String[]{EventTypes.OVERSEAS_CONTAINER_UNLOADED,
EventTypes.OVERSEAS_INBOUND_ORDER_DETAINED_CHANGED, EventTypes.OVERSEAS_DELIVERY_COMPLETED}) {
var event = event(type);
client.receive("token", event);
verify(firstleg).receive("token", event);
}
verifyNoInteractions(finance);
}
@Test void unsupportedEventsHaveNoDefaultDestination() {
assertThatThrownBy(() -> client.receive("token", event(EventTypes.WALLET_COMMAND_COMPLETED)))
.isInstanceOf(IllegalArgumentException.class).hasMessageContaining("Unsupported outbound");
verifyNoInteractions(firstleg, finance);
}
@Test void declaredEndpointsMatchTheSharedRouteTable() throws Exception {
assertEndpoint(FirstlegEventClient.class, "receive", "FIRSTLEG_SERVICE_URL", "firstleg",
EventTypes.OVERSEAS_CONTAINER_UNLOADED);
assertEndpoint(FinanceBusinessEventClient.class, "wallet", "FINANCE_SERVICE_URL", "finance",
EventTypes.WALLET_COMMAND_REQUESTED);
assertEndpoint(FinanceBusinessEventClient.class, "fee", "FINANCE_SERVICE_URL", "finance",
EventTypes.BUSINESS_FEE_SOURCE_CHANGED);
}
private void assertEndpoint(Class<?> type, String method, String env, String property, String eventType) throws Exception {
var route = EventDeliveryRoute.forEventType(eventType);
var annotation = type.getAnnotation(FeignClient.class);
assertThat(annotation.name()).isEqualTo(route.serviceName());
assertThat(annotation.url()).isEqualTo("${" + env + ":${baiyue.clients." + property + ".url:}}");
assertThat(type.getMethod(method, String.class, EventEnvelope.class).getAnnotation(PostMapping.class).value())
.containsExactly(route.path());
}
private EventEnvelope event(String type) {
var payload = new ObjectMapper().createObjectNode().put("businessNo", "test");
return new EventEnvelope("00000000-0000-4000-8000-000000000009", type, 1, Instant.now(),
RegionCode.OVERSEAS, RegionCode.CN, "1", "BUSINESS", "1", 1L, null,
"trace", "correlation", null, payload,
EventPayloadHash.sha256(EventPayloadCanonicalizer.canonicalize(payload)));
}
}