完成单机TEST统一入口与可靠投递回归收尾

This commit is contained in:
2026-09-29 19:48:34 +08:00
parent 64a70c9f28
commit 6c0a026cc4
89 changed files with 968 additions and 983 deletions
@@ -73,11 +73,18 @@ class Phase4BrowserApiBoundaryTest {
}
@Test
void overseasLastlegReachesDomesticPrintThroughSharedInfrastructureNetwork() throws Exception {
Path composePath = Path.of("deploy/docker-compose.overseas.yml");
void lastlegReachesPrintThroughTheUnifiedTestNetwork() throws Exception {
Path composePath = Path.of("deploy/docker-compose.yml");
if (!Files.exists(composePath)) composePath = Path.of("..").resolve(composePath);
String compose = Files.readString(composePath);
assertTrue(compose.contains("PRINT_SERVICE_URL: ${PRINT_SERVICE_URL:-http://print:9207}"));
String lastleg = compose.substring(compose.indexOf(" lastleg-service:"), compose.indexOf(" warehouse-overseas-service:"));
assertTrue(lastleg.contains("<<: *common"));
assertTrue(lastleg.contains("<<: *common-environment"));
assertTrue(lastleg.contains("PRINT_SERVICE_URL: ${PRINT_SERVICE_URL:-http://print:9207}"));
assertTrue(compose.contains("networks: [firstleg-network, infra-network]"));
assertTrue(compose.contains("name: firstleg-test-network"));
assertFalse(lastleg.contains("ports:"));
assertFalse(compose.contains("gateway-overseas"));
}
@Test
@@ -12,9 +12,9 @@ class ReceivingPhotoUploadConfigurationContractTest {
@Test
void lastlegAcceptsTheSameTenMegabyteLimitAsFileService() throws Exception {
String application = read("lastleg-service/src/main/resources/application.yml");
String overseas = read("config/nacos/overseas/lastleg-service.yml");
String testConfiguration = read("config/nacos/test/lastleg-service.yml");
for (String configuration : new String[]{application, overseas}) {
for (String configuration : new String[]{application, testConfiguration}) {
assertThat(configuration).contains(
"max-file-size: ${LASTLEG_MULTIPART_MAX_FILE_SIZE:10MB}",
"max-request-size: ${LASTLEG_MULTIPART_MAX_REQUEST_SIZE:11MB}");
@@ -170,6 +170,7 @@ class InboundUnloadCompletedOutboxRelayTest {
private LastlegEventOutbox row(EventEnvelope event) throws Exception {
LastlegEventOutbox row = new LastlegEventOutbox();
row.setId(9001L);
row.setEventType(event.eventType());
row.setEventKey("OverseasContainerUnloaded:7001");
row.setPayloadJson(objectMapper.writeValueAsString(event));
return row;
@@ -14,7 +14,7 @@ import static org.assertj.core.api.Assertions.assertThat;
class DomesticPartnerWarehouseClientContractTest {
@Test
void freezesCnInternalUrlTokenHeaderAndFourFieldDto() throws Exception {
void freezesWarehouseInternalUrlTokenHeaderAndFourFieldDto() throws Exception {
FeignClient feign = DomesticPartnerWarehouseClient.class.getAnnotation(FeignClient.class);
assertThat(feign.name()).isEqualTo("warehouse-service");
assertThat(feign.url()).isEqualTo("${baiyue.clients.domestic-warehouse.url:}");
@@ -30,22 +30,33 @@ class DomesticPartnerWarehouseClientContractTest {
}
@Test
void developmentDeploymentRequiresAndPassesTheCnUrlAndSharedInternalToken() throws Exception {
void testDeploymentPassesInternalWarehouseUrlAndSharedAuthentication() throws Exception {
String application = Files.readString(Path.of("src/main/resources/application.yml"));
String nacos = Files.readString(Path.of("../config/nacos/overseas/lastleg-service.yml"));
String common = Files.readString(Path.of("../config/nacos/overseas/baiyue-common.yml"));
String compose = Files.readString(Path.of("../deploy/docker-compose.overseas.yml"));
String deploy = Files.readString(Path.of("../deploy/scripts/deploy-services.sh"));
String nacos = Files.readString(Path.of("../config/nacos/test/lastleg-service.yml"));
String common = Files.readString(Path.of("../config/nacos/test/baiyue-common.yml"));
String compose = Files.readString(Path.of("../deploy/docker-compose.yml"));
String deploy = Files.readString(Path.of("../deploy/scripts/deploy-built-service.sh"));
assertThat(application).contains("url: ${DOMESTIC_WAREHOUSE_URL:}")
.contains("cache-ttl: ${DOMESTIC_WAREHOUSE_CACHE_TTL:30m}");
assertThat(nacos).contains("url: ${DOMESTIC_WAREHOUSE_URL}")
.contains("cache-ttl: ${DOMESTIC_WAREHOUSE_CACHE_TTL:30m}");
assertThat(common).contains("internal-service-token: ${INTERNAL_SERVICE_TOKEN}");
String lastleg = compose.substring(compose.indexOf(" lastleg-service:"), compose.indexOf(" warehouse-overseas-service:"));
assertThat(lastleg).contains("<<: *common-environment")
.contains("DOMESTIC_WAREHOUSE_URL: ${DOMESTIC_WAREHOUSE_URL:-http://warehouse:9205}")
.contains("expose: [\"9303\"]")
.doesNotContain("ports:");
assertThat(compose).contains("INTERNAL_SERVICE_TOKEN: ${INTERNAL_SERVICE_TOKEN}")
.contains("DOMESTIC_WAREHOUSE_URL: ${DOMESTIC_WAREHOUSE_URL}");
assertThat(deploy).contains("FIRSTLEG_EVENT_BRIDGE_URL DOMESTIC_WAREHOUSE_URL")
.contains("NACOS_SERVER_ADDR OVERSEAS_NACOS_USERNAME OVERSEAS_NACOS_PASSWORD "
+ "OVERSEAS_NACOS_NAMESPACE INTERNAL_SERVICE_TOKEN");
.contains("NACOS_USERNAME: ${NACOS_USERNAME}")
.contains("NACOS_NAMESPACE: ${NACOS_NAMESPACE:?actual TEST namespace ID required}")
.contains("JWT_JWKS_URI: http://auth:9100/api/auth/.well-known/jwks.json")
.doesNotContain("OVERSEAS_NACOS_NAMESPACE", "OVERSEAS_NACOS_USERNAME", "FIRSTLEG_EVENT_BRIDGE_URL");
assertThat(common).contains("session-mode: redis")
.contains("jwk-set-uri: ${JWT_JWKS_URI:http://auth:9100/api/auth/.well-known/jwks.json}");
assertThat(deploy).contains("Only test is supported")
.contains("NACOS_SERVER_ADDR NACOS_NAMESPACE NACOS_USERNAME NACOS_PASSWORD")
.contains("REDIS_TOKEN_KEY_PREFIX INTERNAL_SERVICE_TOKEN")
.contains("lastleg-service) db_prefix=LASTLEG");
}
}
@@ -75,8 +75,19 @@ class PdaWarehouseContractTest {
"/api/pda/v1/last-leg/locations/resolve:", "/api/pda/v1/last-leg/pallets/resolve:",
"/api/pda/v1/last-leg/operations:")) assertThat(openapi).contains(path);
assertThat(openapi).doesNotContain("/api/pda/v1/last-leg/inbound-plans/{planNo}");
String gateway = Files.readString(Path.of("../gateway-overseas/src/main/resources/application-overseas.yml"));
assertThat(gateway).contains("/api/pda/v1/last-leg/**").contains("lb://lastleg-service");
String gateway = Files.readString(Path.of("../gateway/src/main/resources/application.yml"));
String lastlegRoute = gateway.substring(gateway.indexOf("- id: lastleg-service"),
gateway.indexOf("- id: warehouse-overseas-service"));
assertThat(lastlegRoute).contains("uri: lb://lastleg-service")
.contains("/api/pda/v1/last-leg/**")
.contains("/api/platform/v1/last-leg/**")
.contains("/api/merchant/v1/last-leg/**");
assertThat(gateway.lines().filter(line -> line.strip().startsWith("- Path=")))
.noneMatch(line -> line.contains("/internal/"));
assertThat(gateway).contains("allowed-headers: Authorization,")
.doesNotContain("gateway-overseas");
String nacos = Files.readString(Path.of("../config/nacos/test/gateway.yml"));
assertThat(nacos).doesNotContain("routes:"); // Shared source routes must not be replaced by a partial regional list.
}
private static AuthenticatedUser user(Set<String> authorities, Long warehouseId) {
@@ -29,7 +29,7 @@ class OutboxLeaseDatabaseTest {
var repository = new UnloadCompletedOutboxRepository();
ReflectionTestUtils.setField(repository, "mapper", mapper);
var journal = new EventDeliveryJournal(jdbc, new DataSourceTransactionManager(dataSource));
LocalDateTime now = LocalDateTime.now();
LocalDateTime now = LocalDateTime.of(2026, 9, 29, 12, 0);
jdbc.update("INSERT INTO ll_event_outbox(id,event_type,status,retry_count,next_retry_at,created_at) VALUES(1,?,'PENDING',0,?,?)", "OverseasContainerUnloaded", now.minusSeconds(1), now.minusMinutes(3));
assertThat(journal.begin("old", "lastleg-service", "OverseasContainerUnloaded", "1", null, "consumer", now.minusMinutes(2), () -> repository.claim(1L, "old", now.minusMinutes(2)))).isFalse();
assertThat(journal.begin("old", "lastleg-service", "OverseasContainerUnloaded", "1", null, "consumer", now, () -> repository.claim(1L, "old", now))).isTrue();
@@ -66,7 +66,7 @@ class OutboxLeaseDatabaseTest {
var mapper = new SqlSessionTemplate(factory.getObject()).getMapper(LastlegEventOutboxMapper.class);
var repository = new com.baiyue.lastleg.financefee.repository.OverseasFeeOutboxRepository(mapper);
var journal = new EventDeliveryJournal(jdbc, new DataSourceTransactionManager(dataSource));
LocalDateTime now = LocalDateTime.now();
LocalDateTime now = LocalDateTime.of(2026, 9, 29, 12, 0);
jdbc.update("INSERT INTO ll_event_outbox(id,event_type,status,retry_count,next_retry_at,created_at) VALUES(1,?,'PENDING',0,?,?)", "BusinessFeeSourceChanged", now.minusSeconds(1), now.minusMinutes(3));
assertThat(journal.begin("old", "lastleg-service", "BusinessFeeSourceChanged", "1", null, "consumer", now.minusMinutes(2), () -> repository.claim(1L, "old", now.minusMinutes(2)))).isFalse();
assertThat(journal.begin("old", "lastleg-service", "BusinessFeeSourceChanged", "1", null, "consumer", now, () -> repository.claim(1L, "old", now))).isTrue();
@@ -69,16 +69,12 @@ class Phase5OverseasUpgradeSqlContractTest {
}
@Test
void overseasFixedAdminProjectionAssertionMatchesItsAuthorityArray() throws Exception {
void unifiedSessionDoesNotInitializeASecondAuthorizationProjection() throws Exception {
String overseas = repositoryFile("deploy/sql/海外区域统一增量-MySQL8.sql");
int start = overseas.indexOf("VALUES ('AUTHORIZATION','1000001'");
int end = overseas.indexOf(";", start);
String authorityRow = overseas.substring(start, end);
int authorityCount = count(authorityRow, "platform:");
assertThat(authorityCount).isPositive();
assertThat(authorityRow).contains("baseline-platform-admin-authorization-v0");
assertThat(overseas).doesNotContain("@platform_admin_overseas_authorities");
assertThat(overseas).doesNotContain("CREATE TABLE ll_security_projection", "CREATE TABLE ll_security_event_inbox",
"baseline-platform-admin-authorization-v0", "@platform_admin_overseas_authorities");
String primary = repositoryFile("deploy/sql/头程数据库统一增量-MySQL8.sql");
assertThat(primary).contains("CREATE TABLE iam_security_subject_version", "CREATE TABLE iam_security_tenant_version");
}
@Test
@@ -39,7 +39,9 @@ class SchemaChineseCommentContractTest {
List<TableDefinition> baselineTables = assertAllChineseComments(baseline, "基线 SQL", 56);
assertAllChineseComments(incremental, "增量 SQL", 50);
assertAllChineseComments(overseasUnified, "海外统一初始化 SQL", 127);
assertAllChineseComments(overseasUnified, "统一测试初始化 SQL", 126);
assertFalse(overseasUnified.contains("CREATE TABLE ll_security_projection"));
assertFalse(overseasUnified.contains("CREATE TABLE ll_security_event_inbox"));
assertCommentMigrationCovers(incremental, overseasUnified, baselineTables);
}
@@ -25,7 +25,7 @@ class LoadingCompletedConsumerTest {
String table=schema.substring(schema.indexOf("CREATE TABLE IF NOT EXISTS ll_inbound_order ("),schema.indexOf("CREATE TABLE IF NOT EXISTS ll_inbound_order_item ("));
assertTrue(table.contains("customer_id")); assertFalse(table.contains("tenant_id"));
}
@Test void rejectsEventFromWrongRegion(){ EventEnvelope source=event(); EventEnvelope invalid=new EventEnvelope(source.eventId(),source.eventType(),source.eventVersion(),source.occurredAt(),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 rejectsUnsupportedEventType(){ EventEnvelope source=event(); EventEnvelope invalid=new EventEnvelope(source.eventId(),"UnsupportedEvent",source.eventVersion(),source.occurredAt(),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","Customer 100","ONE_CLICK_DROPSHIP",List.of(pallet),"FBA"); var payload=new FirstLegLoadingPlanCompletedV1("plan-d","LP-D","book-d","MSCU6639870","CAB-D","92","Warehouse",List.of(order)); JsonNode node=json.valueToTree(payload); addManifest(node.path("orders").get(0).path("pallets").get(0),2); 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(),"100","LOADING_PLAN","plan-d",2,1L,"123e4567-e89b-12d3-a456-426614174011","FIRSTLEG_LOADING_COMPLETED:plan-d:100:1",null,node,hash); assertEquals(com.baiyue.common.event.DeliveryAck.Outcome.APPLIED, service.consume(event).outcome()); ArgumentCaptor<DropshipRequests.Receive> captor=ArgumentCaptor.forClass(DropshipRequests.Receive.class); verify(dropshipOrders).receive(captor.capture()); verify(inventory,never()).registerInTransit(anyString(),anyString(),any()); assertEquals("100",captor.getValue().customerId()); assertEquals("123e4567-e89b-12d3-a456-426614174010:DROPSHIP:in-d",captor.getValue().idempotencyKey()); 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()); }
@Test void freezesReceivingWarehouseInInitialInTransitInventory(){
service.consume(event());