feat: 完善数据空间查询资源边界

- 将联邦源数与分片上限改为配置驱动

- 固化工作台一万行上限及结果字节保护
This commit is contained in:
2026-09-01 17:02:37 +08:00
parent 3e34b65bcb
commit c00369f6b9
10 changed files with 367 additions and 20 deletions

View File

@@ -0,0 +1,62 @@
package tech.easyflow.dataspace.config;
import com.easyagents.federation.sql.federation.FederationExecutionPolicy;
import java.time.Duration;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.util.unit.DataSize;
/**
* 数据空间联邦执行策略配置测试。
*/
public class DataspaceFederationPropertiesTest {
/**
* 验证默认配置保持原有两源安全边界。
*/
@Test
public void shouldKeepBasicPolicyByDefault() throws Exception {
DataspaceFederationProperties properties = new DataspaceFederationProperties();
properties.afterPropertiesSet();
FederationExecutionPolicy policy = properties.toExecutionPolicy();
Assert.assertEquals(FederationExecutionPolicy.basic(), policy);
}
/**
* 验证 benchmark 可只扩大引用源和分片数,不放宽行、字节和时限。
*/
@Test
public void shouldBuildSixSourceBenchmarkPolicy() throws Exception {
DataspaceFederationProperties properties = new DataspaceFederationProperties();
properties.setMaximumReferencedSources(6);
properties.setMaximumFragments(12);
properties.setMaximumConcurrentFragments(2);
properties.setMaximumIntermediateRows(100_000L);
properties.setMaximumIntermediateBytes(DataSize.ofMegabytes(64));
properties.setMaximumExecutionTime(Duration.ofSeconds(60));
properties.afterPropertiesSet();
FederationExecutionPolicy policy = properties.toExecutionPolicy();
Assert.assertEquals(6, policy.maximumReferencedSources());
Assert.assertEquals(12, policy.maximumFragments());
Assert.assertEquals(2, policy.maximumConcurrentFragments());
Assert.assertEquals(100_000L, policy.maximumIntermediateRows());
Assert.assertEquals(64L * 1024L * 1024L, policy.maximumIntermediateBytes());
Assert.assertEquals(60_000L, policy.maximumExecutionTimeMillis());
}
/**
* 验证引用源数不能超过分片上限。
*/
@Test(expected = IllegalStateException.class)
public void shouldRejectSourceLimitGreaterThanFragmentLimit() throws Exception {
DataspaceFederationProperties properties = new DataspaceFederationProperties();
properties.setMaximumReferencedSources(6);
properties.setMaximumFragments(4);
properties.afterPropertiesSet();
}
}

View File

@@ -0,0 +1,52 @@
package tech.easyflow.dataspace.config;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.util.unit.DataSize;
/**
* 数据空间同步查询结果保护配置测试。
*/
public class DataspaceQueryPropertiesTest {
/**
* 验证生产默认值保持 16 MiB 总结果和 1 MiB 单字段保护。
*/
@Test
public void shouldKeepSafeDefaults() throws Exception {
DataspaceQueryProperties properties = new DataspaceQueryProperties();
properties.afterPropertiesSet();
Assert.assertEquals(16L * 1024L * 1024L,
properties.getMaximumResultBytes().toBytes());
Assert.assertEquals(1024L * 1024L,
properties.getMaximumCellBytes().toBytes());
}
/**
* 验证 benchmark 可显式提高同步结果字节上限。
*/
@Test
public void shouldAcceptLargeResultBenchmarkLimits() throws Exception {
DataspaceQueryProperties properties = new DataspaceQueryProperties();
properties.setMaximumResultBytes(DataSize.ofMegabytes(64));
properties.afterPropertiesSet();
Assert.assertEquals(64L * 1024L * 1024L,
properties.getMaximumResultBytes().toBytes());
}
/**
* 验证单字段上限不能超过总结果上限。
*/
@Test(expected = IllegalStateException.class)
public void shouldRejectCellLimitGreaterThanResultLimit() throws Exception {
DataspaceQueryProperties properties = new DataspaceQueryProperties();
properties.setMaximumResultBytes(DataSize.ofKilobytes(512));
properties.setMaximumCellBytes(DataSize.ofMegabytes(1));
properties.afterPropertiesSet();
}
}

View File

@@ -16,6 +16,7 @@ import java.util.List;
import java.util.Map;
import org.junit.Test;
import tech.easyflow.common.cache.RedisLockExecutor;
import tech.easyflow.dataspace.config.DataspaceFederationProperties;
import tech.easyflow.dataspace.entity.Dataspace;
import tech.easyflow.dataspace.entity.DataspaceConnection;
import tech.easyflow.dataspace.entity.DataspaceObject;
@@ -183,7 +184,8 @@ public class DataspaceMetadataCompatibilityTest {
mock(DataspaceDatabaseProviderRegistry.class),
resolver,
mock(RedisLockExecutor.class),
mock(org.springframework.transaction.support.TransactionTemplate.class));
mock(org.springframework.transaction.support.TransactionTemplate.class),
new DataspaceFederationProperties());
return new Fixture(service);
}

View File

@@ -0,0 +1,47 @@
package tech.easyflow.dataspace.service;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import org.junit.Test;
import tech.easyflow.common.web.exceptions.BusinessException;
/**
* SQL 工作台最大返回行数测试。
*/
public class DataspaceQueryRowLimitTest {
/**
* 验证调用方未指定时使用 500 行默认值。
*/
@Test
public void shouldUseDefaultRowsWhenMissing() {
assertEquals(500, DataspaceQueryService.normalizeMaximumRows(null));
}
/**
* 验证 10,000 行产品上限可直接使用。
*/
@Test
public void shouldAcceptMaximumRows() {
assertEquals(10_000, DataspaceQueryService.normalizeMaximumRows(10_000));
}
/**
* 验证非正数和超过产品上限的请求被明确拒绝。
*/
@Test
public void shouldRejectRowsOutsideProductRange() {
assertInvalid(0);
assertInvalid(10_001);
}
private void assertInvalid(int value) {
try {
DataspaceQueryService.normalizeMaximumRows(value);
fail("超出范围的最大返回行数应被拒绝");
} catch (BusinessException exception) {
assertEquals(40066, exception.getErrorCode());
}
}
}