优化
This commit is contained in:
+101
@@ -0,0 +1,101 @@
|
||||
package com.baiyue.lastleg.export;
|
||||
|
||||
import com.baiyue.common.core.api.PageResult;
|
||||
import com.baiyue.common.core.export.ExportContracts.ExportBatchRequest;
|
||||
import com.baiyue.lastleg.dto.LastlegOrderRequests;
|
||||
import com.baiyue.lastleg.service.LastlegOrderService;
|
||||
import com.baiyue.lastleg.inventory.query.dto.InventoryQueryRequests;
|
||||
import com.baiyue.lastleg.inventory.query.service.InventoryQueryService;
|
||||
import com.baiyue.lastleg.masterdata.exchange.dto.MonthlyExchangeRateDtos;
|
||||
import com.baiyue.lastleg.masterdata.exchange.service.MonthlyExchangeRateService;
|
||||
import com.baiyue.lastleg.fleet.reporting.TripOperationsModels;
|
||||
import com.baiyue.lastleg.fleet.reporting.TripOperationsService;
|
||||
import com.baiyue.lastleg.security.InternalServiceTokenGuard;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import jakarta.validation.Validation;
|
||||
import org.junit.jupiter.api.*;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
class LastlegExportProviderServiceTest {
|
||||
private LastlegExportProviderService service;
|
||||
private LastlegOrderService orders;
|
||||
private InventoryQueryService inventory;
|
||||
private MonthlyExchangeRateService rates;
|
||||
private TripOperationsService operations;
|
||||
private jakarta.validation.ValidatorFactory validators;
|
||||
|
||||
@BeforeEach void setup() {
|
||||
service = new LastlegExportProviderService();
|
||||
orders = mock(LastlegOrderService.class); inventory = mock(InventoryQueryService.class);
|
||||
rates = mock(MonthlyExchangeRateService.class); operations = mock(TripOperationsService.class);
|
||||
ReflectionTestUtils.setField(service, "orders", orders);
|
||||
ReflectionTestUtils.setField(service, "inventory", inventory);
|
||||
ReflectionTestUtils.setField(service, "rates", rates);
|
||||
ReflectionTestUtils.setField(service, "operations", operations);
|
||||
ReflectionTestUtils.setField(service, "json", new ObjectMapper().findAndRegisterModules().disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS));
|
||||
validators = Validation.buildDefaultValidatorFactory();
|
||||
ReflectionTestUtils.setField(service, "validator", validators.getValidator());
|
||||
ReflectionTestUtils.setField(service, "signingKey", "test-internal-token-with-at-least-32-bytes");
|
||||
}
|
||||
@AfterEach void close() { validators.close(); }
|
||||
|
||||
@Test void batchesAllRowsAndBindsSnapshotToFiltersRequesterAndAttempt() {
|
||||
var row = new MonthlyExchangeRateDtos.Response("2026-10", "USD", "CNY", new BigDecimal("7.12"), "ACTIVE", 1, "operator", LocalDateTime.of(2026,10,8,12,0), null);
|
||||
when(rates.page(any())).thenAnswer(call -> {
|
||||
MonthlyExchangeRateDtos.Query q = call.getArgument(0);
|
||||
return new PageResult<>(List.of(row), q.page(), q.size(), 2, 2);
|
||||
});
|
||||
var first = service.batch("MONTHLY_EXCHANGE_RATE_LIST", request(Map.of("status", "ACTIVE"), null, null));
|
||||
assertTrue(first.hasMore()); assertEquals(2L, first.totalRows());
|
||||
assertEquals(new BigDecimal("7.12"), first.rows().get(0).get("usdToCnyAverage"));
|
||||
assertEquals("2026-10-08T12:00:00", first.rows().get(0).get("updatedAt"));
|
||||
var second = service.batch("MONTHLY_EXCHANGE_RATE_LIST", request(Map.of("status", "ACTIVE"), first.nextCursor(), first.snapshotToken()));
|
||||
assertFalse(second.hasMore()); assertTrue(second.columns().isEmpty()); assertEquals(first.schemaHash(), second.schemaHash());
|
||||
verify(rates).page(new MonthlyExchangeRateDtos.Query(2,1,null,null,"ACTIVE"));
|
||||
assertThrows(ResponseStatusException.class, () -> service.batch("MONTHLY_EXCHANGE_RATE_LIST", request(Map.of("status", "INACTIVE"), "1", first.snapshotToken())));
|
||||
assertThrows(ResponseStatusException.class, () -> service.batch("MONTHLY_EXCHANGE_RATE_LIST", new ExportBatchRequest("t","0","PLATFORM","other",1,Map.of("status","ACTIVE"),"1",first.snapshotToken(),1)));
|
||||
assertThrows(ResponseStatusException.class, () -> service.batch("MONTHLY_EXCHANGE_RATE_LIST", new ExportBatchRequest("t","0","PLATFORM","u",2,Map.of("status","ACTIVE"),"1",first.snapshotToken(),1)));
|
||||
}
|
||||
|
||||
@Test void retainsOrderStageFalseAndRelabelFiltersWithoutExportingInternalIds() {
|
||||
var order = new ObjectMapper().findAndRegisterModules().convertValue(Map.of("id", "9007199254740993", "orderNo", "LL-1", "currentStatus", "PENDING_ASSIGNMENT", "abnormal", false, "detained", true), com.baiyue.lastleg.dto.LastlegOrderSummary.class);
|
||||
when(orders.page(isNull(), any(), eq("RL-1"))).thenReturn(new PageResult<>(List.of(order),1,1,1,1));
|
||||
var result = service.batch("LAST_MILE_ORDER_LIST", request(Map.of("detained",false,"sailingStage","BEFORE_DEPARTURE","relabelNo","RL-1"),null,null));
|
||||
verify(orders).page(isNull(), argThat(q -> Boolean.FALSE.equals(q.detained()) && q.sailingStage() == LastlegOrderRequests.SailingStage.BEFORE_DEPARTURE), eq("RL-1"));
|
||||
assertEquals("否", result.rows().get(0).get("abnormal"));
|
||||
assertEquals("是", result.rows().get(0).get("detained"));
|
||||
assertEquals("待分配", result.rows().get(0).get("currentStatus"));
|
||||
assertTrue(result.columns().stream().noneMatch(c -> c.key().equals("id") || c.key().equals("customerId")));
|
||||
}
|
||||
|
||||
@Test void keepsCustomerScopeAndLedgerCustomerFilter() {
|
||||
when(inventory.ledgers(eq("200"), any())).thenReturn(new PageResult<>(List.of(),1,1,0,0));
|
||||
service.batch("OVERSEAS_INVENTORY_LEDGER", request(Map.of("customerId","200","customerName","客户"),null,null));
|
||||
verify(inventory).ledgers(eq("200"), argThat(q -> "客户".equals(q.customerName())));
|
||||
}
|
||||
|
||||
@Test void defaultsCostVisibilityClosed() {
|
||||
when(operations.report(any(), eq(false))).thenReturn(new TripOperationsModels.Result(new PageResult<>(List.of(),1,1,0,0),null,null));
|
||||
service.batch("TRIP_OPERATIONS_LIST",request(Map.of("from","2026-10-01T00:00:00Z","to","2026-10-08T00:00:00Z"),null,null));
|
||||
verify(operations).report(any(), eq(false));
|
||||
}
|
||||
|
||||
@Test void rejectsScopeInvalidParametersAndUntrustedInternalCalls() {
|
||||
assertThrows(ResponseStatusException.class, () -> service.batch("LAST_MILE_ORDER_LIST",new ExportBatchRequest("t","1","MERCHANT","u",1,Map.of(),null,null,1)));
|
||||
assertThrows(ResponseStatusException.class, () -> service.batch("LAST_MILE_ORDER_LIST",request(Map.of("unknown","x"),null,null)));
|
||||
assertThrows(ResponseStatusException.class, () -> service.batch("LAST_MILE_ORDER_LIST",request(Map.of(),"1",null)));
|
||||
assertThrows(ResponseStatusException.class, () -> new LastlegExportProviderController(new InternalServiceTokenGuard("expected"),service).batch("wrong","LAST_MILE_ORDER_LIST",request(Map.of(),null,null)));
|
||||
verifyNoInteractions(orders);
|
||||
}
|
||||
|
||||
private ExportBatchRequest request(Map<String,Object> p,String cursor,String snapshot) {
|
||||
return new ExportBatchRequest("t","0","PLATFORM","u",1,p,cursor,snapshot,1);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user