fix(firstleg): validate public port schedule queries with zero scope
This commit is contained in:
@@ -16,7 +16,7 @@ import java.util.List;
|
||||
public final class PortScheduleDtos {
|
||||
private PortScheduleDtos() {}
|
||||
|
||||
public record Query(@Positive Long customerId, @Positive Long oceanBookingId,
|
||||
public record Query(@Min(0) Long customerId, @Positive Long oceanBookingId,
|
||||
@Positive Long containerBookingId, Boolean expired,
|
||||
@Size(max = 128) String keyword, @Min(1) long page,
|
||||
@Min(1) @Max(200) long size) {
|
||||
|
||||
+40
@@ -15,6 +15,7 @@ import com.baiyue.firstleg.portschedule.repository.PortScheduleRepository;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import jakarta.validation.Validation;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
@@ -34,6 +35,16 @@ import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
class PortScheduleServiceTest {
|
||||
@Test
|
||||
void platformPublicQueryAllowsZeroButRejectsNegativeCustomerScope() {
|
||||
try (var factory = Validation.buildDefaultValidatorFactory()) {
|
||||
var validator = factory.getValidator();
|
||||
assertThat(validator.validate(new com.baiyue.firstleg.portschedule.dto.PortScheduleDtos.Query(
|
||||
0L, null, null, null, null, 1, 5))).isEmpty();
|
||||
assertThat(validator.validate(new com.baiyue.firstleg.portschedule.dto.PortScheduleDtos.Query(
|
||||
-1L, null, null, null, null, 1, 5))).anyMatch(row -> row.getPropertyPath().toString().equals("customerId"));
|
||||
}
|
||||
}
|
||||
@Mock private PortScheduleRepository repository;
|
||||
@InjectMocks private PortScheduleService service;
|
||||
|
||||
@@ -79,6 +90,35 @@ class PortScheduleServiceTest {
|
||||
verify(repository, never()).insert(any(PortScheduleEntity.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void platformBookingRequiresZeroScopeAndRejectsArbitraryCustomerWithoutInsert() {
|
||||
OceanBookingEntity platformBooking = new OceanBookingEntity();
|
||||
platformBooking.setId(10L);
|
||||
when(repository.oceanBooking(10L)).thenReturn(platformBooking);
|
||||
assertThatThrownBy(() -> service.create(7L, "admin", "wrong-platform-scope",
|
||||
new CreateRequest(0, data(null, future(1), future(2)), null)))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("customerId与订舱客户不一致");
|
||||
verify(repository, never()).insert(any(PortScheduleEntity.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void createsZeroScopeScheduleForPlatformBooking() {
|
||||
OceanBookingEntity platformBooking = new OceanBookingEntity();
|
||||
platformBooking.setId(10L);
|
||||
when(repository.oceanBooking(10L)).thenReturn(platformBooking);
|
||||
when(repository.containerBooking(20L)).thenReturn(new ContainerBookingEntity());
|
||||
when(repository.allocation(10L, 20L)).thenReturn(new OceanBookingContainerAllocationEntity());
|
||||
ScheduleData d = data(20L, future(1), future(2));
|
||||
ScheduleData platformData = new ScheduleData(0L, d.oceanBookingId(), d.containerBookingId(),
|
||||
d.sourceType(), d.sourceName(), d.sourceRef(), d.vesselName(), d.voyageNo(),
|
||||
d.departurePortCode(), d.departurePortName(), d.destinationPortCode(), d.destinationPortName(),
|
||||
d.etdAt(), d.etaAt(), d.bookingCutoffAt(), d.customsCutoffAt(), d.portCutoffAt(),
|
||||
d.observedAt(), d.expiresAt(), d.remark());
|
||||
Detail result = service.create(7L, "admin", "platform-scope-create",
|
||||
new CreateRequest(0, platformData, "平台公共船期"));
|
||||
assertThat(result.portSchedule().schedule().getCustomerId()).isZero();
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsStaleUpdateWithoutMutation() {
|
||||
when(repository.find(1L)).thenReturn(schedule(3));
|
||||
|
||||
Reference in New Issue
Block a user