task-80: 补充 JVM 堆、直接内存、临时磁盘和连接池容量配置说明
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
package com.nanri.aiimage.config;
|
||||
|
||||
import com.nanri.aiimage.config.CapacityPlanService.CapacityPlan;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* Task 80:补充 JVM 堆、直接内存、临时磁盘和连接池容量配置说明。容量计划
|
||||
* (CapacityPlan)集中描述四类容量边界,构造时注入机器内存以便确定性校验:
|
||||
* 堆/直接内存不得超机器内存比例、临时磁盘预留必须非零、连接池总和有上限。
|
||||
*/
|
||||
class CapacityPlanServiceTest {
|
||||
|
||||
// ---- 1. 默认路径:默认配置下生成完整容量计划,四类容量齐备且无越限警告 ----
|
||||
|
||||
@Test
|
||||
void test_task_080_task_normal_default_path() {
|
||||
CapacityPlanProperties properties = new CapacityPlanProperties();
|
||||
CapacityPlanService service = new CapacityPlanService(properties, machineBytes(32L * 1024 * 1024 * 1024));
|
||||
|
||||
CapacityPlan plan = service.buildPlan();
|
||||
|
||||
assertNotNull(plan);
|
||||
assertEquals(properties.getHeapMaxBytes(), plan.heapMaxBytes(), "堆上限来自配置");
|
||||
assertEquals(properties.getDirectMaxBytes(), plan.directMaxBytes(), "直接内存上限来自配置");
|
||||
assertEquals(properties.getTempDiskReserveBytes(), plan.tempDiskReserveBytes(), "临时磁盘预留来自配置");
|
||||
assertEquals(properties.getDbPoolMaxSize(), plan.dbPoolMaxSize(), "DB 连接池来自配置");
|
||||
assertEquals(properties.getHttpClientPoolMaxSize(), plan.httpClientPoolMaxSize(), "外部 HTTP 连接池来自配置");
|
||||
assertEquals(properties.getRustfsPoolMaxSize(), plan.rustfsPoolMaxSize(), "RustFS 连接池来自配置");
|
||||
assertTrue(plan.warnings().isEmpty(), "默认配置(32G 机器)不应有越限警告");
|
||||
}
|
||||
|
||||
// ---- 2. 批量:多连接池全部纳入汇总校验,总和上限生效 ----
|
||||
|
||||
@Test
|
||||
void test_task_080_task_normal_multiple_items() {
|
||||
CapacityPlanProperties properties = new CapacityPlanProperties();
|
||||
properties.setDbPoolMaxSize(200);
|
||||
properties.setHttpClientPoolMaxSize(200);
|
||||
properties.setRustfsPoolMaxSize(200);
|
||||
CapacityPlanService service = new CapacityPlanService(properties, machineBytes(32L * 1024 * 1024 * 1024));
|
||||
|
||||
CapacityPlan plan = service.buildPlan();
|
||||
|
||||
assertEquals(200 + 200 + 200, plan.poolTotal(), "三个连接池总和必须纳入汇总");
|
||||
assertTrue(plan.warnings().stream().anyMatch(w -> w.contains("连接池")),
|
||||
"连接池总和超上限必须产生警告");
|
||||
}
|
||||
|
||||
// ---- 3. 幂等:重复生成容量计划结果稳定 ----
|
||||
|
||||
@Test
|
||||
void test_task_080_task_normal_repeated_operation_is_idempotent() {
|
||||
CapacityPlanProperties properties = new CapacityPlanProperties();
|
||||
CapacityPlanService service = new CapacityPlanService(properties, machineBytes(32L * 1024 * 1024 * 1024));
|
||||
|
||||
CapacityPlan first = service.buildPlan();
|
||||
CapacityPlan second = service.buildPlan();
|
||||
CapacityPlan third = service.buildPlan();
|
||||
|
||||
assertEquals(first, second, "重复生成结果必须稳定");
|
||||
assertEquals(second, third, "重复生成结果必须稳定");
|
||||
}
|
||||
|
||||
// ---- 4. 空输入:未配置项走默认值兜底,不创建无效资源 ----
|
||||
|
||||
@Test
|
||||
void test_task_080_task_boundary_empty_input() {
|
||||
CapacityPlanProperties properties = new CapacityPlanProperties();
|
||||
properties.setHeapMaxBytes(0);
|
||||
properties.setDirectMaxBytes(0);
|
||||
properties.setTempDiskReserveBytes(0);
|
||||
CapacityPlanService service = new CapacityPlanService(properties, machineBytes(32L * 1024 * 1024 * 1024));
|
||||
|
||||
CapacityPlan plan = service.buildPlan();
|
||||
|
||||
assertEquals(0, plan.heapMaxBytes(), "显式配置 0 即 0,不猜测");
|
||||
assertTrue(plan.warnings().stream().anyMatch(w -> w.contains("临时磁盘")),
|
||||
"临时磁盘预留为 0 必须警告,避免无界写盘");
|
||||
}
|
||||
|
||||
// ---- 5. 单元素:只配置一项时其余走默认值,整体计划仍完整 ----
|
||||
|
||||
@Test
|
||||
void test_task_080_task_boundary_single_item() {
|
||||
CapacityPlanProperties properties = new CapacityPlanProperties();
|
||||
properties.setDbPoolMaxSize(5);
|
||||
CapacityPlanService service = new CapacityPlanService(properties, machineBytes(32L * 1024 * 1024 * 1024));
|
||||
|
||||
CapacityPlan plan = service.buildPlan();
|
||||
|
||||
assertEquals(5, plan.dbPoolMaxSize(), "单独配置的项生效");
|
||||
assertEquals(properties.getHeapMaxBytes(), plan.heapMaxBytes(), "未配置项走默认值");
|
||||
assertTrue(plan.poolTotal() > 0, "单配置项不破坏其余默认项");
|
||||
}
|
||||
|
||||
// ---- 6. 上限/超限:堆超机器内存比例被拒绝并警告,不发生无界分配 ----
|
||||
|
||||
@Test
|
||||
void test_task_080_task_boundary_limit_and_overflow() {
|
||||
CapacityPlanProperties properties = new CapacityPlanProperties();
|
||||
properties.setHeapMaxBytes(24L * 1024 * 1024 * 1024); // 32G 机器上的 75% > 70% 阈值
|
||||
CapacityPlanService service = new CapacityPlanService(properties, machineBytes(32L * 1024 * 1024 * 1024));
|
||||
|
||||
CapacityPlan plan = service.buildPlan();
|
||||
|
||||
assertTrue(plan.warnings().stream().anyMatch(w -> w.contains("堆")),
|
||||
"堆超过机器内存比例必须警告");
|
||||
assertEquals(24L * 1024 * 1024 * 1024, plan.heapMaxBytes(), "警告不吞配置,但明确标注");
|
||||
}
|
||||
|
||||
// ---- 7. 非法参数:负值配置抛出可识别错误 ----
|
||||
|
||||
@Test
|
||||
void test_task_080_task_invalid_input_rejected() {
|
||||
CapacityPlanProperties properties = new CapacityPlanProperties();
|
||||
properties.setDbPoolMaxSize(-1);
|
||||
CapacityPlanService service = new CapacityPlanService(properties, machineBytes(32L * 1024 * 1024 * 1024));
|
||||
|
||||
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, service::buildPlan);
|
||||
|
||||
assertTrue(ex.getMessage().contains("连接池"), "负连接池必须抛出可识别错误消息");
|
||||
}
|
||||
|
||||
// ---- 8. 依赖失败:机器内存信息不可用时降级为保守计划,不泄漏 ----
|
||||
|
||||
@Test
|
||||
void test_task_080_task_dependency_failure_releases_resources() {
|
||||
CapacityPlanProperties properties = new CapacityPlanProperties();
|
||||
CapacityPlanService service = new CapacityPlanService(properties, 0);
|
||||
|
||||
CapacityPlan plan = service.buildPlan();
|
||||
|
||||
assertNotNull(plan);
|
||||
assertEquals(0, plan.machineMaxMemoryBytes(), "机器内存不可用时为 0,不猜测");
|
||||
assertTrue(plan.warnings().stream().anyMatch(w -> w.contains("机器内存")),
|
||||
"无法取得机器内存必须警告,避免过度承诺");
|
||||
}
|
||||
|
||||
private static long machineBytes(long bytes) {
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user