This commit is contained in:
2026-10-08 17:07:57 +08:00
parent 16d2d9111a
commit c1ddb658bd
111 changed files with 2914 additions and 941 deletions
@@ -25,6 +25,7 @@ class ExportProviderClientTest {
@MockBean private WarehouseExportProviderClient warehouse;
@MockBean private FirstlegExportProviderClient firstleg;
@MockBean private FinanceExportProviderClient finance;
@MockBean private LastlegExportProviderClient lastleg;
@Resource private ExportProviderClient client;
@Configuration(proxyBeanMethods = false)
@@ -48,6 +49,16 @@ class ExportProviderClientTest {
verifyNoInteractions(iam,warehouse,firstleg,finance);
}
@Test void routesLastlegExportsThroughTheBoundedInternalClient() {
var response=ApiResponse.success(new ExportBatchResponse(1,"hash","snapshot",java.util.List.of(),java.util.List.of(),null,false,0L));
when(lastleg.batch(anyString(),anyString(),any())).thenReturn(response);
var definition=new ExportDefinitionRegistry.Definition();definition.setProviderService("lastleg-service");
var request=new ExportBatchRequest("9","0","PLATFORM","7",1,Map.of(),null,null,200);
assertSame(response,client.batch("token","LAST_MILE_ORDER_LIST",definition,request));
verify(lastleg).batch("token","LAST_MILE_ORDER_LIST",request);
verifyNoInteractions(iam,order,warehouse,firstleg,finance);
}
@Test void routesFinanceExportsToFinanceService() {
var response=ApiResponse.success(new ExportBatchResponse(1,"hash","snapshot",java.util.List.of(),java.util.List.of(),null,false,0L));
when(finance.batch(anyString(),anyString(),any())).thenReturn(response);
@@ -0,0 +1,48 @@
package com.baiyue.file.config;
import org.junit.jupiter.api.Test;
import org.yaml.snakeyaml.Yaml;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.*;
class LastlegExportDefinitionContractTest {
@Test void localAndNacosDefinitionsKeepTheSameBoundedProviderAndPermissions() throws Exception {
Map<?, ?> local = definitions(Path.of("src/main/resources/application.yml"));
Map<?, ?> nacos = definitions(Path.of("../config/nacos/test/file-service.yml"));
Map<String, String> expected = Map.ofEntries(
Map.entry("LAST_MILE_ORDER_LIST", "platform:overseas-warehouse:last-mile-order:export"),
Map.entry("OVERSEAS_INVENTORY_BALANCE", "platform:overseas-warehouse:inventory:export"),
Map.entry("OVERSEAS_INVENTORY_LEDGER", "platform:overseas-warehouse:inventory:export"),
Map.entry("OVERSEAS_QUOTE_LIST", "platform:overseas-master-data:quote:export"),
Map.entry("MONTHLY_EXCHANGE_RATE_LIST", "platform:overseas-master-data:exchange-rate:export"),
Map.entry("VEHICLE_LIST", "platform:overseas-master-data:vehicle:export"),
Map.entry("FLEET_QUOTE_LIST", "platform:fleet:quote:export"),
Map.entry("TRIP_OPERATIONS_LIST", "platform:fleet:operations:export"));
for (var entry : expected.entrySet()) {
var definition = (Map<?, ?>) local.get(entry.getKey());
assertNotNull(definition, entry.getKey());
assertEquals(definition, nacos.get(entry.getKey()));
assertEquals("lastleg-service", definition.get("provider-service"));
assertEquals("/internal/exports/v1/" + entry.getKey() + "/batches", definition.get("provider-path"));
assertEquals(entry.getValue(), definition.get("required-permission"));
assertEquals("PLATFORM", definition.get("app-scope"));
assertEquals(200, definition.get("batch-size"));
var controlled = new ExportDefinitionRegistry.Definition();
controlled.setProviderService("lastleg-service");
controlled.setProviderPath(String.valueOf(definition.get("provider-path")));
controlled.setRequiredPermission(entry.getValue());
controlled.setAppScope("PLATFORM");
var registry = new ExportDefinitionRegistry();
assertDoesNotThrow(() -> registry.setDefinitions(Map.of(entry.getKey(), controlled)));
}
}
private Map<?, ?> definitions(Path path) throws Exception {
Object value = new Yaml().load(Files.readString(path));
for (String key : new String[]{"baiyue", "file", "export", "definitions"}) value = ((Map<?, ?>) value).get(key);
return (Map<?, ?>) value;
}
}
@@ -28,6 +28,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
@SpringJUnitConfig(classes = {ExportTaskService.class, ExportTaskServiceTest.TestConfig.class})
@@ -55,6 +56,32 @@ class ExportTaskServiceTest {
assertEquals(ResultCode.FORBIDDEN, denied.getResultCode());
}
@Test
void operationExportDerivesCostVisibilityFromAuthenticatedPermissions() {
var definition = definition();
definition.setRequiredPermission("platform:fleet:operations:export");
when(registry.require("TRIP_OPERATIONS_LIST")).thenReturn(definition);
when(states.createConstrained(any(FileExportTask.class))).thenAnswer(invocation ->
new ExportStateService.CreationResult(invocation.getArgument(0), true));
service.create(user(1L, Set.of("platform:fleet:operations:export")),
new CreateExportTaskRequest("TRIP_OPERATIONS_LIST", "XLSX", "出车记录", Map.of("costVisible", true)));
var captured = org.mockito.ArgumentCaptor.forClass(FileExportTask.class);
verify(states).createConstrained(captured.capture());
assertTrue(captured.getValue().getParametersJson().contains("\"costVisible\":false"));
}
@Test
void costPermissionCannotBeBypassedByDownloadAllOrRetry() {
FileExportTask task = new FileExportTask();
task.setId(9L); task.setTenantId(0L); task.setAppCode("PLATFORM"); task.setRequestedBy(2L);
task.setExportType("TRIP_OPERATIONS_LIST"); task.setParametersJson("{\"costVisible\":true}");
when(repository.find(9L)).thenReturn(task);
var reader = user(1L, Set.of("platform:download:all", "platform:fleet:operations:export"));
assertEquals(ResultCode.FORBIDDEN, assertThrows(BizException.class, () -> service.download(reader,9L)).getResultCode());
assertEquals(ResultCode.FORBIDDEN, assertThrows(BizException.class, () -> service.retry(reader,9L)).getResultCode());
verifyNoInteractions(storage);
}
@Test
void refusesAnotherUsersTaskUnlessDownloadAllIsGranted() {
when(registry.require("CUSTOMER_LIST")).thenReturn(definition());