diff --git a/backend-java/src/test/java/com/nanri/aiimage/metrics/TaskTerminalMetricsTest.java b/backend-java/src/test/java/com/nanri/aiimage/metrics/TaskTerminalMetricsTest.java new file mode 100644 index 00000000..7ab7c5b2 --- /dev/null +++ b/backend-java/src/test/java/com/nanri/aiimage/metrics/TaskTerminalMetricsTest.java @@ -0,0 +1,86 @@ +package com.nanri.aiimage.metrics; + +import io.micrometer.core.instrument.Counter; +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-182:task.success/failed/cancelled 终态计数契约(spec 11 §1)。 + * 每个终态独立计数、分 moduleType;单次终态调用精确 +1,互不串扰。 + */ +class TaskTerminalMetricsTest { + + private final SimpleMeterRegistry registry = new SimpleMeterRegistry(); + private final TaskObservabilityMetrics metrics = new TaskObservabilityMetrics("server-110", registry); + + private Counter counter(String terminal, String moduleType) { + return registry.get("aiimage.task." + terminal).tag("moduleType", moduleType).counter(); + } + + @Test + void successCounted() { + metrics.taskTerminal("similarasin", "success"); + assertEquals(1.0, counter("success", "similarasin").count()); + } + + @Test + void failedCounted() { + metrics.taskTerminal("similarasin", "failed"); + assertEquals(1.0, counter("failed", "similarasin").count()); + } + + @Test + void cancelledCounted() { + metrics.taskTerminal("similarasin", "cancelled"); + assertEquals(1.0, counter("cancelled", "similarasin").count()); + } + + @Test + void moduleSplitIndependent() { + metrics.taskTerminal("similarasin", "success"); + metrics.taskTerminal("publish", "success"); + assertEquals(1.0, counter("success", "similarasin").count()); + assertEquals(1.0, counter("success", "publish").count()); + } + + @Test + void singleTerminalCallCountsOnce() { + metrics.taskTerminal("brand", "failed"); + assertEquals(1.0, counter("failed", "brand").count(), "单次终态调用精确 +1"); + } + + @Test + void terminalTypesDoNotCrossCount() { + metrics.taskTerminal("similarasin", "success"); + metrics.taskTerminal("similarasin", "failed"); + assertEquals(1.0, counter("success", "similarasin").count()); + assertEquals(1.0, counter("failed", "similarasin").count()); + assertEquals(0.0, registry.find("aiimage.task.cancelled").tag("moduleType", "similarasin").counter() == null + ? 0.0 + : registry.find("aiimage.task.cancelled").tag("moduleType", "similarasin").counter().count(), + "success/failed 不应污染 cancelled"); + } + + @Test + void terminalNamesFrozen() { + metrics.taskTerminal("similarasin", "success"); + metrics.taskTerminal("similarasin", "failed"); + metrics.taskTerminal("similarasin", "cancelled"); + assertTrue(registry.getMeters().stream() + .anyMatch(m -> m.getId().getName().equals("aiimage.task.success"))); + assertTrue(registry.getMeters().stream() + .anyMatch(m -> m.getId().getName().equals("aiimage.task.failed"))); + assertTrue(registry.getMeters().stream() + .anyMatch(m -> m.getId().getName().equals("aiimage.task.cancelled"))); + } + + @Test + void countersCarryInstanceLabel() { + metrics.taskTerminal("similarasin", "success"); + assertEquals("server-110", + registry.get("aiimage.task.success").counter().getId().getTag("instanceId")); + } +}