Files
baiyue-firstleg/lastleg-service/src/test/java/com/baiyue/lastleg/client/DirectEventClientTest.java
T

101 lines
5.3 KiB
Java

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);
when(finance.fee("token", event)).thenReturn(ApiResponse.success(DeliveryAck.of(event, DeliveryAck.Outcome.APPLIED)));
client.receive("token", event);
verify(finance).fee("token", event);
verifyNoMoreInteractions(finance);
verifyNoInteractions(firstleg);
}
@Test void companyVehicleCostsUseTheirOwnFinanceEndpoint() {
var event = event(EventTypes.COMPANY_VEHICLE_COST_SUBMITTED);
var ack = ApiResponse.success(DeliveryAck.of(event, DeliveryAck.Outcome.APPLIED));
when(finance.vehicleCost("token", event)).thenReturn(ack);
assertThat(client.receive("token", event)).isSameAs(ack);
verify(finance).vehicleCost("token", event);
verifyNoMoreInteractions(finance);
verifyNoInteractions(firstleg);
}
@Test void companyCostValidationConflictsArePermanentButDependencyFailuresRetry() {
var event = event(EventTypes.COMPANY_VEHICLE_COST_SUBMITTED);
for (String code : new String[]{"FIN_400", "FIN_404", "FIN_409", "FIN_503"}) {
when(finance.vehicleCost("token", event)).thenReturn(new ApiResponse<>(code, "rejected", null, null, null, Instant.now()));
assertThatThrownBy(() -> client.receive("token", event))
.isInstanceOf(com.baiyue.common.web.EventDeliveryFailure.class)
.satisfies(error -> assertThat(com.baiyue.common.web.EventDeliveryFailure.isPermanent((Exception) error)).isEqualTo(!"FIN_503".equals(code)));
}
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(com.baiyue.common.web.EventDeliveryFailure.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);
assertEndpoint(FinanceBusinessEventClient.class, "vehicleCost", "FINANCE_SERVICE_URL", "finance",
EventTypes.COMPANY_VEHICLE_COST_SUBMITTED);
}
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(), "1", "BUSINESS", "1", 1L, null,
"trace", "correlation", null, payload,
EventPayloadHash.sha256(EventPayloadCanonicalizer.canonicalize(payload)));
}
}