package com.baiyue.lastleg.pda; import com.baiyue.lastleg.palletops.dto.PalletOperationRequests; import com.baiyue.lastleg.pda.move.dto.PdaInventoryMoveRequest; import com.baiyue.lastleg.pda.stocktake.dto.PdaStocktakeRequests; import com.baiyue.lastleg.relabel.pda.dto.PdaRelabelRequests; import org.junit.jupiter.api.Test; import java.io.IOException; import java.lang.reflect.RecordComponent; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.List; import java.util.Set; import java.util.stream.Collectors; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; class PdaOperationsOpenApiContractTest { private static final Set SERVER_OWNED = Set.of( "customerId", "warehouseId", "overseasWarehouseId", "operator", "operatorKey", "operatorName"); @Test void pdaOperationRequestsNeverAcceptServerOwnedScope() { List> containers = List.of(PdaStocktakeRequests.class, PalletOperationRequests.class, PdaRelabelRequests.class); for (Class container : containers) { for (Class type : container.getDeclaredClasses()) { if (type.isRecord()) assertNoServerOwnedFields(type); } } assertNoServerOwnedFields(PdaInventoryMoveRequest.class); } @Test void versionedOpenApiPublishesEveryPdaWarehouseOperation() throws IOException { String yaml = resource("openapi/overseas-pda-operations-v1.yaml"); List paths = List.of( "/api/pda/v1/last-leg/stocktakes:", "/api/pda/v1/last-leg/stocktakes/{taskNo}:", "/api/pda/v1/last-leg/stocktakes/{taskNo}/counts:", "/api/pda/v1/last-leg/stocktakes/{taskNo}/submit:", "/api/pda/v1/last-leg/inventory-moves:", "/api/pda/v1/last-leg/pallet-operations/pallets/resolve:", "/api/pda/v1/last-leg/pallet-operations/assemble:", "/api/pda/v1/last-leg/pallet-operations/disassemble:", "/api/pda/v1/last-leg/pallet-operations/swap:", "/api/pda/v1/last-leg/pallet-operations/unbind:", "/api/pda/v1/last-leg/relabel-tasks/candidates:", "/api/pda/v1/last-leg/relabel-tasks/{relabelNo}:", "/api/pda/v1/last-leg/relabel-tasks/{relabelNo}/claim:", "/api/pda/v1/last-leg/relabel-tasks/{relabelNo}/units:", "/api/pda/v1/last-leg/relabel-tasks/{relabelNo}/units/skip:", "/api/pda/v1/last-leg/relabel-tasks/{relabelNo}/exceptions:", "/api/pda/v1/last-leg/relabel-tasks/{relabelNo}/photos/files:", "/api/pda/v1/last-leg/relabel-tasks/{relabelNo}/complete:", "/api/pda/v1/last-leg/relabel-tasks/{relabelNo}/review:"); for (String path : paths) assertTrue(yaml.contains(path), path); assertEquals(19, paths.size()); assertTrue(yaml.contains("enum: [LOCATION, PALLET]")); assertTrue(yaml.contains("enum: [APPROVE, REWORK]")); assertTrue(yaml.contains("enum: [DAMAGED, MISSING_LABEL, LABEL_MISMATCH, UNREADABLE, OTHER]")); for (String field : SERVER_OWNED) assertFalse(yaml.contains(field + ":"), field); for (String excluded : List.of("/outbound", "/dispatch", "/delivery")) { assertFalse(yaml.contains(excluded), excluded); } } private static void assertNoServerOwnedFields(Class type) { Set fields = Arrays.stream(type.getRecordComponents()) .map(RecordComponent::getName).collect(Collectors.toSet()); assertTrue(java.util.Collections.disjoint(fields, SERVER_OWNED), type.getSimpleName()); } private String resource(String name) throws IOException { try (var input = getClass().getClassLoader().getResourceAsStream(name)) { assertTrue(input != null, name); return new String(input.readAllBytes(), StandardCharsets.UTF_8); } } }