task-184: task.heartbeat.age 心跳年龄 gauge 契约(新鲜/陈旧/负时钟保护/未写无 meter)+ 8 条测试

This commit is contained in:
2026-09-04 23:48:21 +08:00
parent 0ec4fb3534
commit 17cfd6902b
@@ -0,0 +1,79 @@
package com.nanri.aiimage.metrics;
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* task-184task.heartbeat.age 心跳年龄 gauge 契约(spec 11 §1)。
* 年龄 = 距最后心跳的毫秒数,由 TaskHeartbeatService/巡检写入;新鲜/陈旧可观测;
* 刚心跳≈0;时钟负保护;未设置不产生 meter。
*/
class TaskHeartbeatAgeMetricsTest {
private final SimpleMeterRegistry registry = new SimpleMeterRegistry();
private final TaskObservabilityMetrics metrics = new TaskObservabilityMetrics("server-110", registry);
private io.micrometer.core.instrument.Gauge gauge(String moduleType) {
return registry.get("aiimage.task.heartbeat.age").tag("moduleType", moduleType).gauge();
}
@Test
void ageComputedFreshAndStale() {
metrics.taskHeartbeatAge("similarasin", 200L);
assertEquals(200.0, gauge("similarasin").value(), "新鲜心跳年龄应小");
metrics.taskHeartbeatAge("similarasin", 3_600_000L);
assertEquals(3_600_000.0, gauge("similarasin").value(), "陈旧心跳年龄应大");
}
@Test
void ageJustHeartbeatIsZero() {
metrics.taskHeartbeatAge("similarasin", 0L);
assertEquals(0.0, gauge("similarasin").value());
}
@Test
void ageClockNegativeGuard() {
metrics.taskHeartbeatAge("similarasin", -100L);
assertEquals(0.0, gauge("similarasin").value(), "时钟回拨导致的负年龄按 0 处理");
}
@Test
void ageUpdatesOnEachWrite() {
metrics.taskHeartbeatAge("similarasin", 1_000L);
metrics.taskHeartbeatAge("similarasin", 2_000L);
assertEquals(2_000.0, gauge("similarasin").value());
}
@Test
void ageSplitByModule() {
metrics.taskHeartbeatAge("similarasin", 500L);
metrics.taskHeartbeatAge("publish", 900L);
assertEquals(500.0, gauge("similarasin").value());
assertEquals(900.0, gauge("publish").value());
}
@Test
void noHeartbeatYetNoGauge() {
assertNull(registry.find("aiimage.task.heartbeat.age")
.tag("moduleType", "withdraw").gauge(),
"从未写入心跳年龄时不应产生 gauge");
}
@Test
void ageNameFrozen() {
metrics.taskHeartbeatAge("similarasin", 10L);
assertTrue(registry.getMeters().stream()
.anyMatch(m -> m.getId().getName().equals("aiimage.task.heartbeat.age")));
}
@Test
void ageCarriesInstanceLabel() {
metrics.taskHeartbeatAge("similarasin", 10L);
assertEquals("server-110",
registry.get("aiimage.task.heartbeat.age").gauge().getId().getTag("instanceId"));
}
}