Copilot commented on code in PR #3122:
URL: https://github.com/apache/dubbo-go/pull/3122#discussion_r2637579091


##########
metrics/bus_test.go:
##########
@@ -44,11 +44,37 @@ func init() {
 }
 
 func TestBusPublish(t *testing.T) {
-       t.Run("testBusPublish", func(t *testing.T) {
-               event := <-mockChan
+       event := <-mockChan
 
-               if event, ok := event.(MockEvent); ok {
-                       assert.Equal(t, event, NewEmptyMockEvent())
-               }
-       })
+       if event, ok := event.(MockEvent); ok {
+               assert.Equal(t, event, NewEmptyMockEvent())
+       }
+}
+
+func TestBusUnsubscribe(t *testing.T) {
+       testChan := make(chan MetricsEvent, 1)
+       eventType := "dubbo.metrics.test.unsubscribe"
+
+       Subscribe(eventType, testChan)
+
+       testEvent := &MockEvent{}
+       Publish(testEvent)
+
+       Unsubscribe(eventType)
+
+       Publish(testEvent)
+}
+
+func TestBusPublishChannelFull(t *testing.T) {
+       testChan := make(chan MetricsEvent, 1)
+       eventType := "dubbo.metrics.test.full"
+
+       Subscribe(eventType, testChan)
+
+       testEvent := &MockEvent{}
+       testChan <- testEvent
+
+       Publish(testEvent)
+
+       Unsubscribe(eventType)
 }

Review Comment:
   The test TestBusPublishChannelFull does not verify the expected behavior 
when publishing to a full channel. The channel is filled with one event, then a 
Publish is attempted, but there's no assertion to verify what happens (e.g., 
whether the event is dropped, logged, or blocks). Consider adding assertions to 
verify the expected behavior when the channel is full.



##########
metrics/bus_test.go:
##########
@@ -44,11 +44,37 @@ func init() {
 }
 
 func TestBusPublish(t *testing.T) {
-       t.Run("testBusPublish", func(t *testing.T) {
-               event := <-mockChan
+       event := <-mockChan
 
-               if event, ok := event.(MockEvent); ok {
-                       assert.Equal(t, event, NewEmptyMockEvent())
-               }
-       })
+       if event, ok := event.(MockEvent); ok {
+               assert.Equal(t, event, NewEmptyMockEvent())
+       }
+}
+
+func TestBusUnsubscribe(t *testing.T) {
+       testChan := make(chan MetricsEvent, 1)
+       eventType := "dubbo.metrics.test.unsubscribe"
+
+       Subscribe(eventType, testChan)
+
+       testEvent := &MockEvent{}
+       Publish(testEvent)
+
+       Unsubscribe(eventType)
+
+       Publish(testEvent)
+}

Review Comment:
   The test TestBusUnsubscribe does not verify the behavior after 
unsubscribing. After calling Unsubscribe, a second Publish is made, but there's 
no assertion to verify that the event was not received on the unsubscribed 
channel. Consider adding an assertion to verify the channel does not receive 
the event after unsubscription, for example by using a select statement with a 
timeout to confirm no event is received.



