This commit is contained in:
2026-10-19 17:56:36 +08:00
parent bb917c954c
commit dcfba1053c
232 changed files with 15655 additions and 6005 deletions
@@ -1,57 +1,49 @@
package com.baiyue.lastleg.dispatch;
import org.junit.jupiter.api.Test;
import org.yaml.snakeyaml.Yaml;
import java.util.*;
import static org.assertj.core.api.Assertions.*;
import java.nio.charset.StandardCharsets;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
/** 精确解析公开草稿合同,不以全文件字符串误匹配旧客户拆单协议。 */
class SmartDispatchOpenApiContractTest {
@Test
void contractDocumentsOnlyCandidateAndPreArrangeSmartDispatchWrites() throws Exception {
String yaml;
try (var input = getClass().getResourceAsStream("/openapi/overseas-business-v1.yaml")) {
yaml = new String(input.readAllBytes(), StandardCharsets.UTF_8);
/** 草稿端点、版本化请求和候选参数必须与冻结端口一致,旧standalone路由移除。 */
@Test void contractPublishesOwnedVersionedDraftProtocol()throws Exception {
Map<String,Object> root;
try(var input=getClass().getResourceAsStream("/openapi/overseas-business-v1.yaml")){root=new Yaml().load(input);}
var paths=map(root.get("paths"));String base="/api/platform/v1/last-leg/dispatches";
assertThat(paths).doesNotContainKey(base+"/pre-arrange");
var expected=new LinkedHashMap<String,String>();
expected.put("/drafts","DispatchCreateDraft");expected.put("/drafts/containers","DispatchCreateContainer");
expected.put("/drafts/snapshot","DispatchDraftSnapshot");expected.put("/draft-locks/lock","DispatchDraftSelection");
expected.put("/draft-locks/unlock","DispatchDraftSelection");expected.put("/draft-locks/release","DispatchDraftRelease");
expected.put("/drafts/pre-arrange","DispatchConvertDraft");expected.put("/drafts/{draftToken}/containers/{containerId}","DispatchReasonCommand");
var businessRequired=Map.of(
"DispatchCreateDraft",List.of("warehouseId"),"DispatchCreateContainer",List.of("draftToken","capacity"),
"DispatchDraftSelection",List.of("draftToken","draftContainerId","source"),"DispatchDraftSnapshot",List.of("draftToken","planIds","containers"),
"DispatchDraftRelease",List.of("draftToken"),"DispatchConvertDraft",List.of("draftToken","groups"));
var schemas=map(map(root.get("components")).get("schemas"));
for(var item:expected.entrySet()){
String method=item.getKey().contains("{containerId}")?"delete":"post";
var operation=map(map(paths.get(base+item.getKey())).get(method));
var body=map(operation.get("requestBody"));assertThat(body.get("required")).isEqualTo(true);
var schema=map(map(map(body.get("content")).get("application/json")).get("schema"));
assertThat(schema.get("$ref")).isEqualTo("#/components/schemas/"+item.getValue());
var request=map(schemas.get(item.getValue()));var fields=map(request.get("properties"));
assertThat(fields).doesNotContainKeys("customerId","planPalletIds","returnReceiptIds","expectedVersion");
assertThat(((List<?>)request.get("required")).contains("idempotencyKey")).isTrue();
if(!item.getKey().equals("/drafts"))assertThat(((List<?>)request.get("required")).contains("recordVersion")).isTrue();
assertThat(((List<?>)request.get("required")).containsAll(businessRequired.getOrDefault(item.getValue(),List.of()))).isTrue();
}
assertTrue(yaml.contains("/api/platform/v1/last-leg/dispatches/candidates:"));
assertTrue(yaml.contains("/api/platform/v1/last-leg/dispatches/pre-arrange:"));
assertTrue(yaml.contains("/api/platform/v1/last-leg/dispatches/drafts/pre-arrange:"));
assertTrue(yaml.contains("required: [draftToken, groups]"));
assertTrue(yaml.contains("required: [draftContainerId, planPalletIds, returnReceiptIds]"));
assertTrue(yaml.contains("SmartDispatchDraftGroupResult:"));
assertTrue(yaml.contains("/api/platform/v1/last-leg/dispatches/draft-locks/lock:"));
assertTrue(yaml.contains("/api/platform/v1/last-leg/dispatches/draft-locks/unlock:"));
assertTrue(yaml.contains("/api/platform/v1/last-leg/dispatches/draft-locks/release:"));
assertTrue(yaml.contains("/api/platform/v1/last-leg/dispatches/drafts:"));
assertTrue(yaml.contains("/api/platform/v1/last-leg/dispatches/drafts/snapshot:"));
assertTrue(yaml.contains("/api/platform/v1/last-leg/dispatches/drafts/containers:"));
assertTrue(yaml.contains("/api/platform/v1/last-leg/dispatches/drafts/{draftToken}/containers/{containerId}:"));
assertTrue(yaml.contains("draftContainerId:"));
assertTrue(yaml.contains("SmartDispatchDraftContainer:"));
assertTrue(yaml.contains("capacity: { type: integer, enum: [15, 30] }"));
assertTrue(yaml.contains("SmartDispatchDraft:"));
assertTrue(yaml.contains("platform:overseas-warehouse:inbound-order:list"));
assertTrue(yaml.contains("platform:overseas-warehouse:inbound-order:smart-dispatch"));
assertTrue(yaml.contains("SmartDispatchPreArrange"));
assertTrue(yaml.contains("SmartDispatchCandidate"));
assertTrue(yaml.contains("overseasWarehouseCode: { type: string, nullable: true, description: 实际海外接柜仓编码"));
assertTrue(yaml.contains("grossWeightKg: { type: number, nullable: true, description: 候选托盘分摊毛重"));
assertTrue(yaml.contains("禁止使用体积重替代"));
String preArrangeSchema = yaml.substring(yaml.indexOf(" SmartDispatchPreArrange:"),
yaml.indexOf(" SmartDispatchDraftPallet:"));
String updateSchema = yaml.substring(yaml.indexOf(" DispatchUpdate:"),
yaml.indexOf(" DeliveryTransfer:"));
assertFalse(preArrangeSchema.contains("route:"));
assertFalse(updateSchema.contains("route:"));
assertTrue(updateSchema.contains("departAt: { type: string, format: date-time, nullable: true }"));
assertTrue(yaml.contains("name: planIds"));
String planIdsParameter = yaml.substring(yaml.indexOf("name: planIds"),
yaml.indexOf("name: orderNo", yaml.indexOf("name: planIds")));
assertTrue(planIdsParameter.contains("required: false"));
String dispatchContract = yaml.substring(yaml.indexOf("/api/platform/v1/last-leg/dispatches:"),
yaml.indexOf("/api/platform/v1/last-leg/outbound-orders:"));
assertFalse(dispatchContract.contains("name: customerId"));
assertFalse(yaml.contains("/api/platform/v1/last-leg/dispatches/{dispatchNo}/depart:"));
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();
assertThat(parameterNames).contains("warehouseId","destinationWarehouseCode","draftToken").doesNotContain("customerId","fbaWarehouseCode");
var draft=map(map(schemas.get("DispatchDraft")).get("properties"));
assertThat(draft.keySet()).containsExactlyInAnyOrder("draftToken","recordVersion","status","warehouseId","containers","sources","expiresAt");
var vehicle=map(map(schemas.get("DispatchDraftVehicle")).get("properties"));assertThat(vehicle.keySet()).containsExactlyInAnyOrder("draftContainerId","dispatch");
}
/** 失败显示实际缺失节点,避免静默按空合同放过接口漂移。 */
@SuppressWarnings("unchecked")
private static Map<String,Object> map(Object value){assertThat(value).isInstanceOf(Map.class);return (Map<String,Object>)value;}
}