106 lines
5.5 KiB
Java
106 lines
5.5 KiB
Java
package com.baiyue.integration.provider;
|
|
|
|
import com.baiyue.integration.dto.CarrierScheduleDtos.QueryRequest;
|
|
import com.baiyue.integration.provider.HedeTrackingClient.TrackingResponse;
|
|
import org.junit.jupiter.api.Test;
|
|
|
|
import static org.assertj.core.api.Assertions.assertThat;
|
|
import static org.mockito.Mockito.mock;
|
|
import static org.mockito.Mockito.when;
|
|
|
|
class HedeCarrierScheduleProviderAdapterTest {
|
|
@Test
|
|
void appendedLoadingAndChangedEtaPreserveGateEventProjection() throws Exception {
|
|
String raw = row("FFAU4879673", "2026-08-05 04:24", "2026-08-22 00:00", "2026-07-30 21:31", "2026-08-01 15:55", "", "", "", "");
|
|
String next = row("FFAU4879673", "2026-08-05 04:24", "2026-08-23 00:00", "2026-07-30 21:31", "2026-08-01 15:55", "2026-08-04 19:45", "", "", "");
|
|
var adapter = new HedeCarrierScheduleProviderAdapter(mock(HedeTrackingClient.class));
|
|
var before = adapter.observations("FFAU4879673", raw);
|
|
var after = adapter.observations("FFAU4879673", next);
|
|
CarrierResponseAuditAssertions.stableSharedFacts(before, after, raw, next);
|
|
assertThat(after).hasSize(before.size() + 1);
|
|
}
|
|
@Test
|
|
void parsesConfirmedMainTableColumnsAndDoesNotTurnEtaIntoAnActualNode() throws Exception {
|
|
String html = row("XYLU8251457", "2026-08-20 00:00", "2026-09-09 00:00",
|
|
"", "", "", "", "", "");
|
|
|
|
var rows = HedeCarrierScheduleProviderAdapter.rows(html);
|
|
HedeTrackingClient client = mock(HedeTrackingClient.class);
|
|
HedeCarrierScheduleProviderAdapter adapter = new HedeCarrierScheduleProviderAdapter(client);
|
|
|
|
assertThat(rows).singleElement().satisfies(value -> {
|
|
assertThat(value.containerNo()).isEqualTo("XYLU8251457");
|
|
assertThat(value.vessel()).isEqualTo("POSEN");
|
|
assertThat(value.voyage()).isEqualTo("2607W");
|
|
assertThat(value.estimatedDeparture()).isEqualTo("2026-08-20 00:00");
|
|
assertThat(value.estimatedArrival()).isEqualTo("2026-09-09 00:00");
|
|
});
|
|
assertThat(adapter.observations("XYLU8251457", html)).extracting(value -> value.standardNode())
|
|
.containsExactlyInAnyOrder("DEPARTED_ORIGIN_PORT", "ARRIVED_DESTINATION_PORT");
|
|
assertThat(adapter.observations("XYLU8251457", html)).allSatisfy(value -> {
|
|
assertThat(value.estimatedAt()).isNotNull();
|
|
assertThat(value.actualAt()).isNull();
|
|
});
|
|
}
|
|
|
|
@Test
|
|
void mapsOnlyActualHedeMilestonesForTheRequestedContainer() {
|
|
String html = row("FFAU4879673", "2026-08-05 04:24", "2026-08-22 00:00",
|
|
"2026-07-30 21:31", "2026-08-01 15:55", "2026-08-04 19:45", "", "", "");
|
|
HedeTrackingClient client = mock(HedeTrackingClient.class);
|
|
when(client.configured()).thenReturn(true);
|
|
when(client.query(new QueryRequest("HEDE", "CONTAINER_NO", "FFAU4879673")))
|
|
.thenReturn(new TrackingResponse(html));
|
|
HedeCarrierScheduleProviderAdapter adapter = new HedeCarrierScheduleProviderAdapter(client);
|
|
|
|
var result = adapter.query(new QueryRequest("HEDE", "CONTAINER_NO", "FFAU4879673"));
|
|
|
|
assertThat(result.outcome()).isEqualTo("SUCCESS");
|
|
assertThat(result.observations()).extracting(value -> value.standardNode())
|
|
.containsExactlyInAnyOrder("DEPARTED_ORIGIN_PORT", "ARRIVED_DESTINATION_PORT", "AT_ORIGIN_PORT",
|
|
"LOADED_ON_VESSEL");
|
|
assertThat(result.observations()).allSatisfy(value -> {
|
|
assertThat(value.providerEventId()).hasSize(64);
|
|
assertThat(value.rawPayloadHash()).hasSize(64);
|
|
assertThat(value.sourceReference()).contains("FFAU4879673").contains("POSEN/2607W");
|
|
});
|
|
assertThat(result.observations()).extracting(value -> value.observedAt())
|
|
.containsOnly(result.observations().get(0).observedAt());
|
|
}
|
|
|
|
@Test
|
|
void actualEmptyReturnIsMappedPrecisely() throws Exception {
|
|
String html = row("FFAU4879673", "2026-08-05 04:24", "2026-08-22 00:00",
|
|
"2026-07-30 21:31", "2026-08-01 15:55", "2026-08-04 19:45", "", "",
|
|
"2026-08-28 08:00");
|
|
HedeTrackingClient client = mock(HedeTrackingClient.class);
|
|
var result = new HedeCarrierScheduleProviderAdapter(client).observations("FFAU4879673", html);
|
|
assertThat(result).filteredOn(value -> "EMPTY_RETURNED".equals(value.standardNode()))
|
|
.singleElement().satisfies(value -> {
|
|
assertThat(value.actualAt()).isNotNull();
|
|
assertThat(value.estimatedAt()).isNull();
|
|
});
|
|
}
|
|
|
|
@Test
|
|
void refusesAmbiguousBillLevelAutomation() {
|
|
HedeTrackingClient client = mock(HedeTrackingClient.class);
|
|
HedeCarrierScheduleProviderAdapter adapter = new HedeCarrierScheduleProviderAdapter(client);
|
|
|
|
var result = adapter.query(new QueryRequest("HEDE", "BILL_OF_LADING", "HDE123"));
|
|
|
|
assertThat(result.outcome()).isEqualTo("PERMANENT_FAILURE");
|
|
assertThat(result.errorCode()).isEqualTo("HEDE_CONTAINER_REQUIRED");
|
|
}
|
|
|
|
private static String row(String container, String etd, String eta, String emptyOut, String fullIn,
|
|
String loaded, String discharged, String fullOut, String emptyReturned) {
|
|
return "<table><tbody><tr class=\"read-tr\">"
|
|
+ td("***") + td(container) + td("POSEN") + td("2607W") + td(etd) + td(eta)
|
|
+ td(emptyOut) + td(fullIn) + td(loaded) + td(discharged) + td(fullOut) + td(emptyReturned)
|
|
+ td("查看") + "</tr></tbody></table>";
|
|
}
|
|
|
|
private static String td(String value) { return "<td>" + value + "</td>"; }
|
|
}
|