##########
metrics/api_test.go:
##########
@@ -0,0 +1,309 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package metrics
+
+import (
+       "testing"
+)
+
+import (
+       "github.com/stretchr/testify/assert"
+)
+
+// mockMetricRegistry is a simple mock implementation of MetricRegistry for 
testing
+type mockMetricRegistry struct {
+       counters   map[string]*mockCounterMetric
+       gauges     map[string]*mockGaugeMetric
+       histograms map[string]*mockObservableMetric
+       summaries  map[string]*mockObservableMetric
+       rts        map[string]*mockObservableMetric
+}
+
+func newMockMetricRegistry() *mockMetricRegistry {
+       return &mockMetricRegistry{
+               counters:   make(map[string]*mockCounterMetric),
+               gauges:     make(map[string]*mockGaugeMetric),
+               histograms: make(map[string]*mockObservableMetric),
+               summaries:  make(map[string]*mockObservableMetric),
+               rts:        make(map[string]*mockObservableMetric),
+       }
+}
+
+func (m *mockMetricRegistry) Counter(id *MetricId) CounterMetric {
+       if c, ok := m.counters[id.Name]; ok {
+               return c
+       }
+       c := &mockCounterMetric{}
+       m.counters[id.Name] = c
+       return c
+}
+
+func (m *mockMetricRegistry) Gauge(id *MetricId) GaugeMetric {
+       if g, ok := m.gauges[id.Name]; ok {
+               return g
+       }
+       g := &mockGaugeMetric{}
+       m.gauges[id.Name] = g
+       return g
+}
+
+func (m *mockMetricRegistry) Histogram(id *MetricId) ObservableMetric {
+       if h, ok := m.histograms[id.Name]; ok {
+               return h
+       }
+       h := &mockObservableMetric{}
+       m.histograms[id.Name] = h
+       return h
+}
+
+func (m *mockMetricRegistry) Summary(id *MetricId) ObservableMetric {
+       if s, ok := m.summaries[id.Name]; ok {
+               return s
+       }
+       s := &mockObservableMetric{}
+       m.summaries[id.Name] = s
+       return s
+}
+
+func (m *mockMetricRegistry) Rt(id *MetricId, opts *RtOpts) ObservableMetric {
+       if rt, ok := m.rts[id.Name]; ok {
+               return rt
+       }
+       rt := &mockObservableMetric{}
+       m.rts[id.Name] = rt
+       return rt
+}
+
+func (m *mockMetricRegistry) Export() {}
+
+type mockCounterMetric struct {
+       value float64
+}
+
+func (m *mockCounterMetric) Inc()          { m.value++ }
+func (m *mockCounterMetric) Add(v float64) { m.value += v }
+
+type mockGaugeMetric struct {
+       value float64
+}
+
+func (m *mockGaugeMetric) Set(v float64) { m.value = v }
+func (m *mockGaugeMetric) Inc()          { m.value++ }
+func (m *mockGaugeMetric) Dec()          { m.value-- }
+func (m *mockGaugeMetric) Add(v float64) { m.value += v }
+func (m *mockGaugeMetric) Sub(v float64) { m.value -= v }
+
+type mockObservableMetric struct {
+       value float64
+}
+
+func (m *mockObservableMetric) Observe(v float64) { m.value = v }
+
+func TestMetricIdTagKeys(t *testing.T) {
+       tests := []struct {
+               name string
+               tags map[string]string
+               want int
+       }{
+               {
+                       name: "empty tags",
+                       tags: map[string]string{},
+                       want: 0,
+               },
+               {
+                       name: "single tag",
+                       tags: map[string]string{"app": "dubbo"},
+                       want: 1,
+               },
+               {
+                       name: "multiple tags",
+                       tags: map[string]string{
+                               "app":     "dubbo",
+                               "version": "1.0.0",
+                               "ip":      "127.0.0.1",
+                       },
+                       want: 3,
+               },
+       }
+
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       m := &MetricId{Name: "test_metric", Tags: tt.tags}
+                       got := m.TagKeys()
+                       assert.Equal(t, tt.want, len(got))
+                       for k := range tt.tags {
+                               assert.Contains(t, got, k)
+                       }
+               })
+       }
+}
+
+func TestBaseCollectorStateCount(t *testing.T) {
+       registry := newMockMetricRegistry()
+       collector := &BaseCollector{R: registry}
+       level := GetApplicationLevel()
+
+       totalKey := NewMetricKey("total", "Total requests")
+       succKey := NewMetricKey("succ", "Success requests")
+       failKey := NewMetricKey("fail", "Failed requests")
+
+       t.Run("success", func(t *testing.T) {
+               collector.StateCount(totalKey, succKey, failKey, level, true)
+
+               total := registry.counters["total"]
+               succ := registry.counters["succ"]
+               fail := registry.counters["fail"]
+
+               assert.NotNil(t, total)
+               assert.NotNil(t, succ)
+               assert.Equal(t, float64(1), total.value)
+               assert.Equal(t, float64(1), succ.value)
+               if fail != nil {
+                       assert.Equal(t, float64(0), fail.value)
+               }
+       })
+
+       t.Run("failure", func(t *testing.T) {
+               collector.StateCount(totalKey, succKey, failKey, level, false)
+
+               total := registry.counters["total"]
+               fail := registry.counters["fail"]
+
+               assert.NotNil(t, total)
+               assert.NotNil(t, fail)
+               assert.Equal(t, float64(2), total.value)
+               assert.Equal(t, float64(1), fail.value)
+       })
+}
+
+func TestDefaultCounterVec(t *testing.T) {
+       registry := newMockMetricRegistry()
+       key := NewMetricKey("test_counter", "Test counter")
+       counterVec := NewCounterVec(registry, key)
+       labels := map[string]string{"app": "dubbo", "version": "1.0.0"}
+
+       t.Run("Inc", func(t *testing.T) {
+               counterVec.Inc(labels)
+               metricId := NewMetricIdByLabels(key, labels)
+               counter := registry.Counter(metricId).(*mockCounterMetric)
+               assert.Equal(t, float64(1), counter.value)
+       })
+
+       t.Run("Add", func(t *testing.T) {
+               counterVec.Add(labels, 5.0)
+               metricId := NewMetricIdByLabels(key, labels)
+               counter := registry.Counter(metricId).(*mockCounterMetric)
+               assert.Equal(t, float64(6), counter.value)
+       })
+}
+
+func TestDefaultGaugeVec(t *testing.T) {
+       registry := newMockMetricRegistry()
+       key := NewMetricKey("test_gauge", "Test gauge")
+       gaugeVec := NewGaugeVec(registry, key)
+       labels := map[string]string{"app": "dubbo", "version": "1.0.0"}
+
+       t.Run("Set", func(t *testing.T) {
+               gaugeVec.Set(labels, 100.0)
+               gauge := registry.Gauge(NewMetricIdByLabels(key, 
labels)).(*mockGaugeMetric)
+               assert.Equal(t, float64(100), gauge.value)
+       })
+
+       t.Run("Inc", func(t *testing.T) {
+               gaugeVec.Inc(labels)
+               gauge := registry.Gauge(NewMetricIdByLabels(key, 
labels)).(*mockGaugeMetric)
+               assert.Equal(t, float64(101), gauge.value)
+       })
+
+       t.Run("Dec", func(t *testing.T) {
+               gaugeVec.Dec(labels)
+               gauge := registry.Gauge(NewMetricIdByLabels(key, 
labels)).(*mockGaugeMetric)
+               assert.Equal(t, float64(100), gauge.value)
+       })
+
+       t.Run("Add", func(t *testing.T) {
+               gaugeVec.Add(labels, 50.0)
+               gauge := registry.Gauge(NewMetricIdByLabels(key, 
labels)).(*mockGaugeMetric)
+               assert.Equal(t, float64(150), gauge.value)
+       })
+
+       t.Run("Sub", func(t *testing.T) {
+               gaugeVec.Sub(labels, 30.0)
+               gauge := registry.Gauge(NewMetricIdByLabels(key, 
labels)).(*mockGaugeMetric)
+               assert.Equal(t, float64(120), gauge.value)
+       })
+}

