Merge remote-tracking branch 'origin/test' into dev
This commit is contained in:
@@ -40,6 +40,8 @@ import com.baiyue.firstleg.oceanbooking.entity.OceanBookingEntity;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
import org.mockito.InOrder;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
@@ -785,6 +787,7 @@ class LoadingPickServiceTest {
|
||||
|
||||
@Test
|
||||
void failedSameOperationIdCanResumeWithoutCreatingAnotherCommand() {
|
||||
assertNoTruckCoupling();
|
||||
LoadingPickTaskEntity failed = task();
|
||||
failed.setTaskStatus("COMPLETION_FAILED");
|
||||
LoadingPickTaskEntity completing = task();
|
||||
@@ -871,6 +874,35 @@ class LoadingPickServiceTest {
|
||||
verify(completionCommands).complete(900L, "worker-1");
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "truck state {0} never participates in PDA completion")
|
||||
@ValueSource(strings = {"NO_APPOINTMENT", "DRAFT", "IN_PROGRESS", "COMPLETED"})
|
||||
void completionWorkerIsIndependentOfEveryTruckAppointmentState(String truckState) {
|
||||
assertNoTruckCoupling();
|
||||
LoadingPickTaskEntity completing = task();
|
||||
completing.setTaskStatus("COMPLETING");
|
||||
when(repository.task(20L)).thenReturn(completing);
|
||||
when(repository.inboundOwners(20L)).thenReturn(List.of(
|
||||
new LoadingPickItemMapper.InboundOwner(101L, 50L)));
|
||||
when(repository.allPlanItemsPicked(10L)).thenReturn(true);
|
||||
when(repository.review(20L)).thenReturn(null);
|
||||
when(repository.approve(20L, 9L, "operator", "checked")).thenReturn(1);
|
||||
when(repository.completeAccepted(20L, 9L, "operator")).thenReturn(1);
|
||||
long commandId = 920L + Math.abs(truckState.hashCode() % 20);
|
||||
when(completionCommands.complete(commandId, "worker-truck-independent")).thenReturn(true);
|
||||
|
||||
service.processCompletion(completionCommand(commandId,
|
||||
"async-truck-independent-" + truckState.toLowerCase()), "worker-truck-independent");
|
||||
|
||||
verify(cabinetEvidenceService).requireComplete(99L);
|
||||
verify(settlementService).settleOwner(20L, 50L, 9L, "operator");
|
||||
verify(loadingDeliveryService).completeAfterPdaSettlement(101L, 50L, 9L, "operator",
|
||||
"PDA-async-truck-independent-" + truckState.toLowerCase() + "-50", "checked");
|
||||
verify(loadingListService).finishFromPda(10L, 20L, 9L, "operator");
|
||||
verify(loadingListService).publishCompletedEvent(10L);
|
||||
verify(repository).completeAccepted(20L, 9L, "operator");
|
||||
verify(completionCommands).complete(commandId, "worker-truck-independent");
|
||||
}
|
||||
|
||||
@Test
|
||||
void workerUsesCabinetEvidenceOnceWithReversedTwoCustomerOwnerOrder() {
|
||||
LoadingPickTaskEntity completing = task();
|
||||
@@ -911,6 +943,7 @@ class LoadingPickServiceTest {
|
||||
|
||||
@Test
|
||||
void secondCustomerOwnerReadyFailureLeavesEveryOwnerUnsettledAndUncompleted() {
|
||||
assertNoTruckCoupling();
|
||||
LoadingPickTaskEntity completing = task();
|
||||
completing.setTaskStatus("COMPLETING");
|
||||
when(repository.task(20L)).thenReturn(completing);
|
||||
@@ -939,6 +972,7 @@ class LoadingPickServiceTest {
|
||||
|
||||
@Test
|
||||
void workerRestartResumesFromOwnerCheckpointsWithoutRepeatingSettlements() {
|
||||
assertNoTruckCoupling();
|
||||
LoadingPickTaskEntity completing = task();
|
||||
completing.setTaskStatus("COMPLETING");
|
||||
when(repository.task(20L)).thenReturn(completing);
|
||||
@@ -1180,6 +1214,14 @@ class LoadingPickServiceTest {
|
||||
verify(repository, never()).touchTask(any(Long.class), any(Integer.class));
|
||||
}
|
||||
|
||||
private static void assertNoTruckCoupling() {
|
||||
assertThat(LoadingPickService.class.getDeclaredFields())
|
||||
.noneMatch(field -> field.getType().equals(TruckAppointmentService.class));
|
||||
assertThat(LoadingPickService.class.getDeclaredMethods())
|
||||
.noneMatch(method -> method.getName().equals("completeTruckAfterCommit")
|
||||
|| method.getName().equals("completeLoadingFromPda"));
|
||||
}
|
||||
|
||||
private void preparePick(LoadingPickTaskEntity task, LoadingPickItemEntity item, String operationId) {
|
||||
when(repository.history(operationId)).thenReturn(null);
|
||||
when(repository.task(20L)).thenReturn(task);
|
||||
|
||||
@@ -455,6 +455,78 @@ class TruckAppointmentServiceTest {
|
||||
assertThat(history.getValue().getToStatus()).isEqualTo("RESCHEDULED");
|
||||
}
|
||||
|
||||
@Test void createRejectsUnknownBookingWithoutWriting() {
|
||||
SaveRequest request = validRequest();
|
||||
when(oceanBookings.find(99L)).thenReturn(null);
|
||||
|
||||
assertThatThrownBy(() -> service.create(7L, "admin", request))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("关联订舱不存在");
|
||||
|
||||
verify(repository, never()).insert(any());
|
||||
verify(repository, never()).history(any());
|
||||
}
|
||||
|
||||
@Test void createRejectsWarehouseMismatchWithoutWriting() {
|
||||
SaveRequest request = validRequest();
|
||||
when(request.warehouseId()).thenReturn(19L);
|
||||
|
||||
assertThatThrownBy(() -> service.create(7L, "admin", request))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("warehouseId与订舱不一致");
|
||||
|
||||
verify(repository, never()).insert(any());
|
||||
}
|
||||
|
||||
@Test void createRejectsInvalidTruckingSupplierWithoutWriting() {
|
||||
SaveRequest request = validRequest();
|
||||
when(suppliers.trucking(8L, null)).thenThrow(
|
||||
new BizException(com.baiyue.common.core.api.ResultCode.CONFLICT, "拖车服务商未启用"));
|
||||
|
||||
assertThatThrownBy(() -> service.create(7L, "admin", request))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("拖车服务商未启用");
|
||||
|
||||
verify(repository, never()).insert(any());
|
||||
}
|
||||
|
||||
@Test void editRejectsTargetBookingOwnedByAnotherActiveAppointment() {
|
||||
TruckAppointmentEntity current = entity(TruckAppointmentStatus.DRAFT, 3);
|
||||
current.setOceanBookingId(99L);
|
||||
TruckAppointmentEntity occupied = entity(TruckAppointmentStatus.PENDING_DISPATCH, 1);
|
||||
occupied.setId(2L); occupied.setOceanBookingId(199L); occupied.setAppointmentNo("TA-260901-0099");
|
||||
SaveRequest request = validRequest();
|
||||
when(request.expectedVersion()).thenReturn(3);
|
||||
when(request.oceanBookingId()).thenReturn(199L);
|
||||
OceanBookingEntity target = releasedBooking(); target.setId(199L);
|
||||
when(oceanBookings.find(199L)).thenReturn(target);
|
||||
when(repository.find(1L)).thenReturn(current);
|
||||
when(repository.firstActiveForUpdate(199L)).thenReturn(occupied);
|
||||
|
||||
assertThatThrownBy(() -> service.edit(1L, 7L, "admin", request))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("TA-260901-0099");
|
||||
|
||||
verify(repository, never()).updateEdit(any(), anyInt());
|
||||
}
|
||||
|
||||
@Test void detailJsonContainsNoContainerProtocolFields() throws Exception {
|
||||
TruckAppointmentEntity appointment = entity(TruckAppointmentStatus.DRAFT, 0);
|
||||
appointment.setOceanBookingId(99L); appointment.setContainerBookingId(88L);
|
||||
appointment.setLoadingPlanId(77L); appointment.setCabinetNo("CAB-OLD"); appointment.setContainerNo("MSCU6639870");
|
||||
when(repository.find(1L)).thenReturn(appointment);
|
||||
|
||||
String json = objectMapper.writeValueAsString(service.detail(1L));
|
||||
|
||||
assertThat(json).doesNotContain("containerBookingId", "loadingPlanId", "cabinetNo", "containerNo", "containers");
|
||||
assertThat(json).contains("oceanBookingId");
|
||||
}
|
||||
|
||||
@Test void deleteAttachmentKeepsAppointmentOwnershipGuard() {
|
||||
when(repository.find(1L)).thenReturn(entity(TruckAppointmentStatus.DRAFT, 0));
|
||||
when(repository.deleteAttachment(1L, 77L)).thenReturn(1);
|
||||
|
||||
service.deleteAttachment(1L, 77L);
|
||||
|
||||
verify(repository).deleteAttachment(1L, 77L);
|
||||
}
|
||||
|
||||
private String requestHash(String action, long id, Object request) throws Exception {
|
||||
String canonical = action + '|' + id + '|' + objectMapper.writeValueAsString(request);
|
||||
return java.util.HexFormat.of().formatHex(java.security.MessageDigest.getInstance("SHA-256")
|
||||
|
||||
Reference in New Issue
Block a user