package com.baiyue.integration.provider; import com.baiyue.integration.dto.CarrierScheduleDtos.QueryRequest; import com.fasterxml.jackson.databind.ObjectMapper; 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 SmlCarrierScheduleProviderAdapterTest { private final ObjectMapper objectMapper = new ObjectMapper(); @Test void appendedMilestoneAndRevisedEstimateDoNotChangeExistingEventProjection() throws Exception { String raw = """ {"events":[{"actCd":"FOTMAD","actTpCd":"A","eventDt":"2026-08-01 15:55"}, {"actCd":"FUVMAD","actTpCd":"E","eventDt":"2026-08-23 14:00"}]} """; String next = raw.replace("08-23", "08-24").replace("]}", ",{\"actCd\":\"FLVMLO\",\"actTpCd\":\"A\",\"eventDt\":\"2026-08-04 19:45\"}]}"); var adapter = new SmlCarrierScheduleProviderAdapter(mock(SmlTrackingClient.class)); var before = adapter.observations("SMCU7019890", new SmlTrackingClient.TrackingResponse("BKG", "COP", objectMapper.readTree(raw), objectMapper.createObjectNode(), objectMapper.createObjectNode(), raw)); var after = adapter.observations("SMCU7019890", new SmlTrackingClient.TrackingResponse("BKG", "COP", objectMapper.readTree(next), objectMapper.createObjectNode(), objectMapper.createObjectNode(), next)); CarrierResponseAuditAssertions.stableSharedFacts(before, after, raw, next); assertThat(after).hasSize(before.size() + 1); } @Test void sevenSampleBoundaryUsesActTypeAndLeavesFitmdoUnmapped() throws Exception { String timeline = """ {"TRANS_RESULT_KEY":"S","count":9,"events":[ {"actCd":"FOTMAD","actTpCd":"A","eventDt":"2026-08-01 15:55"}, {"actCd":"FLVMLO","actTpCd":"A","eventDt":"2026-08-04 19:45"}, {"actCd":"FLVMDO","actTpCd":"A","eventDt":"2026-08-07 17:00"}, {"actCd":"FUVMAD","actTpCd":"E","eventDt":"2026-08-23 14:00"}, {"actCd":"FUVMBD","actTpCd":"E","eventDt":"2026-08-23 16:00"}, {"actCd":"FUVMUD","actTpCd":"E","eventDt":"2026-08-24 08:00"}, {"actCd":"FITMDO","actTpCd":"E","eventDt":"2026-08-25 08:00"}, {"actCd":"MITYAD","actTpCd":"E","eventDt":"2026-09-01 08:00"}, {"actCd":"MOTYDO","actTpCd":"A","eventDt":"2026-07-28 08:00"}]} """; SmlTrackingClient client = mock(SmlTrackingClient.class); when(client.configured()).thenReturn(true); var response = new SmlTrackingClient.TrackingResponse("SMLBKG", "COP1", objectMapper.readTree(timeline), objectMapper.createObjectNode(), objectMapper.createObjectNode(), timeline); when(client.query(new QueryRequest("SML", "CONTAINER_NO", "SMCU7019890"))).thenReturn(response); var result = new SmlCarrierScheduleProviderAdapter(client) .query(new QueryRequest("SML", "CONTAINER_NO", "SMCU7019890")); assertThat(result.observations()).hasSize(7); assertThat(result.observations()).filteredOn(value -> value.actualAt() != null) .extracting(value -> value.standardNode()) .containsExactlyInAnyOrder("AT_ORIGIN_PORT", "LOADED_ON_VESSEL", "DEPARTED_ORIGIN_PORT"); assertThat(result.observations()).filteredOn(value -> value.estimatedAt() != null).hasSize(4); assertThat(result.observations()).extracting(value -> value.observedAt()) .containsOnly(result.observations().get(0).observedAt()); assertThat(result.observations()).extracting(value -> value.providerNodeCode()) .doesNotContain("FITMDO", "MOTYDO"); } @Test void onlyActualMityadCanBecomeActualEmptyReturn() throws Exception { String timeline = """ {"events":[ {"actCd":"MITYAD","actTpCd":"E","eventDt":"2026-09-01 08:00"}, {"actCd":"MITYAD","actTpCd":"A","eventDt":"2026-09-02 09:00"}]} """; var response = new SmlTrackingClient.TrackingResponse("BKG", "COP", objectMapper.readTree(timeline), objectMapper.createObjectNode(), objectMapper.createObjectNode(), timeline); var values = new SmlCarrierScheduleProviderAdapter(mock(SmlTrackingClient.class)) .observations("SMCU7019890", response); assertThat(values).filteredOn(value -> value.actualAt() != null).singleElement() .satisfies(value -> assertThat(value.standardNode()).isEqualTo("EMPTY_RETURNED")); assertThat(values).filteredOn(value -> value.estimatedAt() != null).singleElement(); } @Test void ambiguousFitmdoAndCargoEmptyReleaseStayUnmapped() { assertThat(SmlCarrierScheduleProviderAdapter.standardNode("FITMDO")).isNull(); assertThat(SmlCarrierScheduleProviderAdapter.standardNode("MOTYDO")).isNull(); assertThat(SmlCarrierScheduleProviderAdapter.standardNode("FUVMUD")) .isEqualTo("DISCHARGED_FROM_VESSEL"); } }