Review Comment:
   The subtests in TestDefaultGaugeVec share the same registry instance and 
labels map, which creates test interdependence. The "Inc" subtest expects 101 
(assuming "Set" ran first with 100), "Dec" expects 100, "Add" expects 150, and 
"Sub" expects 120. Each subtest depends on the execution and final state of all 
previous subtests. This makes tests fragile and order-dependent. Consider 
creating a fresh registry for each subtest to ensure test isolation and 
independence.



##########
metrics/metadata/collector_test.go:
##########
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package metadata
+
+import (
+       "testing"
+       "time"
+)
+
+import (
+       "github.com/stretchr/testify/assert"
+)
+
+import (
+       "dubbo.apache.org/dubbo-go/v3/common/constant"
+)
+
+func TestMetadataMetricEventType(t *testing.T) {
+       event := &MetadataMetricEvent{
+               Name: MetadataPush,
+               Succ: true,
+       }
+
+       assert.Equal(t, constant.MetricsMetadata, event.Type())
+}
+
+func TestMetadataMetricEventCostMs(t *testing.T) {
+       start := time.Now()
+       time.Sleep(10 * time.Millisecond)
+       end := time.Now()
+
+       event := &MetadataMetricEvent{
+               Name:  MetadataPush,
+               Start: start,
+               End:   end,
+       }
+
+       cost := event.CostMs()
+       assert.Greater(t, cost, 0.0)
+       assert.Less(t, cost, 100.0) // Should be around 10ms
+}

Review Comment:
   This test uses time.Sleep to create a delay for testing timing calculations, 
which can lead to flaky tests in CI/CD environments with variable execution 
speeds. The assertion on line 55 checks that cost is less than 100ms when only 
10ms was slept, which provides a wide margin but could still be fragile. 
Consider using mock time or more deterministic approaches for testing 
time-based calculations, or at least document that this test may be affected by 
system load.



