diff --git a/handlers/handler-performance-stats/pom.xml b/handlers/handler-performance-stats/pom.xml new file mode 100644 index 00000000000..23a3504d3d0 --- /dev/null +++ b/handlers/handler-performance-stats/pom.xml @@ -0,0 +1,38 @@ + + + + 4.0.0 + + io.servicecomb + handlers + 0.1.0-m3-SNAPSHOT + + cse-handler-performance-stats + + + io.servicecomb + java-chassis-core + + + io.servicecomb + foundation-metrics + + + com.netflix.hystrix + hystrix-core + + + com.huawei.paas.cse + foundation-auth + 0.1 + + + \ No newline at end of file diff --git a/handlers/handler-performance-stats/src/main/java/com/huawei/paas/cse/handler/stats/PerfStatsHandler.java b/handlers/handler-performance-stats/src/main/java/com/huawei/paas/cse/handler/stats/PerfStatsHandler.java new file mode 100644 index 00000000000..05783b4f907 --- /dev/null +++ b/handlers/handler-performance-stats/src/main/java/com/huawei/paas/cse/handler/stats/PerfStatsHandler.java @@ -0,0 +1,96 @@ +/* + * Copyright 2017 Huawei Technologies Co., Ltd + * + * Licensed 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 com.huawei.paas.cse.handler.stats; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.servicecomb.core.Invocation; +import io.servicecomb.core.handler.impl.AbstractHandler; +import io.servicecomb.foundation.metrics.Metrics; +import io.servicecomb.foundation.metrics.performance.PerfStatContext; +import io.servicecomb.foundation.metrics.performance.PerfStatSuccFail; +import io.servicecomb.swagger.invocation.AsyncResponse; +import io.servicecomb.swagger.invocation.exception.InvocationException; + +/** + * 统计成功、失败的tps、时延等等参数 + * @author + * @version [版本号, 2016年12月5日] + * @see [相关类/方法] + * @since [产品/模块版本] + */ +public class PerfStatsHandler extends AbstractHandler { + private static final Logger LOGGER = LoggerFactory.getLogger(PerfStatsHandler.class); + + /** + * {@inheritDoc} + */ + @Override + public void handle(Invocation invocation, AsyncResponse asyncResp) throws Exception { + String name = invocation.getOperationMeta().getMicroserviceQualifiedName(); + // 先确认是否需要跟踪? + if (!isNeedPerfStat(name)) { + invocation.next(asyncResp); + return; + } + + PerfStatContext context = new PerfStatContext(); + + // TODO: + // 1.如果能确定是放在exceptionHandler前面,则这里不必catch + // 2.作为handler,框架上的异常场景统计不到 + // 3.这里只统计了调用的tps,而业务层的消息数,如何感知支撑? + // 使用标准的metrics方案,可以解决这些问题 + try { + invocation.next(resp -> { + asyncResp.handle(resp); + + onStat(invocation, resp.isSuccessed(), context); + }); + } catch (Throwable e) { + if (!InvocationException.class.isInstance(e)) { + LOGGER.error("invoke failed,", e); + } + onStat(invocation, false, context); + asyncResp.fail(invocation.getInvocationType(), e); + } + } + + protected void onStat(Invocation invocation, boolean isSucc, PerfStatContext context) { + context.setMsgCount(1); + + // 统计标识带上transport名称,方便识别场景 + String statName = invocation.getInvocationQualifiedName(); + + // TODO:同优先级的,后加入的应该在最后 + PerfStatSuccFail stat = Metrics.getOrCreateLocalPerfStat(statName, 0); + stat.add(isSucc, context); + } + + // TODO:由客户端带过来?不应该要求两端都配置? + /** + * <一句话功能简述> + * <功能详细描述> + * @param name + * @return + */ + private boolean isNeedPerfStat(String name) { + return true; + } + +} diff --git a/handlers/handler-performance-stats/src/main/java/com/huawei/paas/cse/handler/stats/monitor/DataFactory.java b/handlers/handler-performance-stats/src/main/java/com/huawei/paas/cse/handler/stats/monitor/DataFactory.java new file mode 100644 index 00000000000..3bd1a755061 --- /dev/null +++ b/handlers/handler-performance-stats/src/main/java/com/huawei/paas/cse/handler/stats/monitor/DataFactory.java @@ -0,0 +1,189 @@ +package com.huawei.paas.cse.handler.stats.monitor; + +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryMXBean; +import java.lang.management.MemoryUsage; +import java.lang.management.OperatingSystemMXBean; +import java.lang.management.ThreadMXBean; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.util.EntityUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.huawei.paas.foundation.auth.AuthHeaderUtils; +import com.huawei.paas.foundation.auth.HttpClientFactory; +import com.netflix.config.DynamicBooleanProperty; +import com.netflix.config.DynamicPropertyFactory; +import com.netflix.config.DynamicStringProperty; +import com.netflix.hystrix.HystrixCommandMetrics; + +import io.netty.util.concurrent.DefaultThreadFactory; +import io.servicecomb.serviceregistry.RegistryUtils; +import io.vertx.core.json.Json; + +/** + * 数据生成工厂,启动一个线程池,定时发送数据 + * @author w00293972 + */ +class DataFactory { + + private static final Logger LOGGER = LoggerFactory.getLogger(DataFactory.class); + private static final int CORE_SIZE = 1; + private static final int SLEEP_MINI_TIME = 1; + private static final int SLEEP_MAX_TIME = 10; + private static final int DELAY_TIME_MILLISECONDS = 1000; + + private static final String SSL_KEY = "mc.consumer"; + private boolean hasStart = false; + private boolean firestError = true; + + private static DataFactory INSTANCE = new DataFactory(); + + private ScheduledExecutorService executorService = null; + + private DataFactory() { + ThreadFactory tf = new DefaultThreadFactory("cse-monitor-datafactory"); + executorService = Executors.newScheduledThreadPool(CORE_SIZE, tf); + } + + public static DataFactory getInstance() { + return INSTANCE; + } + + /** + * 开启数据上报 + */ + void start() { + if (!hasStart) { + LOGGER.info("Start collect monitor data, send to Monitor Sender!"); + executorService.scheduleWithFixedDelay(() -> { + int elapsedTime = sendData(getData()); + delayTime(elapsedTime); + }, DELAY_TIME_MILLISECONDS, DELAY_TIME_MILLISECONDS, TimeUnit.MILLISECONDS); + hasStart = true; + } + } + + private void delayTime(int elapsedTime) { + int sleepTime = elapsedTime / 1000; + try { + if (sleepTime < SLEEP_MINI_TIME) { + return; + } + if (sleepTime > SLEEP_MAX_TIME) { + sleepTime = SLEEP_MAX_TIME; + } + Thread.sleep(sleepTime * 1000); + } catch (InterruptedException e) { + LOGGER.error("Sleep delay time error"); + } + } + + /** + * 发送数据 + * @param monitorData + */ + int sendData(MonitorData monitorData) { + if (!getEnableMonitor()) { + return 0; + } + HttpClient monitorClient = HttpClientFactory.getOrCreateHttpClient(SSL_KEY); + HttpPost httpPost = new HttpPost(getServerUrl() + "/csemonitor/v1/metric?service=" + monitorData.getName()); + httpPost.addHeader("Content-Type", "application/json"); + Map akskHeaders = AuthHeaderUtils.getInstance().genAuthHeaders(); + for (Map.Entry header : akskHeaders.entrySet()) { + httpPost.setHeader(header.getKey(), header.getValue()); + } + HttpEntity entity; + long startTime = System.currentTimeMillis(); + try { + entity = new StringEntity(Json.encode(monitorData)); + httpPost.setEntity(entity); + HttpResponse response = monitorClient.execute(httpPost); + LOGGER.debug(response.getStatusLine().toString()); + EntityUtils.consume(response.getEntity()); + } catch (IOException e) { + if (firestError) { + LOGGER.error("Upload monitor data error!"); + firestError = false; + } + } + long endTime = System.currentTimeMillis(); + int time = (int) (endTime - startTime); + return time; + } + + /** + * 构造数据 + * @return 监控数据 + */ + MonitorData getData() { + Collection instances = HystrixCommandMetrics.getInstances(); + MonitorData monitorData = new MonitorData(); + monitorData.setName(RegistryUtils.getMicroservice().getServiceName()); + monitorData.setInstance(RegistryUtils.getMicroserviceInstance().getHostName()); + exactProcessInfo(monitorData); + if (instances == null || instances.isEmpty()) { + return monitorData; + } + for (HystrixCommandMetrics instance : instances) { + monitorData.appendInterfaceInfo(instance); + } + return monitorData; + } + + private void exactProcessInfo(MonitorData monitorData) { + MemoryMXBean memBean = ManagementFactory.getMemoryMXBean(); + MemoryUsage memoryHeapUsage = memBean.getHeapMemoryUsage(); + MemoryUsage memoryNonHeapUsage = memBean.getNonHeapMemoryUsage(); + ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); + int threadCount = threadBean.getThreadCount(); + OperatingSystemMXBean osMxBean = ManagementFactory.getOperatingSystemMXBean(); + // this method only work well on Unix operation system + double cpu = osMxBean.getSystemLoadAverage(); + monitorData.setCpu(cpu); + monitorData.setThreadCount(threadCount); + Map memoryInfo = new HashMap<>(); + memoryInfo.put("heapInit", memoryHeapUsage.getInit()); + memoryInfo.put("heapMax", memoryHeapUsage.getMax()); + memoryInfo.put("heapCommit", memoryHeapUsage.getCommitted()); + memoryInfo.put("heapUsed", memoryHeapUsage.getUsed()); + memoryInfo.put("nonHeapInit", memoryNonHeapUsage.getInit()); + memoryInfo.put("nonHeapCommit", memoryNonHeapUsage.getCommitted()); + memoryInfo.put("nonHeapUsed", memoryNonHeapUsage.getUsed()); + monitorData.setMemory(memoryInfo); + } + + /** + * 获取数据上报地址 + * @return + */ + public String getServerUrl() { + DynamicStringProperty property = DynamicPropertyFactory.getInstance() + .getStringProperty("cse.monitor.client.serverUri", "https://cse-dashbord-service:30109"); + return property.getValue(); + } + + /** + * 获取是否上报数据 + * @return + */ + public boolean getEnableMonitor() { + DynamicBooleanProperty property = DynamicPropertyFactory.getInstance() + .getBooleanProperty("cse.monitor.client.enable", true); + return property.getValue(); + } +} diff --git a/handlers/handler-performance-stats/src/main/java/com/huawei/paas/cse/handler/stats/monitor/MonitorData.java b/handlers/handler-performance-stats/src/main/java/com/huawei/paas/cse/handler/stats/monitor/MonitorData.java new file mode 100644 index 00000000000..b6990752d46 --- /dev/null +++ b/handlers/handler-performance-stats/src/main/java/com/huawei/paas/cse/handler/stats/monitor/MonitorData.java @@ -0,0 +1,377 @@ +package com.huawei.paas.cse.handler.stats.monitor; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import com.netflix.hystrix.HystrixCommandMetrics; +import com.netflix.hystrix.HystrixEventType; + +/** + * 监控上报的数据,每次上报一条数据 + * @author w00293972 + */ +public class MonitorData { + private static final double PERCENTAGE_995 = 99.5; + private static final double PERCENTAGE_99 = 99; + private static final double PERCENTAGE_90 = 90; + private static final double PERCENTAGE_75 = 75; + private static final double PERCENTAGE_50 = 50; + private static final double PERCENTAGE_25 = 25; + private static final double PERCENTAGE_5 = 5; + private static final int SCALE_VAL = 1; + /** + * 服务名称 + */ + private String name; + /** + * 服务实例名称 + */ + private String instance; + + private int thread; + private double cpu; + private Map memory; + + /** + * 接口相关监控数据 + */ + private List interfaces = new ArrayList<>(); + + /** + * 用户自定义的一些变量 + */ + private Map customs; + + public void appendInterfaceInfo(HystrixCommandMetrics metrics) { + InterfaceInfo interfaceInfo = new InterfaceInfo(); + int windowTime = metrics.getProperties().metricsRollingStatisticalWindowInMilliseconds().get() / 1000; + HystrixEventType[] events = {HystrixEventType.SUCCESS, HystrixEventType.FAILURE}; + long rollingTotal = 0; + long cumulativeTotal = 0; + + for (HystrixEventType event : events) { + long val = metrics.getRollingCount(event); + long cumVal = metrics.getCumulativeCount(event); + rollingTotal += val; + cumulativeTotal += cumVal; + } + long successCount = metrics.getRollingCount(HystrixEventType.SUCCESS); + long failureCount = metrics.getRollingCount(HystrixEventType.FAILURE); + long semRejectCount = metrics.getRollingCount(HystrixEventType.SEMAPHORE_REJECTED); + long threadRejectCount = metrics.getRollingCount(HystrixEventType.THREAD_POOL_REJECTED); + long timeoutCount = metrics.getRollingCount(HystrixEventType.TIMEOUT); + + int latency = metrics.getExecutionTimeMean(); + int latency995 = metrics.getExecutionTimePercentile(PERCENTAGE_995); + int latency99 = metrics.getExecutionTimePercentile(PERCENTAGE_99); + int latency90 = metrics.getExecutionTimePercentile(PERCENTAGE_90); + int latency75 = metrics.getExecutionTimePercentile(PERCENTAGE_75); + int latency50 = metrics.getExecutionTimePercentile(PERCENTAGE_50); + int latency25 = metrics.getExecutionTimePercentile(PERCENTAGE_25); + int latency5 = metrics.getExecutionTimePercentile(PERCENTAGE_5); + + interfaceInfo.setName(metrics.getCommandKey().name()); + interfaceInfo.setCircuitBreakerOpen(metrics.getProperties().circuitBreakerEnabled().get()); + interfaceInfo.setFailure(failureCount); + interfaceInfo.setSemaphoreRejected(semRejectCount); + interfaceInfo.setThreadPoolRejected(threadRejectCount); + interfaceInfo.setCountTimeout(timeoutCount); + interfaceInfo.setDesc(metrics.getCommandKey().name()); + interfaceInfo.setLatency(latency); + interfaceInfo.setL25(latency25); + interfaceInfo.setL5(latency5); + interfaceInfo.setL50(latency50); + interfaceInfo.setL75(latency75); + interfaceInfo.setL90(latency90); + interfaceInfo.setL99(latency99); + interfaceInfo.setL995(latency995); + interfaceInfo.setTotal(cumulativeTotal); + double qpsVal = ((double) rollingTotal) / windowTime; + BigDecimal b = new BigDecimal(qpsVal); + BigDecimal qps = b.setScale(SCALE_VAL, RoundingMode.HALF_DOWN); + interfaceInfo.setQps(qps.doubleValue()); + if (rollingTotal == 0) { + interfaceInfo.setRate(100); + } else { + interfaceInfo.setRate(((double) successCount) / rollingTotal); + } + interfaces.add(interfaceInfo); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getInstance() { + return instance; + } + + public void setInstance(String instance) { + this.instance = instance; + } + + public List getInterfaces() { + return interfaces; + } + + public Map getCustoms() { + return customs; + } + + public void setCustoms(Map customs) { + this.customs = customs; + } + + public double getCpu() { + return cpu; + } + + public void setCpu(double cpu) { + this.cpu = cpu; + } + + public int getThreadCount() { + return thread; + } + + public void setThreadCount(int threadCount) { + this.thread = threadCount; + } + + public Map getMemory() { + return memory; + } + + public void setMemory(Map memory) { + this.memory = memory; + } + + /** + * 接口相关监控数据 + * @author w00293972 + */ + public class InterfaceInfo { + /** + * 接口名称 + */ + private String name; + /** + * 接口描述 + */ + private String desc; + /** + * 每秒请求量,单位个 + */ + private double qps; + /** + * 时延,单位毫秒 + */ + private int latency; + + private int l995; + + private int l99; + + private int l90; + + private int l75; + + private int l50; + + private int l25; + + private int l5; + /** + * 成功率,百分比 + */ + private double rate; + /** + * 请求总量 + */ + private long total; + /** + * 当前熔断状态 + */ + private boolean isCircuitBreakerOpen; + /** + * 失败总个数 + */ + private long failure; + /** + * 总短路个数 + */ + private long shortCircuited; + /** + * 总信号量拒绝个数 + */ + private long semaphoreRejected; + /** + * 总线程池拒绝个数 + */ + private long threadPoolRejected; + /** + * 总超时个数 + */ + private long countTimeout; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } + + public double getQps() { + return qps; + } + + public void setQps(double qps) { + this.qps = qps; + } + + public int getLatency() { + return latency; + } + + public void setLatency(int latency) { + this.latency = latency; + } + + public int getL995() { + return l995; + } + + public void setL995(int l995) { + this.l995 = l995; + } + + public int getL99() { + return l99; + } + + public void setL99(int l99) { + this.l99 = l99; + } + + public int getL90() { + return l90; + } + + public void setL90(int l90) { + this.l90 = l90; + } + + public int getL75() { + return l75; + } + + public void setL75(int l75) { + this.l75 = l75; + } + + public int getL50() { + return l50; + } + + public void setL50(int l50) { + this.l50 = l50; + } + + public int getL25() { + return l25; + } + + public void setL25(int l25) { + this.l25 = l25; + } + + public int getL5() { + return l5; + } + + public void setL5(int l5) { + this.l5 = l5; + } + + public double getRate() { + return rate; + } + + public void setRate(double rate) { + this.rate = rate; + } + + public long getTotal() { + return total; + } + + public void setTotal(long total) { + this.total = total; + } + + public boolean isCircuitBreakerOpen() { + return isCircuitBreakerOpen; + } + + public void setCircuitBreakerOpen(boolean isCircuitBreakerOpen) { + this.isCircuitBreakerOpen = isCircuitBreakerOpen; + } + + public long getFailure() { + return failure; + } + + public void setFailure(long failure) { + this.failure = failure; + } + + public long getShortCircuited() { + return shortCircuited; + } + + public void setShortCircuited(long shortCircuited) { + this.shortCircuited = shortCircuited; + } + + public long getSemaphoreRejected() { + return semaphoreRejected; + } + + public void setSemaphoreRejected(long semaphoreRejected) { + this.semaphoreRejected = semaphoreRejected; + } + + public long getThreadPoolRejected() { + return threadPoolRejected; + } + + public void setThreadPoolRejected(long threadPoolRejected) { + this.threadPoolRejected = threadPoolRejected; + } + + public long getCountTimeout() { + return countTimeout; + } + + public void setCountTimeout(long countTimeout) { + this.countTimeout = countTimeout; + } + + } +} diff --git a/handlers/handler-performance-stats/src/main/java/com/huawei/paas/cse/handler/stats/monitor/MonitorStarter.java b/handlers/handler-performance-stats/src/main/java/com/huawei/paas/cse/handler/stats/monitor/MonitorStarter.java new file mode 100644 index 00000000000..f36f2114c32 --- /dev/null +++ b/handlers/handler-performance-stats/src/main/java/com/huawei/paas/cse/handler/stats/monitor/MonitorStarter.java @@ -0,0 +1,12 @@ +package com.huawei.paas.cse.handler.stats.monitor; + +/** + * 启动器,确保DataFactory只能启动一次 + * @author w00293972 + */ +public class MonitorStarter { + + public void start() { + DataFactory.getInstance().start(); + } +} diff --git a/handlers/handler-performance-stats/src/main/resources/META-INF/spring/services.bean.xml b/handlers/handler-performance-stats/src/main/resources/META-INF/spring/services.bean.xml new file mode 100644 index 00000000000..38e2fc4a120 --- /dev/null +++ b/handlers/handler-performance-stats/src/main/resources/META-INF/spring/services.bean.xml @@ -0,0 +1,10 @@ + + + + + \ No newline at end of file diff --git a/handlers/handler-performance-stats/src/main/resources/config/cse.handler.xml b/handlers/handler-performance-stats/src/main/resources/config/cse.handler.xml new file mode 100644 index 00000000000..4e9276c8380 --- /dev/null +++ b/handlers/handler-performance-stats/src/main/resources/config/cse.handler.xml @@ -0,0 +1,20 @@ + + + + + \ No newline at end of file diff --git a/handlers/handler-performance-stats/src/test/java/com/huawei/paas/cse/handler/stats/TestPerfStatsHandler.java b/handlers/handler-performance-stats/src/test/java/com/huawei/paas/cse/handler/stats/TestPerfStatsHandler.java new file mode 100644 index 00000000000..1bed773e196 --- /dev/null +++ b/handlers/handler-performance-stats/src/test/java/com/huawei/paas/cse/handler/stats/TestPerfStatsHandler.java @@ -0,0 +1,74 @@ +/* + * Copyright 2017 Huawei Technologies Co., Ltd + * + * Licensed 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 com.huawei.paas.cse.handler.stats; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +import io.servicecomb.core.Invocation; +import io.servicecomb.core.definition.OperationMeta; +import io.servicecomb.foundation.metrics.performance.PerfStatContext; +import io.servicecomb.swagger.invocation.AsyncResponse; + +public class TestPerfStatsHandler { + + PerfStatsHandler perfStatsHandler = null; + + Invocation invocation = null; + + AsyncResponse asyncResp = null; + + PerfStatContext perfStatContext = null; + + @Before + public void setUp() throws Exception { + perfStatsHandler = new PerfStatsHandler(); + invocation = Mockito.mock(Invocation.class); + asyncResp = Mockito.mock(AsyncResponse.class); + perfStatContext = new PerfStatContext(); + } + + @After + public void tearDown() throws Exception { + perfStatsHandler = null; + invocation = null; + asyncResp = null; + perfStatContext = null; + } + + @Test + public void testHandle() { + boolean status = false; + Mockito.when(invocation.getOperationMeta()).thenReturn(Mockito.mock(OperationMeta.class)); + try { + perfStatsHandler.handle(invocation, asyncResp); + } catch (Exception e) { + status = true; + } + Assert.assertFalse(status); + } + + @Test + public void testOnStat() { + Mockito.when(invocation.getInvocationQualifiedName()).thenReturn("statName"); + perfStatsHandler.onStat(invocation, false, perfStatContext); + Assert.assertEquals(1, perfStatContext.getMsgCount()); + } +} diff --git a/handlers/handler-performance-stats/src/test/java/com/huawei/paas/cse/handler/stats/monitor/DataFactoryTest.java b/handlers/handler-performance-stats/src/test/java/com/huawei/paas/cse/handler/stats/monitor/DataFactoryTest.java new file mode 100644 index 00000000000..a08940a3232 --- /dev/null +++ b/handlers/handler-performance-stats/src/test/java/com/huawei/paas/cse/handler/stats/monitor/DataFactoryTest.java @@ -0,0 +1,189 @@ +package com.huawei.paas.cse.handler.stats.monitor; + +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; + +import org.apache.http.HttpHost; +import org.apache.http.HttpRequest; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.conn.ClientConnectionManager; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.params.HttpParams; +import org.apache.http.protocol.HttpContext; +import org.junit.Assert; +import org.junit.Test; + +import com.huawei.paas.cse.handler.stats.monitor.MonitorData.InterfaceInfo; +import com.huawei.paas.foundation.auth.HttpClientFactory; +import com.netflix.hystrix.HystrixCommandMetrics; +import com.netflix.hystrix.HystrixCommandProperties; +import com.netflix.hystrix.HystrixEventType; +import com.netflix.hystrix.strategy.properties.HystrixProperty; + +import io.servicecomb.serviceregistry.RegistryUtils; +import io.servicecomb.serviceregistry.api.registry.Microservice; +import mockit.Expectations; +import mockit.Mock; +import mockit.MockUp; +import mockit.Mocked; + +@SuppressWarnings("deprecation") +public class DataFactoryTest { + + @Test + public void testStart() { + Constructor[] cs = HttpClientFactory.class.getDeclaredConstructors(); + for (Constructor c : cs) { + c.setAccessible(true); + try { + c.newInstance(); + } catch (InstantiationException | IllegalAccessException | IllegalArgumentException + | InvocationTargetException e) { + e.printStackTrace(); + } + } + + new MockUp () { + @Mock + public Microservice getMicroservice() { + return new Microservice(); + } + }; + + DataFactory.getInstance().start(); + MonitorData data = DataFactory.getInstance().getData(); + Assert.assertNotNull(DataFactory.getInstance().getServerUrl()); + Assert.assertNotNull(data); + } + + @Test + public void testSendData(@Mocked HystrixCommandMetrics metric, @Mocked HttpClient httpClient, @Mocked CloseableHttpResponse resp, @Mocked HystrixCommandProperties properties, + @Mocked HystrixProperty mill) throws IOException { + + HttpClient client = new CloseableHttpClient() { + int times = 0; + @Override + public CloseableHttpResponse execute(HttpUriRequest request) + throws IOException, ClientProtocolException { + if (times == 0) { + times ++; + return resp; + } + else { + throw new IOException(); + } + } + + @Override + public void close() throws IOException { + } + + @Override + public HttpParams getParams() { + return null; + } + + @Override + public ClientConnectionManager getConnectionManager() { + return null; + } + + @Override + protected CloseableHttpResponse doExecute(HttpHost target, HttpRequest request, HttpContext context) + throws IOException, ClientProtocolException { + return null; + } + }; + new MockUp() { + @Mock + public HttpClient getOrCreateHttpClient(String key) { + return client; + } + }; + Collection metrics = new ArrayList(); + metrics.add(metric); + new MockUp () { + @Mock + public Collection getInstances() { + return null; + } + }; + //第一次模拟异常情况发布 + DataFactory.getInstance().sendData(new MonitorData()); + //第二次模拟正常情况 + int time = DataFactory.getInstance().sendData(new MonitorData()); + Assert.assertTrue(time >= 0); + } + + @Test + public void testMonitorData(@Mocked HystrixCommandMetrics metrics, @Mocked HystrixCommandProperties properties, + @Mocked HystrixProperty mill, @Mocked HystrixCommandMetrics metricssecond) { + HystrixProperty circuit = new HystrixProperty() { + @Override + public Boolean get() { + return true; + } + }; + new Expectations() { + { + metrics.getProperties(); + result = properties; + properties.metricsRollingStatisticalWindowInMilliseconds(); + result = mill; + mill.get(); + result = 10000; + properties.circuitBreakerEnabled(); + result = circuit; + metrics.getCumulativeCount(HystrixEventType.SUCCESS); + result = 110; + metrics.getRollingCount(HystrixEventType.SUCCESS); + result = 11; + + metricssecond.getProperties(); + result = properties; + properties.metricsRollingStatisticalWindowInMilliseconds(); + result = mill; + mill.get(); + result = 10000; + properties.circuitBreakerEnabled(); + result = circuit; + metricssecond.getCumulativeCount(HystrixEventType.SUCCESS); + result = 110; + metricssecond.getRollingCount(HystrixEventType.SUCCESS); + result = 0; + } + }; + MonitorData data = new MonitorData(); + data.setName("test"); + data.setInstance("hello"); + data.setCustoms(new HashMap<>()); + data.appendInterfaceInfo(metrics); + data.appendInterfaceInfo(metricssecond); + data.getCustoms(); + data.getInstance(); + InterfaceInfo info = data.getInterfaces().get(0); + info.setShortCircuited(1); + Method[] methods = info.getClass().getDeclaredMethods(); + for (Method m : methods) { + if (m.getName().startsWith("get") || m.getName().startsWith("is")) { + try { + m.invoke(info); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + Assert.assertEquals("test", data.getName()); + Assert.assertEquals(2, data.getInterfaces().size()); + } + +} diff --git a/handlers/handler-performance-stats/src/test/java/com/huawei/paas/cse/handler/stats/monitor/MonitorStarterTest.java b/handlers/handler-performance-stats/src/test/java/com/huawei/paas/cse/handler/stats/monitor/MonitorStarterTest.java new file mode 100644 index 00000000000..4858ed863a7 --- /dev/null +++ b/handlers/handler-performance-stats/src/test/java/com/huawei/paas/cse/handler/stats/monitor/MonitorStarterTest.java @@ -0,0 +1,13 @@ +package com.huawei.paas.cse.handler.stats.monitor; + +import org.junit.Test; + +public class MonitorStarterTest { + + @Test + public void testStart() { + MonitorStarter starter = new MonitorStarter(); + starter.start(); + } + +}