From 472bdf7c4fc3f318b368d9512da47ff9453a0b38 Mon Sep 17 00:00:00 2001 From: passer Date: Tue, 25 May 2021 20:37:17 +0800 Subject: [PATCH] Add unit test for CountTelnetHandler (#7846) * Add unit test for CountTelnetHandler (#7842) * Optimize CountTelnetHandlerTest (#7842) --- .../qos/legacy/CountTelnetHandlerTest.java | 109 +++++++++++++ .../dubbo/qos/legacy/channel/MockChannel.java | 145 ++++++++++++++++++ 2 files changed, 254 insertions(+) create mode 100644 dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/legacy/CountTelnetHandlerTest.java create mode 100644 dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/legacy/channel/MockChannel.java diff --git a/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/legacy/CountTelnetHandlerTest.java b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/legacy/CountTelnetHandlerTest.java new file mode 100644 index 00000000000..1d6f77a6061 --- /dev/null +++ b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/legacy/CountTelnetHandlerTest.java @@ -0,0 +1,109 @@ +/* + * 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.qos.legacy; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.qos.legacy.channel.MockChannel; +import org.apache.dubbo.qos.legacy.service.DemoService; +import org.apache.dubbo.remoting.telnet.TelnetHandler; +import org.apache.dubbo.remoting.telnet.support.TelnetUtils; +import org.apache.dubbo.rpc.Invoker; +import org.apache.dubbo.rpc.RpcStatus; +import org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.CountDownLatch; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.reset; + +public class CountTelnetHandlerTest { + + private TelnetHandler handler = new CountTelnetHandler(); + private MockChannel mockChannel; + private Invoker mockInvoker; + private URL url = URL.valueOf("dubbo://127.0.0.1:20884/demo"); + private CountDownLatch latch; + + @BeforeEach + public void setUp() { + latch = new CountDownLatch(2); + mockChannel = new MockChannel(url, latch); + mockInvoker = mock(Invoker.class); + given(mockInvoker.getInterface()).willReturn(DemoService.class); + given(mockInvoker.getUrl()).willReturn(url); + } + + @AfterEach + public void tearDown() { + ProtocolUtils.closeAll(); + mockChannel.close(); + reset(mockInvoker); + } + + @Test + public void test() throws Exception { + String methodName = "sayHello"; + String message = "org.apache.dubbo.qos.legacy.service.DemoService sayHello 1"; + + DubboProtocol.getDubboProtocol().export(mockInvoker); + RpcStatus.beginCount(url, methodName); + RpcStatus.endCount(url, methodName, 10L, true); + handler.telnet(mockChannel, message); + latch.await(); + + StringBuilder sb = new StringBuilder(); + for (Object o : mockChannel.getReceivedObjects()) { + sb.append(o.toString()); + } + + assertThat(sb.toString(), containsString(buildTable(methodName, + 10, 10, "1", "0", "0"))); + } + + public static String buildTable(String methodName, long averageElapsed, + long maxElapsed, String total, String failed, String active) { + List header = new LinkedList<>(); + header.add("method"); + header.add("total"); + header.add("failed"); + header.add("active"); + header.add("average"); + header.add("max"); + + List> table = new LinkedList<>(); + List row = new LinkedList(); + row.add(methodName); + row.add(total); + row.add(failed); + row.add(active); + row.add(averageElapsed + "ms"); + row.add(maxElapsed + "ms"); + + table.add(row); + + return TelnetUtils.toTable(header, table); + } + +} diff --git a/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/legacy/channel/MockChannel.java b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/legacy/channel/MockChannel.java new file mode 100644 index 00000000000..4eb09a30edc --- /dev/null +++ b/dubbo-plugin/dubbo-qos/src/test/java/org/apache/dubbo/qos/legacy/channel/MockChannel.java @@ -0,0 +1,145 @@ +/* + * 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.qos.legacy.channel; + +import org.apache.dubbo.common.URL; +import org.apache.dubbo.remoting.Channel; +import org.apache.dubbo.remoting.ChannelHandler; +import org.apache.dubbo.remoting.RemotingException; + +import java.net.InetSocketAddress; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CountDownLatch; + +public class MockChannel implements Channel { + public static final String ERROR_WHEN_SEND = "error_when_send"; + InetSocketAddress localAddress; + InetSocketAddress remoteAddress; + private URL remoteUrl; + private ChannelHandler handler; + private boolean isClosed; + private volatile boolean closing; + private Map attributes = new HashMap(1); + private List receivedObjects = new LinkedList<>(); + private CountDownLatch latch; + + public MockChannel() { + + } + + public MockChannel(URL remoteUrl) { + this.remoteUrl = remoteUrl; + } + + public MockChannel(URL remoteUrl, CountDownLatch latch) { + this.remoteUrl = remoteUrl; + this.latch = latch; + } + + public MockChannel(ChannelHandler handler) { + this.handler = handler; + } + + @Override + public URL getUrl() { + return remoteUrl; + } + + @Override + public ChannelHandler getChannelHandler() { + return handler; + } + + @Override + public InetSocketAddress getLocalAddress() { + return localAddress; + } + + @Override + public void send(Object message) throws RemotingException { + if (remoteUrl.getParameter(ERROR_WHEN_SEND, Boolean.FALSE)) { + throw new RemotingException(localAddress, remoteAddress, "mock error"); + } else { + receivedObjects.add(message); + if (latch != null) { + latch.countDown(); + } + } + } + + @Override + public void send(Object message, boolean sent) throws RemotingException { + send(message); + } + + @Override + public void close() { + close(0); + } + + @Override + public void close(int timeout) { + isClosed = true; + } + + @Override + public void startClose() { + closing = true; + } + + @Override + public boolean isClosed() { + return isClosed; + } + + @Override + public InetSocketAddress getRemoteAddress() { + return remoteAddress; + } + + @Override + public boolean isConnected() { + return isClosed; + } + + @Override + public boolean hasAttribute(String key) { + return attributes.containsKey(key); + } + + @Override + public Object getAttribute(String key) { + return attributes.get(key); + } + + @Override + public void setAttribute(String key, Object value) { + attributes.put(key, value); + } + + @Override + public void removeAttribute(String key) { + attributes.remove(key); + } + + public List getReceivedObjects() { + return receivedObjects; + } +}