##########
metrics/api_test.go:
##########
@@ -0,0 +1,309 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package metrics
+
+import (
+       "testing"
+)
+
+import (
+       "github.com/stretchr/testify/assert"
+)
+
+// mockMetricRegistry is a simple mock implementation of MetricRegistry for 
testing
+type mockMetricRegistry struct {
+       counters   map[string]*mockCounterMetric
+       gauges     map[string]*mockGaugeMetric
+       histograms map[string]*mockObservableMetric
+       summaries  map[string]*mockObservableMetric
+       rts        map[string]*mockObservableMetric
+}
+
+func newMockMetricRegistry() *mockMetricRegistry {
+       return &mockMetricRegistry{
+               counters:   make(map[string]*mockCounterMetric),
+               gauges:     make(map[string]*mockGaugeMetric),
+               histograms: make(map[string]*mockObservableMetric),
+               summaries:  make(map[string]*mockObservableMetric),
+               rts:        make(map[string]*mockObservableMetric),
+       }
+}
+
+func (m *mockMetricRegistry) Counter(id *MetricId) CounterMetric {
+       if c, ok := m.counters[id.Name]; ok {
+               return c
+       }
+       c := &mockCounterMetric{}
+       m.counters[id.Name] = c
+       return c
+}
+
+func (m *mockMetricRegistry) Gauge(id *MetricId) GaugeMetric {
+       if g, ok := m.gauges[id.Name]; ok {
+               return g
+       }
+       g := &mockGaugeMetric{}
+       m.gauges[id.Name] = g
+       return g
+}
+
+func (m *mockMetricRegistry) Histogram(id *MetricId) ObservableMetric {
+       if h, ok := m.histograms[id.Name]; ok {
+               return h
+       }
+       h := &mockObservableMetric{}
+       m.histograms[id.Name] = h
+       return h
+}
+
+func (m *mockMetricRegistry) Summary(id *MetricId) ObservableMetric {
+       if s, ok := m.summaries[id.Name]; ok {
+               return s
+       }
+       s := &mockObservableMetric{}
+       m.summaries[id.Name] = s
+       return s
+}
+
+func (m *mockMetricRegistry) Rt(id *MetricId, opts *RtOpts) ObservableMetric {
+       if rt, ok := m.rts[id.Name]; ok {
+               return rt
+       }
+       rt := &mockObservableMetric{}
+       m.rts[id.Name] = rt
+       return rt
+}
+
+func (m *mockMetricRegistry) Export() {}
+
+type mockCounterMetric struct {
+       value float64
+}
+
+func (m *mockCounterMetric) Inc()          { m.value++ }
+func (m *mockCounterMetric) Add(v float64) { m.value += v }
+
+type mockGaugeMetric struct {
+       value float64
+}
+
+func (m *mockGaugeMetric) Set(v float64) { m.value = v }
+func (m *mockGaugeMetric) Inc()          { m.value++ }
+func (m *mockGaugeMetric) Dec()          { m.value-- }
+func (m *mockGaugeMetric) Add(v float64) { m.value += v }
+func (m *mockGaugeMetric) Sub(v float64) { m.value -= v }
+
+type mockObservableMetric struct {
+       value float64
+}
+
+func (m *mockObservableMetric) Observe(v float64) { m.value = v }
+
+func TestMetricIdTagKeys(t *testing.T) {
+       tests := []struct {
+               name string
+               tags map[string]string
+               want int
+       }{
+               {
+                       name: "empty tags",
+                       tags: map[string]string{},
+                       want: 0,
+               },
+               {
+                       name: "single tag",
+                       tags: map[string]string{"app": "dubbo"},
+                       want: 1,
+               },
+               {
+                       name: "multiple tags",
+                       tags: map[string]string{
+                               "app":     "dubbo",
+                               "version": "1.0.0",
+                               "ip":      "127.0.0.1",
+                       },
+                       want: 3,
+               },
+       }
+
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       m := &MetricId{Name: "test_metric", Tags: tt.tags}
+                       got := m.TagKeys()
+                       assert.Equal(t, tt.want, len(got))
+                       for k := range tt.tags {
+                               assert.Contains(t, got, k)
+                       }
+               })
+       }
+}
+
+func TestBaseCollectorStateCount(t *testing.T) {
+       registry := newMockMetricRegistry()
+       collector := &BaseCollector{R: registry}
+       level := GetApplicationLevel()
+
+       totalKey := NewMetricKey("total", "Total requests")
+       succKey := NewMetricKey("succ", "Success requests")
+       failKey := NewMetricKey("fail", "Failed requests")
+
+       t.Run("success", func(t *testing.T) {
+               collector.StateCount(totalKey, succKey, failKey, level, true)
+
+               total := registry.counters["total"]
+               succ := registry.counters["succ"]
+               fail := registry.counters["fail"]
+
+               assert.NotNil(t, total)
+               assert.NotNil(t, succ)
+               assert.Equal(t, float64(1), total.value)
+               assert.Equal(t, float64(1), succ.value)
+               if fail != nil {
+                       assert.Equal(t, float64(0), fail.value)
+               }
+       })
+
+       t.Run("failure", func(t *testing.T) {
+               collector.StateCount(totalKey, succKey, failKey, level, false)
+
+               total := registry.counters["total"]
+               fail := registry.counters["fail"]
+
+               assert.NotNil(t, total)
+               assert.NotNil(t, fail)
+               assert.Equal(t, float64(2), total.value)
+               assert.Equal(t, float64(1), fail.value)
+       })
+}
+
+func TestDefaultCounterVec(t *testing.T) {
+       registry := newMockMetricRegistry()
+       key := NewMetricKey("test_counter", "Test counter")
+       counterVec := NewCounterVec(registry, key)
+       labels := map[string]string{"app": "dubbo", "version": "1.0.0"}
+
+       t.Run("Inc", func(t *testing.T) {
+               counterVec.Inc(labels)
+               metricId := NewMetricIdByLabels(key, labels)
+               counter := registry.Counter(metricId).(*mockCounterMetric)
+               assert.Equal(t, float64(1), counter.value)
+       })
+
+       t.Run("Add", func(t *testing.T) {
+               counterVec.Add(labels, 5.0)
+               metricId := NewMetricIdByLabels(key, labels)
+               counter := registry.Counter(metricId).(*mockCounterMetric)
+               assert.Equal(t, float64(6), counter.value)
+       })
+}

