2026-09-29 17:55:54 +08:00
|
|
|
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);
|
2026-09-29 18:06:18 +08:00
|
|
|
when(finance.fee("token", event)).thenReturn(ApiResponse.success(DeliveryAck.of(event, DeliveryAck.Outcome.APPLIED)));
|
2026-09-29 17:55:54 +08:00
|
|
|
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)))
|
2026-09-29 18:06:18 +08:00
|
|
|
.isInstanceOf(com.baiyue.common.web.EventDeliveryFailure.class).hasMessageContaining("Unsupported outbound");
|
2026-09-29 17:55:54 +08:00
|
|
|
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");
|
2026-09-29 18:47:37 +08:00
|
|
|
return new EventEnvelope("00000000-0000-4000-8000-000000000009", type, 1, Instant.now(), "1", "BUSINESS", "1", 1L, null,
|
2026-09-29 17:55:54 +08:00
|
|
|
"trace", "correlation", null, payload,
|
|
|
|
|
EventPayloadHash.sha256(EventPayloadCanonicalizer.canonicalize(payload)));
|
|
|
|
|
}
|
|
|
|
|
}
|