This commit is contained in:
2026-10-21 16:40:18 +08:00
parent 090591076f
commit c962f614e6
14 changed files with 635 additions and 52 deletions
@@ -38,6 +38,9 @@ class SmartDispatchOpenApiContractTest {
assertThat(map(paths.get(base+"/drafts"))).containsKey("get");
var candidate=map(map(paths.get(base+"/candidates")).get("get"));
var parameterNames=((List<?>)candidate.get("parameters")).stream().map(SmartDispatchOpenApiContractTest::map).map(p->p.get("name")).toList();
var warehouseParameter=((List<?>)candidate.get("parameters")).stream().map(SmartDispatchOpenApiContractTest::map)
.filter(p->"warehouseId".equals(p.get("name"))).findFirst().orElseThrow();
assertThat(warehouseParameter.get("required")).isEqualTo(false);
assertThat(parameterNames).contains("warehouseId","destinationWarehouseCode","draftToken","page","size","warehouseTab").doesNotContain("customerId","fbaWarehouseCode");
assertThat(map(map(schemas.get("DispatchCandidateList")).get("properties")).keySet())
.containsExactlyInAnyOrder("candidates","snapshotAt","complete","total","page","size","pages");
@@ -45,6 +45,16 @@ class SmartDispatchControllerTest {
.andExpect(status().isOk());
verify(aggregate).candidates(actor,new CandidateQuery("92",null,null,"LAX9",null,null,1,20,"ALL"));verifyNoInteractions(planning);
}
/** 区域入口无需隐藏默认仓,全部与城市均由服务端分页。 */
@Test void candidateHttpQueryAllowsRegionalBrowsingWithoutWarehouse()throws Exception {
var mvc=MockMvcBuilders.standaloneSetup(controller).setCustomArgumentResolvers(new AuthenticationPrincipalArgumentResolver()).build();
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(platform(),null,List.of()));
for(String tab:List.of("ALL","LAX","NYC")) {
mvc.perform(get("/api/platform/v1/last-leg/dispatches/candidates").param("warehouseTab",tab)).andExpect(status().isOk());
verify(aggregate).candidates(actor,new CandidateQuery(null,null,null,null,null,null,1,20,tab));
}
verifyNoInteractions(planning);
}
/** 每个写入都将冻结DTO原样传递,拥有者只能来自认证主体。 */
@Test void allDraftRoutesDelegateFrozenVersionedRequests(){
var create=new CreateDraft("create","92");var container=new CreateContainer(0L,"container","d",15);
@@ -0,0 +1,47 @@
package com.baiyue.lastleg.dispatch.service;
import com.baiyue.lastleg.dispatch.mapper.DispatchCandidatePageMapper;
import com.baiyue.lastleg.dispatch.port.DispatchContracts.Actor;
import com.baiyue.lastleg.dispatch.port.DispatchPlanningModels.CandidateQuery;
import com.baiyue.lastleg.dispatch.port.DispatchTypes.ActorMode;
import org.apache.ibatis.session.Configuration;
import org.junit.jupiter.api.Test;
import org.springframework.test.util.ReflectionTestUtils;
import java.util.*;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
/** 区域候选的读取范围与单仓写入职责分离,不依赖测试环境数据。 */
class DispatchRegionalCandidatesTest {
/** 真实服务接受不指定仓的三种区域,保留服务端分页总数;非法仓和区域仍拒绝。 */
@Test void serviceAcceptsRegionalQueriesAndRejectsMalformedScopes() {
var sources=mock(DispatchService.class);var appointments=mock(DispatchAppointmentAllocations.class);
var service=new DispatchAggregateService(null,null,sources,null,null,null,new com.fasterxml.jackson.databind.ObjectMapper());
ReflectionTestUtils.setField(service,"appointments",appointments);
var actor=new Actor("7",ActorMode.PLATFORM,null);
when(sources.candidatePage(eq("7"),any())).thenReturn(new DispatchService.CandidatePage(List.of(),41));
when(sources.selectionGroups(List.of())).thenReturn(Map.of());when(appointments.candidates(List.of())).thenReturn(Map.of());
for(String tab:List.of("ALL","LAX","NYC")) {
var query=new CandidateQuery(null,null,null,null,null,null,2,20,tab);
var result=service.candidates(actor,query);
assertThat(result.total()).isEqualTo(41);assertThat(result.page()).isEqualTo(2);assertThat(result.pages()).isEqualTo(3);
verify(sources).candidatePage("7",query);
}
assertThatThrownBy(()->service.candidates(actor,new CandidateQuery("bad",null,null,null,null,null,1,20,"ALL"))).hasMessageContaining("起运仓筛选无效");
assertThatThrownBy(()->service.candidates(actor,new CandidateQuery(null,null,null,null,null,null,1,20,"bad"))).hasMessageContaining("仓库页签不合法");
}
/** 解析实际Mapper动态SQL,统计和分页采用相同区域条件,单仓消费者继续绑定真实仓。 */
@Test void countAndPageUseOptionalWarehouseAndTheSameRegionPredicate() {
var config=new Configuration();config.addMapper(DispatchCandidatePageMapper.class);
for(String method:List.of("count","page")) for(String tab:List.of("ALL","LAX","NYC")) for(String warehouse:List.of("ALL_WAREHOUSES","321")) {
var query=new CandidateQuery(warehouse.equals("321")?warehouse:null,null,null,null,null,null,1,20,tab);
var sql=config.getMappedStatement(DispatchCandidatePageMapper.class.getName()+"."+method).getBoundSql(Map.of("query",query,"offset",0)).getSql();
if(query.warehouseId()==null)assertThat(sql).doesNotContain("overseasWarehouseId=?");
else assertThat(sql).contains("overseasWarehouseId=?");
if(tab.equals("LAX"))assertThat(sql).contains("REGEXP 'lax|洛杉矶|los angeles'");
if(tab.equals("NYC"))assertThat(sql).contains("REGEXP 'nyc|jfk|");
if(tab.equals("ALL"))assertThat(sql).doesNotContain("REGEXP 'lax|", "REGEXP 'nyc|");
if(method.equals("page"))assertThat(sql).contains("LIMIT ? OFFSET ?");
}
}
}