From 742e035a8a1c3d7c13f8476b60ad12da7456851e Mon Sep 17 00:00:00 2001
From: namelessssssssssss
<100946116+namelessssssssssss@users.noreply.github.com>
Date: Wed, 19 Apr 2023 12:41:53 +0800
Subject: [PATCH] Add metrics provider/consumer uts (#12120)
* Provide uts in metrics-api
* Provide uts in metrics-default
* Provide uts in metrics-default
* Update pom.xml
* Update pom.xml
* Remove 'import *'
* Remove 'import *'
* Merge remote branch
* Add license
* Update DefaultDubboClientObservationConventionTest.java
* Merge remote branch
* Add ut for METRIC_QPS
* Add ut for Provider/Consumer Metrics
* Add ut for Provider/Consumer Metrics
* Add ut for Provider/Consumer Metrics
* Update pom.xml for test
* Add test for p95 & p99
* Add test for p95 & p99
* Update pom.xml
* Update import
* Remove unused todo
* Update test
* Remove unused import
* Remove unnecessary test unit
* Fix codestyle problems
* Fix codestyle problems
---
.../dubbo/common/utils/ReflectionUtils.java | 101 ++++++++++
...tDubboClientObservationConventionTest.java | 71 +++++++
...tDubboServerObservationConventionTest.java | 69 +++++++
.../utils/ObservationConventionUtils.java | 48 +++++
dubbo-metrics/dubbo-metrics-default/pom.xml | 1 -
.../metrics/DefaultMetricsServiceTest.java | 84 ++++++++
.../AggregateMetricsCollectorTest.java | 151 ++++++++++++++-
.../ConfigCenterMetricsCollectorTest.java | 7 -
.../sample/ThreadPoolMetricsSamplerTest.java | 180 ++++++++++++++++++
.../metrics/sampler/MethodMetricsTest.java | 132 +++++++++++++
.../collector/RegistryStatCompositeTest.java | 46 +++++
11 files changed, 875 insertions(+), 15 deletions(-)
create mode 100644 dubbo-common/src/main/java/org/apache/dubbo/common/utils/ReflectionUtils.java
create mode 100644 dubbo-metrics/dubbo-metrics-api/src/test/java/org/apache/dubbo/metrics/observation/DefaultDubboClientObservationConventionTest.java
create mode 100644 dubbo-metrics/dubbo-metrics-api/src/test/java/org/apache/dubbo/metrics/observation/DefaultDubboServerObservationConventionTest.java
create mode 100644 dubbo-metrics/dubbo-metrics-api/src/test/java/org/apache/dubbo/metrics/observation/utils/ObservationConventionUtils.java
create mode 100644 dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/DefaultMetricsServiceTest.java
create mode 100644 dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/sample/ThreadPoolMetricsSamplerTest.java
create mode 100644 dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/sampler/MethodMetricsTest.java
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ReflectionUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ReflectionUtils.java
new file mode 100644
index 0000000000..b659dcb97b
--- /dev/null
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/ReflectionUtils.java
@@ -0,0 +1,101 @@
+/*
+ * 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 org.apache.dubbo.common.utils;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+
+/**
+ * A utility class that provides methods for accessing and manipulating private fields and methods of an object.
+ * This is useful for white-box testing, where the internal workings of a class need to be tested directly.
+ *
+ * Note: Usage of this class should be limited to testing purposes only, as it violates the encapsulation principle.
+ */
+public class ReflectionUtils {
+
+ private ReflectionUtils(){}
+
+ /**
+ * Retrieves the value of the specified field from the given object.
+ *
+ * @param source The object from which to retrieve the field value.
+ * @param fieldName The name of the field to retrieve.
+ * @return The value of the specified field in the given object.
+ * @throws RuntimeException If the specified field does not exist.
+ */
+ public static Object getField(Object source, String fieldName) {
+ try {
+ Field f = source.getClass().getDeclaredField(fieldName);
+ f.setAccessible(true);
+ return f.get(source);
+ } catch (Exception e) {
+ throw new ReflectionException(e);
+ }
+ }
+
+ /**
+ * Invokes the specified method on the given object with the provided parameters.
+ *
+ * @param source The object on which to invoke the method.
+ * @param methodName The name of the method to invoke.
+ * @param params The parameters to pass to the method.
+ * @return The result of invoking the specified method on the given object.
+ */
+ public static Object invoke(Object source, String methodName, Object... params) {
+ try {
+ Class>[] classes = Arrays.stream(params)
+ .map(param -> param != null ? param.getClass() : null)
+ .toArray(Class>[]::new);
+
+ for (Method method : source.getClass().getDeclaredMethods()) {
+ if (method.getName().equals(methodName) && matchParameters(method.getParameterTypes(), classes)) {
+ method.setAccessible(true);
+ return method.invoke(source, params);
+ }
+ }
+ throw new NoSuchMethodException("No method found with the specified name and parameter types");
+ } catch (Exception e) {
+ throw new ReflectionException(e);
+ }
+ }
+
+ private static boolean matchParameters(Class>[] methodParamTypes, Class>[] givenParamTypes) {
+ if (methodParamTypes.length != givenParamTypes.length) {
+ return false;
+ }
+
+ for (int i = 0; i < methodParamTypes.length; i++) {
+ if (givenParamTypes[i] == null) {
+ if (methodParamTypes[i].isPrimitive()) {
+ return false;
+ }
+ } else if (!methodParamTypes[i].isAssignableFrom(givenParamTypes[i])) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public static class ReflectionException extends RuntimeException{
+ public ReflectionException(Throwable cause) {
+ super(cause);
+ }
+ }
+
+}
diff --git a/dubbo-metrics/dubbo-metrics-api/src/test/java/org/apache/dubbo/metrics/observation/DefaultDubboClientObservationConventionTest.java b/dubbo-metrics/dubbo-metrics-api/src/test/java/org/apache/dubbo/metrics/observation/DefaultDubboClientObservationConventionTest.java
new file mode 100644
index 0000000000..8b91e2531d
--- /dev/null
+++ b/dubbo-metrics/dubbo-metrics-api/src/test/java/org/apache/dubbo/metrics/observation/DefaultDubboClientObservationConventionTest.java
@@ -0,0 +1,71 @@
+/*
+ * 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 org.apache.dubbo.metrics.observation;
+
+import io.micrometer.common.KeyValues;
+import org.apache.dubbo.metrics.observation.utils.ObservationConventionUtils;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.RpcInvocation;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+
+public class DefaultDubboClientObservationConventionTest {
+
+ static DubboClientObservationConvention dubboClientObservationConvention = DefaultDubboClientObservationConvention.getInstance();
+
+ @Test
+ void testGetName() {
+ Assertions.assertEquals("rpc.client.duration", dubboClientObservationConvention.getName());
+ }
+
+ @Test
+ void testGetLowCardinalityKeyValues() throws NoSuchFieldException, IllegalAccessException {
+ RpcInvocation invocation = new RpcInvocation();
+ invocation.setMethodName("testMethod");
+ invocation.setAttachment("interface", "com.example.TestService");
+ invocation.setTargetServiceUniqueName("targetServiceName1");
+
+ Invoker> invoker = ObservationConventionUtils.getMockInvokerWithUrl();
+ invocation.setInvoker(invoker);
+
+ DubboClientContext context = new DubboClientContext(invoker, invocation);
+
+ KeyValues keyValues = dubboClientObservationConvention.getLowCardinalityKeyValues(context);
+
+ Assertions.assertEquals("testMethod", ObservationConventionUtils.getValueForKey(keyValues, "rpc.method"));
+ Assertions.assertEquals("targetServiceName1", ObservationConventionUtils.getValueForKey(keyValues, "rpc.service"));
+ Assertions.assertEquals("apache_dubbo", ObservationConventionUtils.getValueForKey(keyValues, "rpc.system"));
+ }
+
+ @Test
+ void testGetContextualName() {
+ RpcInvocation invocation = new RpcInvocation();
+ Invoker> invoker = ObservationConventionUtils.getMockInvokerWithUrl();
+ invocation.setMethodName("testMethod");
+ invocation.setServiceName("com.example.TestService");
+
+ DubboClientContext context = new DubboClientContext(invoker, invocation);
+
+ DefaultDubboClientObservationConvention convention = new DefaultDubboClientObservationConvention();
+
+ String contextualName = convention.getContextualName(context);
+ Assertions.assertEquals("com.example.TestService/testMethod", contextualName);
+ }
+
+
+}
diff --git a/dubbo-metrics/dubbo-metrics-api/src/test/java/org/apache/dubbo/metrics/observation/DefaultDubboServerObservationConventionTest.java b/dubbo-metrics/dubbo-metrics-api/src/test/java/org/apache/dubbo/metrics/observation/DefaultDubboServerObservationConventionTest.java
new file mode 100644
index 0000000000..faa49457e7
--- /dev/null
+++ b/dubbo-metrics/dubbo-metrics-api/src/test/java/org/apache/dubbo/metrics/observation/DefaultDubboServerObservationConventionTest.java
@@ -0,0 +1,69 @@
+/*
+ * 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 org.apache.dubbo.metrics.observation;
+
+import io.micrometer.common.KeyValues;
+import org.apache.dubbo.metrics.observation.utils.ObservationConventionUtils;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.RpcInvocation;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+@SuppressWarnings("deprecation")
+public class DefaultDubboServerObservationConventionTest {
+
+ static DubboServerObservationConvention dubboServerObservationConvention = DefaultDubboServerObservationConvention.getInstance();
+
+ @Test
+ void testGetName() {
+ Assertions.assertEquals("rpc.server.duration", dubboServerObservationConvention.getName());
+ }
+
+ @Test
+ void testGetLowCardinalityKeyValues() throws NoSuchFieldException, IllegalAccessException {
+ RpcInvocation invocation = new RpcInvocation();
+ invocation.setMethodName("testMethod");
+ invocation.setAttachment("interface", "com.example.TestService");
+ invocation.setTargetServiceUniqueName("targetServiceName1");
+
+ Invoker> invoker = ObservationConventionUtils.getMockInvokerWithUrl();
+ invocation.setInvoker(invoker);
+
+ DubboServerContext context = new DubboServerContext(invoker, invocation);
+
+ KeyValues keyValues = dubboServerObservationConvention.getLowCardinalityKeyValues(context);
+
+ Assertions.assertEquals("testMethod", ObservationConventionUtils.getValueForKey(keyValues, "rpc.method"));
+ Assertions.assertEquals("targetServiceName1", ObservationConventionUtils.getValueForKey(keyValues, "rpc.service"));
+ Assertions.assertEquals("apache_dubbo", ObservationConventionUtils.getValueForKey(keyValues, "rpc.system"));
+ }
+
+ @Test
+ void testGetContextualName() {
+ RpcInvocation invocation = new RpcInvocation();
+ Invoker> invoker = ObservationConventionUtils.getMockInvokerWithUrl();
+ invocation.setMethodName("testMethod");
+ invocation.setServiceName("com.example.TestService");
+
+ DubboClientContext context = new DubboClientContext(invoker, invocation);
+
+ DefaultDubboClientObservationConvention convention = new DefaultDubboClientObservationConvention();
+
+ String contextualName = convention.getContextualName(context);
+ Assertions.assertEquals("com.example.TestService/testMethod", contextualName);
+ }
+}
diff --git a/dubbo-metrics/dubbo-metrics-api/src/test/java/org/apache/dubbo/metrics/observation/utils/ObservationConventionUtils.java b/dubbo-metrics/dubbo-metrics-api/src/test/java/org/apache/dubbo/metrics/observation/utils/ObservationConventionUtils.java
new file mode 100644
index 0000000000..4bf2abfa1e
--- /dev/null
+++ b/dubbo-metrics/dubbo-metrics-api/src/test/java/org/apache/dubbo/metrics/observation/utils/ObservationConventionUtils.java
@@ -0,0 +1,48 @@
+/*
+ * 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 org.apache.dubbo.metrics.observation.utils;
+
+import io.micrometer.common.KeyValue;
+import io.micrometer.common.KeyValues;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.rpc.Invoker;
+import org.mockito.Mockito;
+
+import java.lang.reflect.Field;
+
+public class ObservationConventionUtils {
+
+
+ public static Invoker> getMockInvokerWithUrl(){
+ URL url = URL.valueOf("dubbo://127.0.0.1:12345/com.example.TestService?anyhost=true&application=test&category=providers&dubbo=2.0.2&generic=false&interface=com.example.TestService&methods=testMethod&pid=26716&side=provider×tamp=1633863896653");
+ Invoker> invoker = Mockito.mock(Invoker.class);
+ Mockito.when(invoker.getUrl()).thenReturn(url);
+ return invoker;
+ }
+
+ public static String getValueForKey(KeyValues keyValues, Object key) throws NoSuchFieldException, IllegalAccessException {
+ Field f = KeyValues.class.getDeclaredField("keyValues");
+ f.setAccessible(true);
+ KeyValue[] kv = (KeyValue[]) f.get(keyValues);
+ for (KeyValue keyValue : kv) {
+ if (keyValue.getKey().equals(key)) {
+ return keyValue.getValue();
+ }
+ }
+ return null;
+ }
+}
diff --git a/dubbo-metrics/dubbo-metrics-default/pom.xml b/dubbo-metrics/dubbo-metrics-default/pom.xml
index 87ec6a3b9b..71be413c6a 100644
--- a/dubbo-metrics/dubbo-metrics-default/pom.xml
+++ b/dubbo-metrics/dubbo-metrics-default/pom.xml
@@ -46,6 +46,5 @@
micrometer-tracing-integration-test
test
-
diff --git a/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/DefaultMetricsServiceTest.java b/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/DefaultMetricsServiceTest.java
new file mode 100644
index 0000000000..5bb8c014b7
--- /dev/null
+++ b/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/DefaultMetricsServiceTest.java
@@ -0,0 +1,84 @@
+/*
+ * 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 org.apache.dubbo.metrics;
+
+import org.apache.dubbo.common.beans.factory.ScopeBeanFactory;
+import org.apache.dubbo.metrics.collector.MetricsCollector;
+import org.apache.dubbo.metrics.model.MetricsCategory;
+import org.apache.dubbo.metrics.model.sample.GaugeMetricSample;
+import org.apache.dubbo.metrics.model.sample.MetricSample;
+import org.apache.dubbo.metrics.service.DefaultMetricsService;
+import org.apache.dubbo.metrics.service.MetricsEntity;
+import org.apache.dubbo.rpc.model.ApplicationModel;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import static org.mockito.Mockito.when;
+
+@SuppressWarnings("rawtypes")
+public class DefaultMetricsServiceTest {
+
+ private MetricsCollector metricsCollector;
+
+ private DefaultMetricsService defaultMetricsService;
+
+
+ @BeforeEach
+ public void setUp() {
+ ApplicationModel applicationModel = Mockito.mock(ApplicationModel.class);
+ ScopeBeanFactory beanFactory = Mockito.mock(ScopeBeanFactory.class);
+ metricsCollector = Mockito.mock(MetricsCollector.class);
+
+ when(applicationModel.getBeanFactory()).thenReturn(beanFactory);
+ when(beanFactory.getBeansOfType(MetricsCollector.class)).thenReturn(Collections.singletonList(metricsCollector));
+
+ defaultMetricsService = new DefaultMetricsService(applicationModel);
+ }
+
+ @Test
+ public void testGetMetricsByCategories() {
+ MetricSample sample = new GaugeMetricSample<>(
+ "testMetric",
+ "testDescription",
+ null,
+ MetricsCategory.REQUESTS,
+ 42,
+ value -> 42.0
+ );
+ when(metricsCollector.collect()).thenReturn(Collections.singletonList(sample));
+ List categories = Collections.singletonList(MetricsCategory.REQUESTS);
+
+ Map> result = defaultMetricsService.getMetricsByCategories(categories);
+
+ Assertions.assertNotNull(result);
+ Assertions.assertEquals(1, result.size());
+ List entities = result.get(MetricsCategory.REQUESTS);
+ Assertions.assertNotNull(entities);
+ Assertions.assertEquals(1, entities.size());
+
+ MetricsEntity entity = entities.get(0);
+ Assertions.assertEquals("testMetric", entity.getName());
+ Assertions.assertEquals(42.0, entity.getValue());
+ Assertions.assertEquals(MetricsCategory.REQUESTS, entity.getCategory());
+ }
+}
diff --git a/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/AggregateMetricsCollectorTest.java b/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/AggregateMetricsCollectorTest.java
index f2275125b1..7bc56579b6 100644
--- a/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/AggregateMetricsCollectorTest.java
+++ b/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/AggregateMetricsCollectorTest.java
@@ -18,40 +18,53 @@
package org.apache.dubbo.metrics.collector;
import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.beans.factory.ScopeBeanFactory;
import org.apache.dubbo.common.constants.CommonConstants;
+import org.apache.dubbo.common.utils.ReflectionUtils;
import org.apache.dubbo.config.ApplicationConfig;
+
import org.apache.dubbo.config.MetricsConfig;
+
+import org.apache.dubbo.config.context.ConfigManager;
import org.apache.dubbo.config.nested.AggregationConfig;
import org.apache.dubbo.metrics.TestMetricsInvoker;
+import org.apache.dubbo.metrics.aggregate.TimeWindowCounter;
import org.apache.dubbo.metrics.collector.sample.MethodMetricsSampler;
import org.apache.dubbo.metrics.event.MetricsEvent;
+import org.apache.dubbo.metrics.event.RTEvent;
+import org.apache.dubbo.metrics.model.MethodMetric;
import org.apache.dubbo.metrics.model.key.MetricsKey;
import org.apache.dubbo.metrics.model.sample.GaugeMetricSample;
import org.apache.dubbo.metrics.model.sample.MetricSample;
import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.rpc.RpcInvocation;
import org.apache.dubbo.rpc.model.ApplicationModel;
-
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
+import java.util.Collections;
+import java.util.concurrent.ConcurrentHashMap;
+
import java.util.stream.Collectors;
-import static org.apache.dubbo.common.constants.CommonConstants.*;
-import static org.apache.dubbo.common.constants.MetricsConstants.TAG_GROUP_KEY;
-import static org.apache.dubbo.common.constants.MetricsConstants.TAG_INTERFACE_KEY;
-import static org.apache.dubbo.common.constants.MetricsConstants.TAG_METHOD_KEY;
-import static org.apache.dubbo.common.constants.MetricsConstants.TAG_VERSION_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
+import static org.apache.dubbo.common.constants.MetricsConstants.*;
+import static org.apache.dubbo.metrics.model.MetricsCategory.QPS;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.spy;
class AggregateMetricsCollectorTest {
private ApplicationModel applicationModel;
private DefaultMetricsCollector defaultCollector;
-
private String interfaceName;
private String methodName;
private String group;
@@ -59,6 +72,37 @@ class AggregateMetricsCollectorTest {
private RpcInvocation invocation;
private String side;
+ public static MethodMetric getTestMethodMetric() {
+
+ MethodMetric methodMetric = new MethodMetric();
+ methodMetric.setApplicationName("TestApp");
+ methodMetric.setInterfaceName("TestInterface");
+ methodMetric.setMethodName("TestMethod");
+ methodMetric.setGroup("TestGroup");
+ methodMetric.setVersion("1.0.0");
+ methodMetric.setSide("PROVIDER");
+
+ return methodMetric;
+ }
+
+ public static AggregateMetricsCollector getTestCollector() {
+
+ ApplicationModel applicationModel = mock(ApplicationModel.class);
+ ConfigManager configManager = new ConfigManager(applicationModel);
+ MetricsConfig metricsConfig = spy(new MetricsConfig());
+
+ configManager.setMetrics(metricsConfig);
+
+ when(metricsConfig.getAggregation()).thenReturn(new AggregationConfig());
+ when(applicationModel.getApplicationConfigManager()).thenReturn(configManager);
+
+ ScopeBeanFactory beanFactory = mock(ScopeBeanFactory.class);
+ when(beanFactory.getBean(DefaultMetricsCollector.class)).thenReturn(new DefaultMetricsCollector());
+ when(applicationModel.getBeanFactory()).thenReturn(beanFactory);
+
+ return new AggregateMetricsCollector(applicationModel);
+ }
+
@BeforeEach
public void setup() {
ApplicationConfig config = new ApplicationConfig();
@@ -167,4 +211,97 @@ class AggregateMetricsCollectorTest {
Assertions.assertTrue(sampleMap.containsKey(MetricsKey.METRIC_RT_P99.getNameByType(side)));
Assertions.assertTrue(sampleMap.containsKey(MetricsKey.METRIC_RT_P95.getNameByType(side)));
}
+
+ @Test
+ public void testQPS() {
+ ApplicationModel applicationModel = mock(ApplicationModel.class);
+ ConfigManager configManager = mock(ConfigManager.class);
+ MetricsConfig metricsConfig = mock(MetricsConfig.class);
+ ScopeBeanFactory beanFactory = mock(ScopeBeanFactory.class);
+ AggregationConfig aggregationConfig = mock(AggregationConfig.class);
+
+ when(applicationModel.getApplicationConfigManager()).thenReturn(configManager);
+ when(applicationModel.getBeanFactory()).thenReturn(beanFactory);
+ when(beanFactory.getBean(DefaultMetricsCollector.class)).thenReturn(new DefaultMetricsCollector());
+ when(configManager.getMetrics()).thenReturn(Optional.of(metricsConfig));
+ when(metricsConfig.getAggregation()).thenReturn(aggregationConfig);
+ when(aggregationConfig.getEnabled()).thenReturn(Boolean.TRUE);
+
+ AggregateMetricsCollector collector = new AggregateMetricsCollector(applicationModel);
+
+ MethodMetric methodMetric = getTestMethodMetric();
+
+ TimeWindowCounter qpsCounter = new TimeWindowCounter(10, 120);
+
+ for (int i = 0; i < 10000; i++) {
+ qpsCounter.increment();
+ }
+
+ @SuppressWarnings("unchecked")
+ ConcurrentHashMap qps = (ConcurrentHashMap) ReflectionUtils.getField(collector, "qps");
+ qps.put(methodMetric, qpsCounter);
+
+ List collectedQPS = new ArrayList<>();
+ ReflectionUtils.invoke(collector, "collectQPS", collectedQPS);
+
+ Assertions.assertFalse(collectedQPS.isEmpty());
+ Assertions.assertEquals(1, collectedQPS.size());
+
+ MetricSample sample = collectedQPS.get(0);
+ Assertions.assertEquals(MetricsKey.METRIC_QPS.getNameByType("PROVIDER"), sample.getName());
+ Assertions.assertEquals(MetricsKey.METRIC_QPS.getDescription(), sample.getDescription());
+
+ Assertions.assertEquals(QPS, sample.getCategory());
+ Assertions.assertEquals(10000, ((TimeWindowCounter) ((GaugeMetricSample>) sample).getValue()).get());
+ }
+
+ @Test
+ void testP95AndP99() throws InterruptedException {
+ AggregateMetricsCollector collector = getTestCollector();
+ MethodMetric methodMetric = getTestMethodMetric();
+
+ List requestTimes = new ArrayList<>(10000);
+
+ for (int i = 0; i < 300; i++) {
+ requestTimes.add(1000 * Math.random());
+ }
+
+ Collections.sort(requestTimes);
+ double p95Index = 0.95 * (requestTimes.size() - 1);
+ double p99Index = 0.99 * (requestTimes.size() - 1);
+
+ double manualP95 = requestTimes.get((int) Math.round(p95Index));
+ double manualP99 = requestTimes.get((int) Math.round(p99Index));
+
+ for (Double requestTime : requestTimes) {
+ collector.onEvent(new RTEvent(applicationModel, methodMetric, requestTime.longValue()));
+ }
+ Thread.sleep(4000L);
+
+ List samples = collector.collect();
+
+ GaugeMetricSample> p95Sample = samples.stream()
+ .filter(sample -> sample.getName().endsWith("p95"))
+ .map(sample -> (GaugeMetricSample>) sample)
+ .findFirst()
+ .orElse(null);
+
+ GaugeMetricSample> p99Sample = samples.stream()
+ .filter(sample -> sample.getName().endsWith("p99"))
+ .map(sample -> (GaugeMetricSample>) sample)
+ .findFirst()
+ .orElse(null);
+
+ Assertions.assertNotNull(p95Sample);
+ Assertions.assertNotNull(p99Sample);
+
+ double p95 = p95Sample.applyAsDouble();
+ double p99 = p99Sample.applyAsDouble();
+
+ //An error of less than 5% is allowed
+ Assertions.assertTrue(Math.abs(1 - p95 / manualP95) < 0.05);
+ Assertions.assertTrue(Math.abs(1 - p99 / manualP99) < 0.05);
+ }
+
}
+
diff --git a/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/ConfigCenterMetricsCollectorTest.java b/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/ConfigCenterMetricsCollectorTest.java
index e234279339..544dbe7f0c 100644
--- a/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/ConfigCenterMetricsCollectorTest.java
+++ b/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/ConfigCenterMetricsCollectorTest.java
@@ -20,7 +20,6 @@ package org.apache.dubbo.metrics.collector;
import org.apache.dubbo.common.config.configcenter.ConfigChangeType;
import org.apache.dubbo.common.config.configcenter.ConfigChangedEvent;
import org.apache.dubbo.config.ApplicationConfig;
-import org.apache.dubbo.metrics.model.ConfigCenterMetric;
import org.apache.dubbo.metrics.model.sample.GaugeMetricSample;
import org.apache.dubbo.metrics.model.sample.MetricSample;
import org.apache.dubbo.rpc.model.ApplicationModel;
@@ -32,14 +31,8 @@ import org.junit.jupiter.api.Test;
import java.util.List;
import java.util.Map;
-import java.util.function.Supplier;
import static org.apache.dubbo.common.constants.MetricsConstants.TAG_APPLICATION_NAME;
-import static org.apache.dubbo.common.constants.MetricsConstants.TAG_GROUP_KEY;
-import static org.apache.dubbo.common.constants.MetricsConstants.TAG_INTERFACE_KEY;
-import static org.apache.dubbo.common.constants.MetricsConstants.TAG_METHOD_KEY;
-import static org.apache.dubbo.common.constants.MetricsConstants.TAG_VERSION_KEY;
-import static org.junit.jupiter.api.Assertions.*;
class ConfigCenterMetricsCollectorTest {
diff --git a/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/sample/ThreadPoolMetricsSamplerTest.java b/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/sample/ThreadPoolMetricsSamplerTest.java
new file mode 100644
index 0000000000..4b336d91f6
--- /dev/null
+++ b/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/collector/sample/ThreadPoolMetricsSamplerTest.java
@@ -0,0 +1,180 @@
+/*
+ * 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 org.apache.dubbo.metrics.collector.sample;
+
+import org.apache.dubbo.common.beans.factory.ScopeBeanFactory;
+import org.apache.dubbo.common.extension.ExtensionLoader;
+import org.apache.dubbo.common.store.DataStore;
+import org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository;
+import org.apache.dubbo.metrics.collector.DefaultMetricsCollector;
+import org.apache.dubbo.metrics.model.ThreadPoolMetric;
+import org.apache.dubbo.metrics.model.sample.GaugeMetricSample;
+import org.apache.dubbo.metrics.model.sample.MetricSample;
+import org.apache.dubbo.rpc.model.ApplicationModel;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadPoolExecutor;
+
+import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SHARED_EXECUTOR_SERVICE_COMPONENT_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.EXECUTOR_SERVICE_COMPONENT_KEY;
+import static org.mockito.Mockito.when;
+
+@SuppressWarnings("all")
+public class ThreadPoolMetricsSamplerTest {
+
+ ThreadPoolMetricsSampler sampler;
+
+ @BeforeEach
+ void setUp() {
+ DefaultMetricsCollector collector = new DefaultMetricsCollector();
+ sampler = new ThreadPoolMetricsSampler(collector);
+ }
+
+ @Test
+ void testSample() {
+
+ ExecutorService executorService = java.util.concurrent.Executors.newFixedThreadPool(5);
+ ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executorService;
+ sampler.addExecutors("testPool", executorService);
+
+ List metricSamples = sampler.sample();
+
+ Assertions.assertEquals(6, metricSamples.size());
+
+ boolean coreSizeFound = false;
+ boolean maxSizeFound = false;
+ boolean activeSizeFound = false;
+ boolean threadCountFound = false;
+ boolean queueSizeFound = false;
+ boolean largestSizeFound = false;
+
+ for (MetricSample sample : metricSamples) {
+ ThreadPoolMetric threadPoolMetric = ((ThreadPoolMetric) ((GaugeMetricSample) sample).getValue());
+ switch (sample.getName()) {
+ case "dubbo.thread.pool.core.size":
+ coreSizeFound = true;
+ Assertions.assertEquals(5, threadPoolMetric.getCorePoolSize());
+ break;
+ case "dubbo.thread.pool.largest.size":
+ largestSizeFound = true;
+ Assertions.assertEquals(0, threadPoolMetric.getLargestPoolSize());
+ break;
+ case "dubbo.thread.pool.max.size":
+ maxSizeFound = true;
+ Assertions.assertEquals(5, threadPoolMetric.getMaximumPoolSize());
+ break;
+ case "dubbo.thread.pool.active.size":
+ activeSizeFound = true;
+ Assertions.assertEquals(0, threadPoolMetric.getActiveCount());
+ break;
+ case "dubbo.thread.pool.thread.count":
+ threadCountFound = true;
+ Assertions.assertEquals(0, threadPoolMetric.getPoolSize());
+ break;
+ case "dubbo.thread.pool.queue.size":
+ queueSizeFound = true;
+ Assertions.assertEquals(0, threadPoolMetric.getQueueSize());
+ break;
+ }
+ }
+
+ Assertions.assertTrue(coreSizeFound);
+ Assertions.assertTrue(maxSizeFound);
+ Assertions.assertTrue(activeSizeFound);
+ Assertions.assertTrue(threadCountFound);
+ Assertions.assertTrue(queueSizeFound);
+ Assertions.assertTrue(largestSizeFound);
+
+ executorService.shutdown();
+ }
+
+ private DefaultMetricsCollector collector;
+
+ private ThreadPoolMetricsSampler sampler2;
+
+ @Mock
+ private ApplicationModel applicationModel;
+
+ @Mock
+ ScopeBeanFactory scopeBeanFactory;
+
+ @Mock
+ private DataStore dataStore;
+
+ @Mock
+ private FrameworkExecutorRepository frameworkExecutorRepository;
+
+ @Mock
+ private ExtensionLoader extensionLoader;
+
+ @BeforeEach
+ public void setUp2() {
+ MockitoAnnotations.openMocks(this);
+
+ collector = new DefaultMetricsCollector();
+ sampler2 = new ThreadPoolMetricsSampler(collector);
+
+ when(scopeBeanFactory.getBean(FrameworkExecutorRepository.class)).thenReturn(new FrameworkExecutorRepository());
+
+ collector.collectApplication(applicationModel);
+ when(applicationModel.getBeanFactory()).thenReturn(scopeBeanFactory);
+ when(applicationModel.getExtensionLoader(DataStore.class)).thenReturn(extensionLoader);
+ when(extensionLoader.getDefaultExtension()).thenReturn(dataStore);
+ }
+
+ @Test
+ public void testRegistryDefaultSampleThreadPoolExecutor() throws NoSuchFieldException, IllegalAccessException {
+
+ Map serverExecutors = new HashMap<>();
+ Map clientExecutors = new HashMap<>();
+
+ ExecutorService serverExecutor = Executors.newFixedThreadPool(5);
+ ExecutorService clientExecutor = Executors.newFixedThreadPool(5);
+
+ serverExecutors.put("server1", serverExecutor);
+ clientExecutors.put("client1", clientExecutor);
+
+ when(dataStore.get(EXECUTOR_SERVICE_COMPONENT_KEY)).thenReturn(serverExecutors);
+ when(dataStore.get(CONSUMER_SHARED_EXECUTOR_SERVICE_COMPONENT_KEY)).thenReturn(clientExecutors);
+
+ when(frameworkExecutorRepository.getSharedExecutor()).thenReturn(Executors.newFixedThreadPool(5));
+
+ sampler2.registryDefaultSampleThreadPoolExecutor();
+
+ Field f = ThreadPoolMetricsSampler.class.getDeclaredField("sampleThreadPoolExecutor");
+ f.setAccessible(true);
+ Map executors = (Map) f.get(sampler2);
+
+ Assertions.assertEquals(3, executors.size());
+ Assertions.assertTrue(executors.containsKey("DubboServerHandler-server1"));
+ Assertions.assertTrue(executors.containsKey("DubboClientHandler-client1"));
+ Assertions.assertTrue(executors.containsKey("sharedExecutor"));
+
+ serverExecutor.shutdown();
+ clientExecutor.shutdown();
+ }
+}
diff --git a/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/sampler/MethodMetricsTest.java b/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/sampler/MethodMetricsTest.java
new file mode 100644
index 0000000000..9e4eff6941
--- /dev/null
+++ b/dubbo-metrics/dubbo-metrics-default/src/test/java/org/apache/dubbo/metrics/sampler/MethodMetricsTest.java
@@ -0,0 +1,132 @@
+/*
+ * 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 org.apache.dubbo.metrics.sampler;
+
+import org.apache.dubbo.metrics.collector.DefaultMetricsCollector;
+import org.apache.dubbo.metrics.collector.sample.MethodMetricsSampler;
+import org.apache.dubbo.metrics.event.MetricsEvent;
+import org.apache.dubbo.metrics.model.key.MetricsKey;
+import org.apache.dubbo.metrics.model.sample.CounterMetricSample;
+import org.apache.dubbo.metrics.model.sample.GaugeMetricSample;
+import org.apache.dubbo.metrics.model.sample.MetricSample;
+import org.apache.dubbo.metrics.observation.MockInvocation;
+import org.apache.dubbo.rpc.Invocation;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+import java.util.concurrent.atomic.AtomicLong;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+public class MethodMetricsTest {
+
+ private DefaultMetricsCollector collector;
+ private MethodMetricsSampler sampler;
+
+ private Invocation invocation;
+
+ @BeforeEach
+ public void setUp() {
+ collector = new DefaultMetricsCollector();
+ sampler = new MethodMetricsSampler(collector);
+ invocation = spy(new MockInvocation());
+ when(invocation.getTargetServiceUniqueName()).thenReturn("TestService-1");
+ }
+
+ @Test
+ void testRequestsCount() {
+ final long requestTimes = 1000L;
+
+ //METRIC_REQUESTS
+ for (long i = 0; i < requestTimes; i++) {
+ sampler.inc(invocation, MetricsEvent.Type.TOTAL.getNameByType("provider"));
+ }
+
+ List samples = sampler.sample();
+
+ MetricSample requestsSample = samples.stream()
+ .filter(sample -> MetricsKey.METRIC_REQUESTS.getNameByType("provider").equals(sample.getName()))
+ .findFirst()
+ .orElse(null);
+
+ Assertions.assertNotNull(requestsSample, "METRIC_REQUESTS sample should not be null");
+ Assertions.assertEquals(MetricSample.Type.COUNTER, requestsSample.getType(), "METRIC_REQUESTS sample should have a COUNTER type");
+ Assertions.assertTrue(requestsSample instanceof CounterMetricSample);
+ Assertions.assertEquals(requestTimes, ((CounterMetricSample) requestsSample).getValue().longValue());
+ }
+
+ @Test
+ void testRequestsProcessing() {
+ final long requestTimes = 1000L;
+
+ //METRIC_REQUESTS
+ for (long i = 0; i < requestTimes; i++) {
+ sampler.inc(invocation, MetricsEvent.Type.PROCESSING.getNameByType("provider"));
+ }
+
+ List samples = sampler.sample();
+
+ MetricSample requestsSample = samples.stream()
+ .filter(sample -> MetricsKey.METRIC_REQUESTS_PROCESSING.getNameByType("provider").equals(sample.getName()))
+ .findFirst()
+ .orElse(null);
+
+ Assertions.assertNotNull(requestsSample, "METRIC_REQUESTS_PROCESSING sample should not be null");
+ Assertions.assertEquals(MetricSample.Type.GAUGE, requestsSample.getType(), "METRIC_REQUESTS_PROCESSING sample should have a GAUGE type");
+ Assertions.assertTrue(requestsSample instanceof GaugeMetricSample);
+ Assertions.assertEquals(requestTimes, ((AtomicLong) ((GaugeMetricSample) requestsSample).getValue()).get());
+
+ for (long i = 0; i < requestTimes; i++) {
+ sampler.dec(invocation, MetricsEvent.Type.PROCESSING.getNameByType("provider"));
+ }
+
+ samples = sampler.sample();
+
+ requestsSample = samples.stream()
+ .filter(sample -> MetricsKey.METRIC_REQUESTS_PROCESSING.getNameByType("provider").equals(sample.getName()))
+ .findFirst()
+ .orElse(null);
+
+ Assertions.assertEquals(0, ((AtomicLong) ((GaugeMetricSample) requestsSample).getValue()).get());
+ }
+
+ @Test
+ void testRequestSucceed() {
+ final long requestTimes = 1000L;
+
+ //METRIC_REQUESTS_SUCCEED
+ for (long i = 0; i < requestTimes; i++) {
+ sampler.inc(invocation, MetricsEvent.Type.SUCCEED.getNameByType("provider"));
+ }
+
+ List samples = sampler.sample();
+
+ MetricSample requestsSample = samples.stream()
+ .filter(sample -> MetricsKey.METRIC_REQUESTS_SUCCEED.getNameByType("provider").equals(sample.getName()))
+ .findFirst()
+ .orElse(null);
+
+ Assertions.assertNotNull(requestsSample, "METRIC_REQUESTS_SUCCEED sample should not be null");
+ Assertions.assertEquals(MetricSample.Type.COUNTER, requestsSample.getType(), "METRIC_REQUESTS_SUCCEED sample should have a COUNTER type");
+ Assertions.assertTrue(requestsSample instanceof CounterMetricSample);
+ Assertions.assertEquals(requestTimes, ((AtomicLong) ((CounterMetricSample) requestsSample).getValue()).get());
+ }
+
+}
diff --git a/dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/collector/RegistryStatCompositeTest.java b/dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/collector/RegistryStatCompositeTest.java
index ba44ab6c15..b1a34e7e32 100644
--- a/dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/collector/RegistryStatCompositeTest.java
+++ b/dubbo-metrics/dubbo-metrics-registry/src/test/java/org/apache/dubbo/metrics/registry/metrics/collector/RegistryStatCompositeTest.java
@@ -21,15 +21,22 @@ import org.apache.dubbo.metrics.data.ApplicationStatComposite;
import org.apache.dubbo.metrics.data.BaseStatComposite;
import org.apache.dubbo.metrics.data.RtStatComposite;
import org.apache.dubbo.metrics.data.ServiceStatComposite;
+import org.apache.dubbo.metrics.model.MetricsCategory;
import org.apache.dubbo.metrics.model.container.LongContainer;
import org.apache.dubbo.metrics.registry.RegistryMetricsConstants;
+import org.apache.dubbo.metrics.model.sample.GaugeMetricSample;
+
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
+import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
+import static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_RT_AVG;
+import static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_RT_MAX;
+import static org.apache.dubbo.metrics.model.key.MetricsKey.METRIC_RT_MIN;
import static org.apache.dubbo.metrics.model.key.MetricsKey.REGISTER_METRIC_REQUESTS;
import static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE_NOTIFY;
import static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE_REGISTER;
@@ -37,6 +44,7 @@ import static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE
import static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE_SUBSCRIBE;
import static org.apache.dubbo.metrics.registry.RegistryMetricsConstants.OP_TYPE_SUBSCRIBE_SERVICE;
+
public class RegistryStatCompositeTest {
private final String applicationName = "app1";
@@ -77,4 +85,42 @@ public class RegistryStatCompositeTest {
Optional> subContainer = statComposite.getRtStatComposite().getRtStats().stream().filter(longContainer -> longContainer.specifyType(OP_TYPE_NOTIFY.getType())).findFirst();
subContainer.ifPresent(v -> Assertions.assertEquals(10L, v.get(applicationName).longValue()));
}
+
+ @Test
+ @SuppressWarnings("rawtypes")
+ void testCalcServiceKeyRt() {
+ String applicationName = "TestApp";
+ String serviceKey = "TestService";
+ String registryOpType = OP_TYPE_REGISTER_SERVICE.getType();
+ Long responseTime1 = 100L;
+ Long responseTime2 = 200L;
+
+ statComposite.calcServiceKeyRt(applicationName, serviceKey, registryOpType, responseTime1);
+ statComposite.calcServiceKeyRt(applicationName, serviceKey, registryOpType, responseTime2);
+
+ List exportedRtMetrics = statComposite.export(MetricsCategory.RT);
+
+ GaugeMetricSample minSample = exportedRtMetrics.stream()
+ .filter(sample -> sample.getTags().containsValue(applicationName))
+ .filter(sample -> sample.getName().equals(METRIC_RT_MIN.getNameByType("register.service")))
+ .findFirst().orElse(null);
+ GaugeMetricSample maxSample = exportedRtMetrics.stream()
+ .filter(sample -> sample.getTags().containsValue(applicationName))
+ .filter(sample -> sample.getName().equals(METRIC_RT_MAX.getNameByType("register.service")))
+ .findFirst().orElse(null);
+ GaugeMetricSample avgSample = exportedRtMetrics.stream()
+ .filter(sample -> sample.getTags().containsValue(applicationName))
+ .filter(sample -> sample.getName().equals(METRIC_RT_AVG.getNameByType("register.service")))
+ .findFirst().orElse(null);
+
+ Assertions.assertNotNull(minSample);
+ Assertions.assertNotNull(maxSample);
+ Assertions.assertNotNull(avgSample);
+
+ Assertions.assertEquals(responseTime1, minSample.applyAsLong());
+ Assertions.assertEquals(responseTime2, maxSample.applyAsLong());
+ Assertions.assertEquals((responseTime1 + responseTime2) / 2, avgSample.applyAsLong());
+ }
+
+
}