Review Comment:
   The subtests in TestDefaultCounterVec share the same registry instance and 
labels map, which means state carries over between subtests. The "Add" subtest 
on line 207 expects a value of 6, which assumes the "Inc" subtest ran first and 
set the value to 1. This creates test interdependence where the order of 
subtest execution matters. Consider creating a fresh registry for each subtest 
to ensure test isolation and independence.



##########
metrics/registry/event_test.go:
##########
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package registry
+
+import (
+       "testing"
+       "time"
+)
+
+import (
+       "github.com/stretchr/testify/assert"
+)
+
+import (
+       "dubbo.apache.org/dubbo-go/v3/common/constant"
+)
+
+func TestRegistryMetricsEventType(t *testing.T) {
+       event := &RegistryMetricsEvent{
+               Name: Reg,
+               Succ: true,
+       }
+
+       assert.Equal(t, constant.MetricsRegistry, event.Type())
+}
+
+func TestRegistryMetricsEventCostMs(t *testing.T) {
+       start := time.Now()
+       time.Sleep(10 * time.Millisecond)
+       end := time.Now()
+
+       event := &RegistryMetricsEvent{
+               Name:  Reg,
+               Start: start,
+               End:   end,
+       }
+
+       cost := event.CostMs()
+       assert.Greater(t, cost, 0.0)
+       assert.Less(t, cost, 100.0)
+}

Review Comment:
   This test uses time.Sleep to create a delay for testing timing calculations, 
which can lead to flaky tests in CI/CD environments with variable execution 
speeds. The assertion on line 55 checks that cost is less than 100ms when only 
10ms was slept, which provides a wide margin but could still be fragile. 
Consider using mock time or more deterministic approaches for testing 
time-based calculations, or at least document that this test may be affected by 
system load.



