From 75d553f99a22c2d7b2fe7116d8c911004d6578fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E8=87=AA=E8=BE=BE?= <980324341@qq.com> Date: Fri, 4 Sep 2026 23:53:24 +0800 Subject: [PATCH] =?UTF-8?q?task-191:=20=E5=8F=8C=E5=AE=9E=E4=BE=8B?= =?UTF-8?q?=E6=8C=87=E6=A0=87=E5=8C=BA=E5=88=86=E5=9B=9E=E5=BD=92=E5=A5=91?= =?UTF-8?q?=E7=BA=A6=EF=BC=88instanceId=20=E5=88=86=E6=A1=B6=E4=B8=8D?= =?UTF-8?q?=E4=B8=B2=E3=80=81=E6=9C=AA=E9=85=8D=E7=BD=AE=E5=BD=92=20unknow?= =?UTF-8?q?n=E3=80=81=E8=B7=A8=E5=AE=9E=E4=BE=8B=E5=8F=AF=E8=81=9A?= =?UTF-8?q?=E5=90=88=E3=80=81=E5=90=8D=E9=9B=86=E5=90=88=E4=B8=80=E8=87=B4?= =?UTF-8?q?=EF=BC=89+=208=20=E6=9D=A1=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../metrics/DualInstanceMetricTest.java | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 backend-java/src/test/java/com/nanri/aiimage/metrics/DualInstanceMetricTest.java diff --git a/backend-java/src/test/java/com/nanri/aiimage/metrics/DualInstanceMetricTest.java b/backend-java/src/test/java/com/nanri/aiimage/metrics/DualInstanceMetricTest.java new file mode 100644 index 00000000..33afab6b --- /dev/null +++ b/backend-java/src/test/java/com/nanri/aiimage/metrics/DualInstanceMetricTest.java @@ -0,0 +1,96 @@ +package com.nanri.aiimage.metrics; + +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; +import org.junit.jupiter.api.Test; + +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * task-191:双实例指标区分回归契约(spec 11 §1:instanceId 区分 server-110/server-121)。 + * 同一 registry 下两实例同模块指标按 instanceId 分桶、不串;未配置 instanceId 归 unknown; + * 指标名集合稳定一致。 + */ +class DualInstanceMetricTest { + + private final SimpleMeterRegistry registry = new SimpleMeterRegistry(); + + @Test + void instance110LabelApplied() { + new TaskObservabilityMetrics("server-110", registry).taskCreated("similarasin"); + assertEquals("server-110", + registry.get("aiimage.task.created").counter().getId().getTag("instanceId")); + } + + @Test + void instance121LabelApplied() { + new TaskObservabilityMetrics("server-121", registry).taskCreated("similarasin"); + assertEquals("server-121", + registry.get("aiimage.task.created").counter().getId().getTag("instanceId")); + } + + @Test + void twoInstancesDoNotCrossCount() { + TaskObservabilityMetrics a = new TaskObservabilityMetrics("server-110", registry); + TaskObservabilityMetrics b = new TaskObservabilityMetrics("server-121", registry); + a.taskCreated("similarasin"); + b.taskCreated("similarasin"); + b.taskCreated("similarasin"); + assertEquals(1.0, registry.get("aiimage.task.created").tag("moduleType", "similarasin") + .tag("instanceId", "server-110").counter().count()); + assertEquals(2.0, registry.get("aiimage.task.created").tag("moduleType", "similarasin") + .tag("instanceId", "server-121").counter().count()); + } + + @Test + void unconfiguredInstanceFallsBackToUnknown() { + new TaskObservabilityMetrics(null, registry).taskCreated("brand"); + assertEquals("unknown", + registry.get("aiimage.task.created").counter().getId().getTag("instanceId")); + new TaskObservabilityMetrics(" ", registry).taskCreated("brand"); + } + + @Test + void metricsAggregatableAcrossInstances() { + TaskObservabilityMetrics a = new TaskObservabilityMetrics("server-110", registry); + TaskObservabilityMetrics b = new TaskObservabilityMetrics("server-121", registry); + a.taskTerminal("similarasin", "success"); + b.taskTerminal("similarasin", "success"); + // 聚合:跨 instanceId 各 meter 求和,双实例总数应为 2 + double total = registry.find("aiimage.task.success").tag("moduleType", "similarasin").counters().stream() + .mapToDouble(io.micrometer.core.instrument.Counter::count).sum(); + assertEquals(2.0, total, "同模块跨实例指标可聚合"); + } + + @Test + void instanceLabelStableAcrossCalls() { + TaskObservabilityMetrics a = new TaskObservabilityMetrics("server-110", registry); + a.taskCreated("publish"); + a.taskCreated("publish"); + assertEquals(1, registry.find("aiimage.task.created").tag("moduleType", "publish") + .tag("instanceId", "server-110").counters().size(), "同实例同模块应为同一 meter"); + assertEquals(2.0, registry.get("aiimage.task.created").tag("moduleType", "publish") + .tag("instanceId", "server-110").counter().count()); + } + + @Test + void instanceIdGetterReturnsConfiguredValue() { + assertEquals("server-121", new TaskObservabilityMetrics("server-121", null).instanceId()); + assertNotEquals("", new TaskObservabilityMetrics("server-121", null).instanceId()); + } + + @Test + void metricNameSetIdenticalAcrossInstances() { + TaskObservabilityMetrics a = new TaskObservabilityMetrics("server-110", registry); + TaskObservabilityMetrics b = new TaskObservabilityMetrics("server-121", registry); + a.taskCreated("x"); + b.taskCreated("x"); + java.util.Set names = registry.getMeters().stream() + .map(m -> m.getId().getName()).collect(Collectors.toSet()); + assertTrue(names.contains("aiimage.task.created")); + assertEquals(1, names.size(), "仅指标名集合应一致(标签不同不算漂移)"); + } +}