diff --git a/backend-java/src/test/java/com/nanri/aiimage/metrics/TaskDurationMetricsTest.java b/backend-java/src/test/java/com/nanri/aiimage/metrics/TaskDurationMetricsTest.java new file mode 100644 index 00000000..fed3af5b --- /dev/null +++ b/backend-java/src/test/java/com/nanri/aiimage/metrics/TaskDurationMetricsTest.java @@ -0,0 +1,77 @@ +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.assertTrue; + +/** + * task-183:task.duration 耗时记录契约(spec 11 §1)。 + * 开始→终态耗时以 Timer 记录(未配置注册表时降级 debug 日志);非负;分 moduleType。 + */ +class TaskDurationMetricsTest { + + private final SimpleMeterRegistry registry = new SimpleMeterRegistry(); + private final TaskObservabilityMetrics metrics = new TaskObservabilityMetrics("server-110", registry); + + private io.micrometer.core.instrument.Timer timer(String moduleType) { + return registry.get("aiimage.task.duration").tag("moduleType", moduleType).timer(); + } + + @Test + void durationRecorded() { + metrics.taskDuration("similarasin", 1_234L); + assertEquals(1, timer("similarasin").count()); + assertEquals(1_234.0, timer("similarasin").totalTime(java.util.concurrent.TimeUnit.MILLISECONDS), 0.001); + } + + @Test + void durationAccumulates() { + metrics.taskDuration("similarasin", 100L); + metrics.taskDuration("similarasin", 200L); + assertEquals(2, timer("similarasin").count()); + assertEquals(300.0, timer("similarasin").totalTime(java.util.concurrent.TimeUnit.MILLISECONDS), 0.001); + } + + @Test + void shortTaskRecorded() { + metrics.taskDuration("similarasin", 1L); + assertTrue(timer("similarasin").count() >= 1); + } + + @Test + void longTaskRecordedLarger() { + metrics.taskDuration("similarasin", 600_000L); + assertEquals(600_000.0, timer("similarasin").totalTime(java.util.concurrent.TimeUnit.MILLISECONDS), 0.001); + } + + @Test + void durationNeverNegative() { + metrics.taskDuration("similarasin", -5L); + assertEquals(0.0, timer("similarasin").totalTime(java.util.concurrent.TimeUnit.MILLISECONDS), 0.001, + "负耗时按 0 处理,不应破坏指标"); + } + + @Test + void durationSplitByModule() { + metrics.taskDuration("similarasin", 100L); + metrics.taskDuration("publish", 50L); + assertEquals(1, timer("similarasin").count()); + assertEquals(1, timer("publish").count()); + } + + @Test + void durationNameFrozen() { + metrics.taskDuration("similarasin", 10L); + assertTrue(registry.getMeters().stream() + .anyMatch(m -> m.getId().getName().equals("aiimage.task.duration"))); + } + + @Test + void durationCarriesInstanceLabel() { + metrics.taskDuration("similarasin", 10L); + assertEquals("server-110", + registry.get("aiimage.task.duration").timer().getId().getTag("instanceId")); + } +}