##########
metrics/bus_test.go:
##########
@@ -44,11 +44,37 @@ func init() {
 }
 
 func TestBusPublish(t *testing.T) {
-       t.Run("testBusPublish", func(t *testing.T) {
-               event := <-mockChan
+       event := <-mockChan
 
-               if event, ok := event.(MockEvent); ok {
-                       assert.Equal(t, event, NewEmptyMockEvent())
-               }
-       })
+       if event, ok := event.(MockEvent); ok {
+               assert.Equal(t, event, NewEmptyMockEvent())

Review Comment:
   The type assertion on line 49 shadows the event variable from line 47, which 
could lead to confusion. The inner event variable (from the type assertion) is 
then compared to a pointer (*MockEvent from NewEmptyMockEvent()), but the 
assertion extracts a non-pointer MockEvent. This comparison will always fail 
since you're comparing a MockEvent value to a *MockEvent pointer. Consider 
either asserting to *MockEvent or adjusting the comparison logic.
   ```suggestion
        if mockEvent, ok := event.(*MockEvent); ok {
                assert.Equal(t, NewEmptyMockEvent(), mockEvent)
   ```



##########
metrics/common_test.go:
##########
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package metrics
+
+import (
+       "testing"
+)
+
+import (
+       "github.com/stretchr/testify/assert"
+)
+
+import (
+       "dubbo.apache.org/dubbo-go/v3/common/constant"
+)
+
+func TestGetApplicationLevel(t *testing.T) {
+       InitAppInfo("test-app", "1.0.0")
+       level := GetApplicationLevel()
+
+       assert.NotNil(t, level)
+       assert.Equal(t, "test-app", level.ApplicationName)
+       assert.Equal(t, "1.0.0", level.Version)
+       assert.NotEmpty(t, level.Ip)
+       assert.NotEmpty(t, level.HostName)
+}
+
+func TestApplicationMetricLevelTags(t *testing.T) {
+       InitAppInfo("test-app", "1.0.0")
+       level := GetApplicationLevel()
+       tags := level.Tags()
+
+       assert.NotNil(t, tags)
+       assert.Equal(t, "test-app", tags[constant.TagApplicationName])
+       assert.Equal(t, "1.0.0", tags[constant.TagApplicationVersion])
+       assert.NotEmpty(t, tags[constant.TagIp])
+       assert.NotEmpty(t, tags[constant.TagHostname])
+       assert.Equal(t, "", tags[constant.TagGitCommitId])
+}
+
+func TestServiceMetricLevelTags(t *testing.T) {
+       InitAppInfo("test-app", "1.0.0")
+       serviceMetric := NewServiceMetric("com.example.Service")
+       tags := serviceMetric.Tags()
+
+       assert.NotNil(t, tags)
+       assert.Equal(t, "test-app", tags[constant.TagApplicationName])
+       assert.Equal(t, "1.0.0", tags[constant.TagApplicationVersion])
+       assert.Equal(t, "com.example.Service", tags[constant.TagInterface])
+       assert.NotEmpty(t, tags[constant.TagIp])
+       assert.NotEmpty(t, tags[constant.TagHostname])
+}
+
+func TestMethodMetricLevelTags(t *testing.T) {
+       InitAppInfo("test-app", "1.0.0")
+       serviceMetric := NewServiceMetric("com.example.Service")
+       methodLevel := MethodMetricLevel{
+               ServiceMetricLevel: serviceMetric,
+               Method:             "TestMethod",
+               Group:              "test-group",
+               Version:            "1.0.0",
+       }
+
+       tags := methodLevel.Tags()
+
+       assert.NotNil(t, tags)
+       assert.Equal(t, "test-app", tags[constant.TagApplicationName])
+       assert.Equal(t, "1.0.0", tags[constant.TagApplicationVersion])
+       assert.Equal(t, "com.example.Service", tags[constant.TagInterface])
+       assert.Equal(t, "TestMethod", tags[constant.TagMethod])
+       assert.Equal(t, "test-group", tags[constant.TagGroup])
+       assert.Equal(t, "1.0.0", tags[constant.TagVersion])
+}
+
+func TestConfigCenterLevelTags(t *testing.T) {
+       InitAppInfo("test-app", "1.0.0")
+       level := NewConfigCenterLevel("test-key", "test-group", "nacos", 
"added")
+       tags := level.Tags()
+
+       assert.NotNil(t, tags)
+       assert.Equal(t, "test-app", tags[constant.TagApplicationName])
+       assert.Equal(t, "test-key", tags[constant.TagKey])
+       assert.Equal(t, "test-group", tags[constant.TagGroup])
+       assert.Equal(t, "nacos", tags[constant.TagConfigCenter])
+       assert.Equal(t, "added", tags[constant.TagChangeType])
+       assert.NotEmpty(t, tags[constant.TagIp])
+       assert.NotEmpty(t, tags[constant.TagHostname])
+}

Review Comment:
   Each test function calls InitAppInfo with the same values ("test-app", 
"1.0.0"). If InitAppInfo modifies global state or has side effects, this could 
lead to test interference when tests run in parallel. Consider calling 
InitAppInfo once in a TestMain function or in an init function, or ensure that 
each test properly isolates its state if tests are meant to run independently.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to