暂存提交
This commit is contained in:
+31
@@ -0,0 +1,31 @@
|
||||
package com.baiyue.lastleg.service;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.stream.IntStream;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
class LastlegOrderNoGeneratorTest {
|
||||
@Test void actualContainerNumberIsStableAndShared() {
|
||||
LastlegOrderNoGenerator generator = new LastlegOrderNoGenerator();
|
||||
assertEquals("LMO2087379674555461633", generator.forContainerNo("2087379674555461633"));
|
||||
assertEquals(generator.forContainerNo("MSCU1"), new LastlegOrderNoGenerator().forContainerNo("MSCU1"));
|
||||
assertNotEquals(generator.forContainerNo("MSCU1"), generator.forContainerNo("CAB1"));
|
||||
assertTrue(generator.forContainerNo("MSCU1234567890").length() <= 32);
|
||||
assertThrows(IllegalArgumentException.class, () -> generator.forContainerNo(" "));
|
||||
}
|
||||
|
||||
@Test void remainsUniqueAcrossInstancesAndConcurrentCalls() throws Exception {
|
||||
LastlegOrderNoGenerator beforeRestart=new LastlegOrderNoGenerator();
|
||||
String first=beforeRestart.next();
|
||||
LastlegOrderNoGenerator afterRestart=new LastlegOrderNoGenerator();
|
||||
assertNotEquals(first,afterRestart.next());
|
||||
ExecutorService pool=Executors.newFixedThreadPool(8);
|
||||
try {
|
||||
var tasks=IntStream.range(0,1000).mapToObj(i->(Callable<String>)afterRestart::next).toList();
|
||||
Set<String> ids=pool.invokeAll(tasks).stream().map(future->{
|
||||
try { return future.get(); } catch(Exception exception) { throw new RuntimeException(exception); }
|
||||
}).collect(java.util.stream.Collectors.toSet());
|
||||
assertEquals(1000,ids.size());
|
||||
} finally { pool.shutdownNow(); }
|
||||
}
|
||||
}
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
package com.baiyue.lastleg.service;
|
||||
|
||||
import com.baiyue.lastleg.dto.LastlegOrderRequests;
|
||||
import com.baiyue.lastleg.entity.LastlegOrder;
|
||||
import com.baiyue.lastleg.entity.LastlegOrderDetail;
|
||||
import com.baiyue.lastleg.entity.LastlegOrderStatusHistory;
|
||||
import com.baiyue.lastleg.mapper.LastlegOrderDetailMapper;
|
||||
import com.baiyue.lastleg.mapper.LastlegOrderMapper;
|
||||
import com.baiyue.lastleg.mapper.LastlegOrderStatusHistoryMapper;
|
||||
import com.baiyue.lastleg.dropship.entity.DropshipCarton;
|
||||
import com.baiyue.lastleg.dropship.entity.DropshipOrderProfile;
|
||||
import com.baiyue.lastleg.dropship.entity.DropshipSkuInventory;
|
||||
import com.baiyue.lastleg.dropship.mapper.DropshipCartonMapper;
|
||||
import com.baiyue.lastleg.dropship.mapper.DropshipOrderProfileMapper;
|
||||
import com.baiyue.lastleg.dropship.mapper.DropshipSkuInventoryMapper;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class LastlegOrderServiceTest {
|
||||
@Mock LastlegOrderMapper orders;
|
||||
@Mock LastlegOrderDetailMapper details;
|
||||
@Mock LastlegOrderStatusHistoryMapper histories;
|
||||
@Mock DropshipOrderProfileMapper dropshipProfiles;
|
||||
@Mock DropshipSkuInventoryMapper dropshipSkuInventory;
|
||||
@Mock DropshipCartonMapper dropshipCartons;
|
||||
LastlegOrderService service;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
service = new LastlegOrderService();
|
||||
ReflectionTestUtils.setField(service, "orderMapper", orders);
|
||||
ReflectionTestUtils.setField(service, "detailMapper", details);
|
||||
ReflectionTestUtils.setField(service, "historyMapper", histories);
|
||||
ReflectionTestUtils.setField(service, "dropshipProfiles", dropshipProfiles);
|
||||
ReflectionTestUtils.setField(service, "dropshipSkuInventory", dropshipSkuInventory);
|
||||
ReflectionTestUtils.setField(service, "dropshipCartons", dropshipCartons);
|
||||
}
|
||||
|
||||
@Test
|
||||
void detailGroupsDropshipSkuAndCartonsByPallet() {
|
||||
LastlegOrder order = order(11L, "100", "PENDING_ASSIGNMENT", null);
|
||||
order.setOrderType("ONE_CLICK_DROPSHIP");
|
||||
when(orders.selectOne(any())).thenReturn(order);
|
||||
when(details.selectList(any())).thenReturn(List.of());
|
||||
when(histories.selectList(any())).thenReturn(List.of());
|
||||
DropshipOrderProfile first = profile(1L, "SOURCE-P-1", 101L, "WH-P-1");
|
||||
DropshipOrderProfile second = profile(2L, "SOURCE-P-2", 102L, "WH-P-2");
|
||||
when(dropshipProfiles.listOrder("100", 11L)).thenReturn(List.of(first, second));
|
||||
DropshipSkuInventory sku = new DropshipSkuInventory();
|
||||
sku.setProfileId(1L); sku.setSkuCode("SKU-A"); sku.setPackageCount(1L); sku.setProductQuantity(10L);
|
||||
when(dropshipSkuInventory.listOrder("100", 11L)).thenReturn(List.of(sku));
|
||||
DropshipCarton carton = new DropshipCarton();
|
||||
carton.setProfileId(1L); carton.setSkuCode("SKU-A"); carton.setCartonMark("MARK-1");
|
||||
when(dropshipCartons.listOrder("100", 11L)).thenReturn(List.of(carton));
|
||||
|
||||
var response = service.detail("100", 11L);
|
||||
|
||||
assertEquals(2, response.dropshipPallets().size());
|
||||
assertEquals("SOURCE-P-1", response.dropshipPallets().get(0).sourcePalletNo());
|
||||
assertEquals(1, response.dropshipPallets().get(0).skuInventory().size());
|
||||
assertEquals("MARK-1", response.dropshipPallets().get(0).cartons().get(0).getCartonMark());
|
||||
assertTrue(response.dropshipPallets().get(1).skuInventory().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void transferUpdatesOrderAndEveryCargoSnapshot() {
|
||||
LastlegOrder order = order(11L, "100", "PENDING_ASSIGNMENT", null);
|
||||
when(orders.selectList(any())).thenReturn(List.of(order));
|
||||
var request = new LastlegOrderRequests.TransferDestination(
|
||||
List.of(11L), "wh-2", "LAX-02", "Los Angeles 02", null);
|
||||
|
||||
assertEquals(1, service.transferDestination("100", request));
|
||||
|
||||
assertEquals("wh-2", order.getTransferWarehouseId());
|
||||
assertEquals("LAX-02", order.getTransferWarehouseCode());
|
||||
assertEquals("DESTINATION_ASSIGNED", order.getCurrentStatus());
|
||||
ArgumentCaptor<LastlegOrderDetail> cargo = ArgumentCaptor.forClass(LastlegOrderDetail.class);
|
||||
verify(details).update(cargo.capture(), any());
|
||||
assertEquals("LAX-02", cargo.getValue().getDestinationWarehouseCode());
|
||||
ArgumentCaptor<LastlegOrderStatusHistory> history = ArgumentCaptor.forClass(LastlegOrderStatusHistory.class);
|
||||
verify(histories).insert(history.capture());
|
||||
assertEquals("PENDING_ASSIGNMENT", history.getValue().getFromStatus());
|
||||
assertEquals("DESTINATION_ASSIGNED", history.getValue().getToStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
void transferRejectsAnOrderAlreadyBoundToInboundPlan() {
|
||||
LastlegOrder order = order(11L, "100", "DESTINATION_ASSIGNED", "IB-1");
|
||||
when(orders.selectList(any())).thenReturn(List.of(order));
|
||||
var request = new LastlegOrderRequests.TransferDestination(
|
||||
List.of(11L), "wh-2", "LAX-02", "Los Angeles 02", null);
|
||||
|
||||
assertThrows(ResponseStatusException.class, () -> service.transferDestination("100", request));
|
||||
verify(orders, never()).updateById(any(LastlegOrder.class));
|
||||
verify(details, never()).update(any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void batchRejectsMissingOrCrossCustomerIdsBeforeWriting() {
|
||||
when(orders.selectList(any())).thenReturn(List.of(order(11L, "100", "PENDING_ASSIGNMENT", null)));
|
||||
var request = new LastlegOrderRequests.TransferDestination(
|
||||
List.of(11L, 22L), "wh-2", "LAX-02", "Los Angeles 02", null);
|
||||
|
||||
ResponseStatusException error = assertThrows(ResponseStatusException.class,
|
||||
() -> service.transferDestination("100", request));
|
||||
assertTrue(error.getStatusCode().is4xxClientError());
|
||||
verify(orders, never()).updateById(any(LastlegOrder.class));
|
||||
}
|
||||
|
||||
private static LastlegOrder order(long id, String customerId, String status, String inboundOrderNo) {
|
||||
LastlegOrder order = new LastlegOrder();
|
||||
order.setId(id);
|
||||
order.setCustomerId(customerId);
|
||||
order.setCurrentStatus(status);
|
||||
order.setInboundOrderNo(inboundOrderNo);
|
||||
return order;
|
||||
}
|
||||
|
||||
private static DropshipOrderProfile profile(long id, String sourcePalletNo,
|
||||
long warehousePalletId, String palletNo) {
|
||||
DropshipOrderProfile profile = new DropshipOrderProfile();
|
||||
profile.setId(id); profile.setSourcePalletNo(sourcePalletNo);
|
||||
profile.setWarehousePalletId(warehousePalletId); profile.setPalletNo(palletNo);
|
||||
profile.setStatus("RECEIVED");
|
||||
return profile;
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package com.baiyue.lastleg.service;
|
||||
import com.baiyue.common.event.*; import com.baiyue.lastleg.entity.*; import com.baiyue.lastleg.mapper.*; import com.baiyue.lastleg.dropship.dto.DropshipRequests; import com.baiyue.lastleg.dropship.service.DropshipOrderService; import com.fasterxml.jackson.databind.*; import org.junit.jupiter.api.*; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.*; import org.springframework.test.util.ReflectionTestUtils; import java.math.BigDecimal; import java.time.Instant; import java.util.*; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*;
|
||||
@ExtendWith(org.mockito.junit.jupiter.MockitoExtension.class)
|
||||
class LoadingCompletedConsumerTest {
|
||||
@Mock LastlegEventInboxMapper inbox; @Mock LastlegOrderMapper orders; @Mock LastlegOrderDetailMapper details; @Mock LastlegOrderStatusHistoryMapper histories; @Mock DropshipOrderService dropshipOrders; ObjectMapper json=new ObjectMapper().findAndRegisterModules(); LoadingCompletedConsumer service;
|
||||
@BeforeEach void setup(){ service=new LoadingCompletedConsumer(); ReflectionTestUtils.setField(service,"inboxMapper",inbox); ReflectionTestUtils.setField(service,"orderMapper",orders); ReflectionTestUtils.setField(service,"detailMapper",details); ReflectionTestUtils.setField(service,"historyMapper",histories); ReflectionTestUtils.setField(service,"dropshipOrders",dropshipOrders); ReflectionTestUtils.setField(service,"objectMapper",json); ReflectionTestUtils.setField(service,"orderNoGenerator",new LastlegOrderNoGenerator()); lenient().doAnswer(i->{ LastlegOrder o=i.getArgument(0); o.setId(Math.abs(o.getSourceInboundId().hashCode())+1L); return 1; }).when(orders).insert(any(LastlegOrder.class)); }
|
||||
@Test void createsOneOrderPerInboundAndAllSnapshots(){ EventEnvelope event=event(); assertEquals(2,service.consume(event)); verify(orders,times(2)).insert(any(LastlegOrder.class)); verify(details,times(2)).insert(any(LastlegOrderDetail.class)); verify(histories,times(2)).insert(any(LastlegOrderStatusHistory.class)); ArgumentCaptor<LastlegOrder> c=ArgumentCaptor.forClass(LastlegOrder.class); verify(orders,times(2)).insert(c.capture()); assertEquals(Set.of("in-1","in-2"),c.getAllValues().stream().map(LastlegOrder::getSourceInboundId).collect(java.util.stream.Collectors.toSet())); assertTrue(c.getAllValues().stream().allMatch(o->"PENDING_ASSIGNMENT".equals(o.getCurrentStatus()))); assertTrue(c.getAllValues().stream().allMatch(o->o.getId()!=null)); assertTrue(c.getAllValues().stream().allMatch(o->"MSCU1".equals(o.getContainerNo()))); assertEquals(1,c.getAllValues().stream().map(LastlegOrder::getOrderNo).distinct().count()); assertEquals(new LastlegOrderNoGenerator().forContainerNo("MSCU1"),c.getAllValues().get(0).getOrderNo()); }
|
||||
@Test void repeatedEventReturnsExistingEffect(){ EventEnvelope event=event(); LastlegEventInbox row=new LastlegEventInbox(); row.setPayloadHash(event.payloadHash()); when(inbox.selectById(event.eventId())).thenReturn(row); when(orders.countContainer("100","MSCU1")).thenReturn(2L); assertEquals(2,service.consume(event)); verify(orders).countContainer("100","MSCU1"); verify(orders,never()).insert(any(LastlegOrder.class)); verify(details,never()).insert(any(LastlegOrderDetail.class)); }
|
||||
@Test void sameEventWithDifferentHashIsRejected(){ EventEnvelope event=event(); LastlegEventInbox row=new LastlegEventInbox(); row.setPayloadHash("sha256:"+"0".repeat(64)); when(inbox.selectById(event.eventId())).thenReturn(row); assertThrows(IllegalArgumentException.class,()->service.consume(event)); }
|
||||
@Test void rejectsEventFromWrongRegion(){ EventEnvelope source=event(); EventEnvelope invalid=new EventEnvelope(source.eventId(),source.eventType(),source.eventVersion(),source.occurredAt(),RegionCode.OVERSEAS,RegionCode.CN,source.tenantId(),source.aggregateType(),source.aggregateId(),source.aggregateVersion(),source.handoverVersion(),source.traceId(),source.correlationId(),source.causationId(),source.payload(),source.payloadHash()); assertThrows(IllegalArgumentException.class,()->service.consume(invalid)); }
|
||||
@Test void consumesFormalDropshipPalletSnapshots(){ var sku=new FirstLegLoadingPlanCompletedV1.SkuPackageSnapshot("SKU-A","Product A",2,20,List.of("BOX-1","BOX-2")); var pallet=new FirstLegLoadingPlanCompletedV1.PalletSnapshot("PLT-1",List.of(sku)); var item=new FirstLegLoadingPlanCompletedV1.Item("d-1","SKU-A","Product A","Product A",2,20,1,BigDecimal.ONE,BigDecimal.ONE,BigDecimal.ONE,BigDecimal.ONE,"wh-1","ONT8","ONT8",null,null,"MARK",null,List.of()); var order=new FirstLegLoadingPlanCompletedV1.Order("in-d","root-d","ord-d","FL-D","root-od","RK-D","wh-1","ONT8","ONT8",2,20,1,BigDecimal.ONE,BigDecimal.ONE,BigDecimal.ONE,List.of(item),"100","ONE_CLICK_DROPSHIP",List.of(pallet)); var payload=new FirstLegLoadingPlanCompletedV1("plan-d","LP-D","book-d","CONT-D","CAB-D","92","Warehouse",List.of(order)); JsonNode node=json.valueToTree(payload); String hash=EventPayloadHash.sha256(EventPayloadCanonicalizer.canonicalize(node)); var event=new EventEnvelope("123e4567-e89b-12d3-a456-426614174010",EventTypes.FIRST_LEG_LOADING_PLAN_COMPLETED,1,Instant.now(),RegionCode.CN,RegionCode.OVERSEAS,"100","LOADING_PLAN","plan-d",2,1L,"123e4567-e89b-12d3-a456-426614174011","FIRSTLEG_LOADING_COMPLETED:plan-d:100:1",null,node,hash); assertEquals(1,service.consume(event)); ArgumentCaptor<DropshipRequests.Receive> captor=ArgumentCaptor.forClass(DropshipRequests.Receive.class); verify(dropshipOrders).receive(captor.capture()); assertEquals("100",captor.getValue().customerId()); assertEquals(1,captor.getValue().pallets().size()); assertEquals("PLT-1",captor.getValue().pallets().get(0).palletNo()); assertEquals(List.of("BOX-1","BOX-2"),captor.getValue().pallets().get(0).skuPackages().get(0).cartonMarks()); }
|
||||
private EventEnvelope event(){ var item1=new FirstLegLoadingPlanCompletedV1.Item("d-1","SKU-1","产品","Product",5,50,1,new BigDecimal("10"),new BigDecimal("9"),new BigDecimal("12"),new BigDecimal("1.2"),"wh-1","ONT8","FBA ONT8","FBA-1","SHIP-1","MARK-1"); var item2=new FirstLegLoadingPlanCompletedV1.Item("d-2","SKU-2","产品2","Product2",3,30,2,new BigDecimal("8"),new BigDecimal("7"),new BigDecimal("9"),new BigDecimal("0.8"),"wh-2","LAX9","FBA LAX9","FBA-2","SHIP-2","MARK-2"); var p=new FirstLegLoadingPlanCompletedV1("plan-1","LP1","book-1","MSCU1","CAB1","ow-1","洛杉矶海外仓",List.of(new FirstLegLoadingPlanCompletedV1.Order("in-1","root-1","ord-1","FL1","root-o1","RK1","wh-1","ONT8","FBA ONT8",5,50,1,new BigDecimal("10"),new BigDecimal("9"),new BigDecimal("1.2"),List.of(item1)),new FirstLegLoadingPlanCompletedV1.Order("in-2","root-2","ord-2","FL2","root-o2","RK2","wh-2","LAX9","FBA LAX9",3,30,2,new BigDecimal("8"),new BigDecimal("7"),new BigDecimal("0.8"),List.of(item2)))); JsonNode node=json.valueToTree(p); String hash=EventPayloadHash.sha256(EventPayloadCanonicalizer.canonicalize(node)); return new EventEnvelope("123e4567-e89b-12d3-a456-426614174000",EventTypes.FIRST_LEG_LOADING_PLAN_COMPLETED,1,Instant.now(),RegionCode.CN,RegionCode.OVERSEAS,"100","LOADING_PLAN","plan-1",2,1L,"123e4567-e89b-12d3-a456-426614174001","FIRSTLEG_LOADING_COMPLETED:plan-1:100:1",null,node,hash); }
|
||||
}
|
||||
Reference in New Issue
Block a user