From 4fbccd879bba98529f123ddebf431348b974f209 Mon Sep 17 00:00:00 2001
From: cdfive <31885791+cdfive@users.noreply.github.com>
Date: Wed, 26 Dec 2018 16:08:04 +0800
Subject: [PATCH] Add some unit test for sentinel-transport-netty-http module
(#321)
---
.../sentinel-transport-netty-http/pom.xml | 10 +
.../command/netty/HttpServerHandlerTest.java | 212 ++++++++++++++++++
.../netty/HttpServerInitializerTest.java | 64 ++++++
.../command/netty/HttpServerTest.java | 117 ++++++++++
4 files changed, 403 insertions(+)
create mode 100644 sentinel-transport/sentinel-transport-netty-http/src/test/java/com/alibaba/csp/sentinel/transport/command/netty/HttpServerHandlerTest.java
create mode 100644 sentinel-transport/sentinel-transport-netty-http/src/test/java/com/alibaba/csp/sentinel/transport/command/netty/HttpServerInitializerTest.java
create mode 100644 sentinel-transport/sentinel-transport-netty-http/src/test/java/com/alibaba/csp/sentinel/transport/command/netty/HttpServerTest.java
diff --git a/sentinel-transport/sentinel-transport-netty-http/pom.xml b/sentinel-transport/sentinel-transport-netty-http/pom.xml
index ae403039..ad978a6e 100755
--- a/sentinel-transport/sentinel-transport-netty-http/pom.xml
+++ b/sentinel-transport/sentinel-transport-netty-http/pom.xml
@@ -41,5 +41,15 @@
httpcore
4.4.5
+
+ junit
+ junit
+ test
+
+
+ org.mockito
+ mockito-core
+ test
+
\ No newline at end of file
diff --git a/sentinel-transport/sentinel-transport-netty-http/src/test/java/com/alibaba/csp/sentinel/transport/command/netty/HttpServerHandlerTest.java b/sentinel-transport/sentinel-transport-netty-http/src/test/java/com/alibaba/csp/sentinel/transport/command/netty/HttpServerHandlerTest.java
new file mode 100644
index 00000000..3102c217
--- /dev/null
+++ b/sentinel-transport/sentinel-transport-netty-http/src/test/java/com/alibaba/csp/sentinel/transport/command/netty/HttpServerHandlerTest.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright 1999-2018 Alibaba Group Holding 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.alibaba.csp.sentinel.transport.command.netty;
+
+import com.alibaba.csp.sentinel.Constants;
+import com.alibaba.csp.sentinel.config.SentinelConfig;
+import com.alibaba.csp.sentinel.init.InitExecutor;
+import com.alibaba.csp.sentinel.slots.block.RuleConstant;
+import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
+import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
+import com.alibaba.csp.sentinel.transport.CommandCenter;
+import com.alibaba.csp.sentinel.transport.command.NettyHttpCommandCenter;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.embedded.EmbeddedChannel;
+import io.netty.handler.codec.http.*;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.lang.reflect.Field;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST;
+import static io.netty.handler.codec.http.HttpResponseStatus.OK;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Test cases for {@link HttpServerHandler}.
+ *
+ * @author cdfive
+ * @date 2018-12-17
+ */
+public class HttpServerHandlerTest {
+
+ private static String CRLF = "\r\n";
+
+ private static String SENTINEL_CHARSET_NAME = SentinelConfig.charset();
+
+ private static Charset SENTINEL_CHARSET = Charset.forName(SENTINEL_CHARSET_NAME);
+
+ private static EmbeddedChannel embeddedChannel;
+
+ @BeforeClass
+ public static void beforeClass() throws Exception {
+ // don't execute InitExecutor.doInit, to avoid CommandCenter SPI loaded
+ Field[] declaredFields = InitExecutor.class.getDeclaredFields();
+ for (Field declaredField : declaredFields) {
+ if (declaredField.getName().equals("initialized")) {
+ declaredField.setAccessible(true);
+ ((AtomicBoolean)declaredField.get(InitExecutor.class)).set(true);
+ }
+ }
+
+ // create NettyHttpCommandCenter to create HttpServer
+ CommandCenter commandCenter = new NettyHttpCommandCenter();
+ // call beforeStart to register handlers
+ commandCenter.beforeStart();
+ }
+
+ @Before
+ public void before() {
+ // the same Handlers in order as the ChannelPipeline in HttpServerInitializer
+ HttpRequestDecoder httpRequestDecoder = new HttpRequestDecoder();
+ HttpObjectAggregator httpObjectAggregator = new HttpObjectAggregator(1024 * 1024);
+ HttpResponseEncoder httpResponseEncoder = new HttpResponseEncoder();
+
+ HttpServerHandler httpServerHandler = new HttpServerHandler();
+
+ // create new EmbeddedChannel every method call
+ embeddedChannel = new EmbeddedChannel(httpRequestDecoder, httpObjectAggregator, httpResponseEncoder, httpServerHandler);
+ }
+
+ @Test
+ public void testInvalidCommand() {
+ String httpRequestStr = "GET / HTTP/1.1" + CRLF
+ + "Host: localhost:8719" + CRLF
+ + CRLF;
+ String body = "Invalid command";
+
+ processError(httpRequestStr, body);
+ }
+
+ @Test
+ public void testUnknownCommand() {
+ String httpRequestStr = "GET /aaa HTTP/1.1" + CRLF
+ + "Host: localhost:8719" + CRLF
+ + CRLF;
+ String body = String.format("Unknown command \"%s\"", "aaa");
+
+ processError(httpRequestStr, body);
+ }
+
+ @Test
+ public void testVersionCommand() {
+ String httpRequestStr = "GET /version HTTP/1.1" + CRLF
+ + "Host: localhost:8719" + CRLF
+ + CRLF;
+ String body = Constants.SENTINEL_VERSION;
+
+ processSuccess(httpRequestStr, body);
+ }
+
+ @Test
+ public void testGetRuleCommandInvalidType() {
+ String httpRequestStr = "GET /getRules HTTP/1.1" + CRLF
+ + "Host: localhost:8719" + CRLF
+ + CRLF;
+ String body = "invalid type";
+
+ processFailed(httpRequestStr, body);
+ }
+
+ @Test
+ public void testGetRuleCommandFlowEmptyRule() {
+ String httpRequestStr = "GET /getRules?type=flow HTTP/1.1" + CRLF
+ + "Host: localhost:8719" + CRLF
+ + CRLF;
+ String body = "[]";
+
+ processSuccess(httpRequestStr, body);
+ }
+
+// FIXME byteBuf.toString can't get body response now, need to find another way
+// @Test
+ public void testGetRuleCommandFlowSomeRules() {
+ List rules = new ArrayList();
+ FlowRule rule1 = new FlowRule();
+ rule1.setResource("key");
+ rule1.setCount(20);
+ rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
+ rule1.setLimitApp("default");
+ rules.add(rule1);
+ FlowRuleManager.loadRules(rules);
+
+ String httpRequestStr = "GET /getRules?type=flow HTTP/1.1" + CRLF
+ + "Host: localhost:8719" + CRLF
+ + CRLF;
+ String body = "";
+
+ processSuccess(httpRequestStr, body);
+ }
+
+ private void processError(String httpRequestStr, String body) {
+ processError(httpRequestStr, BAD_REQUEST, body);
+ }
+
+ private void processError(String httpRequestStr, HttpResponseStatus status, String body) {
+ String httpResponseStr = processResponse(httpRequestStr);
+ assertErrorStatusAndBody(status, body, httpResponseStr);
+ }
+
+ private void processSuccess(String httpRequestStr, String body) {
+ process(httpRequestStr, OK, body);
+ }
+
+ private void processFailed(String httpRequestStr, String body) {
+ process(httpRequestStr, BAD_REQUEST, body);
+ }
+
+ private void process(String httpRequestStr, HttpResponseStatus status, String body) {
+ String responseStr = processResponse(httpRequestStr);
+ assertStatusAndBody(status, body, responseStr);
+ }
+
+ private String processResponse(String httpRequestStr) {
+ embeddedChannel.writeInbound(Unpooled.wrappedBuffer(httpRequestStr.getBytes(SENTINEL_CHARSET)));
+
+ ByteBuf byteBuf = embeddedChannel.readOutbound();
+
+ String responseStr = byteBuf.toString(SENTINEL_CHARSET);
+ return responseStr;
+ }
+
+ private void assertErrorStatusAndBody(HttpResponseStatus status, String body, String httpResponseStr) {
+ StringBuilder text = new StringBuilder();
+ text.append(HttpVersion.HTTP_1_1.toString()).append(' ').append(status.toString()).append(CRLF);
+ text.append("Content-Type: text/plain; charset=").append(SENTINEL_CHARSET_NAME).append(CRLF);
+ text.append(CRLF);
+ text.append(body);
+
+ assertEquals(text.toString(), httpResponseStr);
+ }
+
+ private void assertStatusAndBody(HttpResponseStatus status, String body, String httpResponseStr) {
+ StringBuilder text = new StringBuilder();
+ text.append(HttpVersion.HTTP_1_1.toString()).append(' ').append(status.toString()).append(CRLF);
+ text.append("Content-Type: text/plain; charset=").append(SENTINEL_CHARSET_NAME).append(CRLF);
+ text.append("content-length: " + body.length()).append(CRLF);
+ text.append("connection: close").append(CRLF);
+ text.append(CRLF);
+ text.append(body);
+
+ assertEquals(text.toString(), httpResponseStr);
+ }
+}
\ No newline at end of file
diff --git a/sentinel-transport/sentinel-transport-netty-http/src/test/java/com/alibaba/csp/sentinel/transport/command/netty/HttpServerInitializerTest.java b/sentinel-transport/sentinel-transport-netty-http/src/test/java/com/alibaba/csp/sentinel/transport/command/netty/HttpServerInitializerTest.java
new file mode 100644
index 00000000..ba43448c
--- /dev/null
+++ b/sentinel-transport/sentinel-transport-netty-http/src/test/java/com/alibaba/csp/sentinel/transport/command/netty/HttpServerInitializerTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 1999-2018 Alibaba Group Holding 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.alibaba.csp.sentinel.transport.command.netty;
+
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelPipeline;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.handler.codec.http.HttpObjectAggregator;
+import io.netty.handler.codec.http.HttpRequestDecoder;
+import io.netty.handler.codec.http.HttpResponseEncoder;
+import org.junit.Test;
+import org.mockito.InOrder;
+
+import static org.mockito.Mockito.*;
+
+/**
+ * Test cases for {@link HttpServerInitializer}.
+ *
+ * @author cdfive
+ * @date 2018-12-19
+ */
+public class HttpServerInitializerTest {
+
+ @Test
+ public void testInitChannel() throws Exception {
+ // mock Objects
+ HttpServerInitializer httpServerInitializer = mock(HttpServerInitializer.class);
+ SocketChannel socketChannel = mock(SocketChannel.class);
+ ChannelPipeline channelPipeline = mock(ChannelPipeline.class);
+
+ // mock SocketChannel#pipeline() method
+ when(socketChannel.pipeline()).thenReturn(channelPipeline);
+
+ // HttpServerInitializer#initChannel(SocketChannel) call real method
+ doCallRealMethod().when(httpServerInitializer).initChannel(socketChannel);
+
+ // start test for HttpServerInitializer#initChannel(SocketChannel)
+ httpServerInitializer.initChannel(socketChannel);
+
+ // verify 4 times calling ChannelPipeline#addLast() method
+ verify(channelPipeline, times(4)).addLast(any(ChannelHandler.class));
+
+ // verify the order of calling ChannelPipeline#addLast() method
+ InOrder inOrder = inOrder(channelPipeline);
+ inOrder.verify(channelPipeline).addLast(any(HttpRequestDecoder.class));
+ inOrder.verify(channelPipeline).addLast(any(HttpObjectAggregator.class));
+ inOrder.verify(channelPipeline).addLast(any(HttpResponseEncoder.class));
+
+ inOrder.verify(channelPipeline).addLast(any(HttpServerHandler.class));
+ }
+}
diff --git a/sentinel-transport/sentinel-transport-netty-http/src/test/java/com/alibaba/csp/sentinel/transport/command/netty/HttpServerTest.java b/sentinel-transport/sentinel-transport-netty-http/src/test/java/com/alibaba/csp/sentinel/transport/command/netty/HttpServerTest.java
new file mode 100644
index 00000000..dbb213c1
--- /dev/null
+++ b/sentinel-transport/sentinel-transport-netty-http/src/test/java/com/alibaba/csp/sentinel/transport/command/netty/HttpServerTest.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 1999-2018 Alibaba Group Holding 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.alibaba.csp.sentinel.transport.command.netty;
+
+import com.alibaba.csp.sentinel.command.CommandHandler;
+import com.alibaba.csp.sentinel.command.CommandHandlerProvider;
+import com.alibaba.csp.sentinel.command.handler.BasicInfoCommandHandler;
+import com.alibaba.csp.sentinel.command.handler.VersionCommandHandler;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.util.Map;
+
+import static org.junit.Assert.*;
+
+/**
+ * Test cases for {@link HttpServer}.
+ *
+ * @author cdfive
+ * @date 2018-12-19
+ */
+public class HttpServerTest {
+
+ private static HttpServer httpServer;
+
+ @BeforeClass
+ public static void beforeClass() {
+ // note: clear handlerMap first, as other test case may init HttpServer.handlerMap
+ // if not, run mvn test, the next assertEquals(0, HttpServer.handlerMap.size()) may fail
+ HttpServer.handlerMap.clear();
+
+ // create new HttpServer
+ httpServer = new HttpServer();
+
+ // no handler in handlerMap at first
+ assertEquals(0, HttpServer.handlerMap.size());
+ }
+
+ @Before
+ public void before() {
+ // clear handlerMap every method call
+ HttpServer.handlerMap.clear();
+ }
+
+ @Test
+ public void testRegisterCommand() {
+ String commandName;
+ CommandHandler handler;
+
+ // if commandName is null, no handler added in handlerMap
+ commandName = null;
+ handler = new VersionCommandHandler();
+ httpServer.registerCommand(commandName, handler);
+ assertEquals(0, HttpServer.handlerMap.size());
+
+ // if commandName is "", no handler added in handlerMap
+ commandName = "";
+ handler = new VersionCommandHandler();
+ httpServer.registerCommand(commandName, handler);
+ assertEquals(0, HttpServer.handlerMap.size());
+
+ // if handler is null, no handler added in handlerMap
+ commandName = "version";
+ handler = null;
+ httpServer.registerCommand(commandName, handler);
+ assertEquals(0, HttpServer.handlerMap.size());
+
+ // add one handler, commandName:version, handler:VersionCommandHandler
+ commandName = "version";
+ handler = new VersionCommandHandler();
+ httpServer.registerCommand(commandName, handler);
+ assertEquals(1, HttpServer.handlerMap.size());
+
+ // add the same name Handler, no handler added in handlerMap
+ commandName = "version";
+ handler = new VersionCommandHandler();
+ httpServer.registerCommand(commandName, handler);
+ assertEquals(1, HttpServer.handlerMap.size());
+
+ // add another handler, commandName:basicInfo, handler:BasicInfoCommandHandler
+ commandName = "basicInfo";
+ handler = new BasicInfoCommandHandler();
+ httpServer.registerCommand(commandName, handler);
+ assertEquals(2, HttpServer.handlerMap.size());
+ }
+
+ @Test
+ public void testRegisterCommands() {
+ Map handlerMap = null;
+
+ // if handlerMap is null, no handler added in handlerMap
+ httpServer.registerCommands(handlerMap);
+ assertEquals(0, HttpServer.handlerMap.size());
+
+ // add handler from CommandHandlerProvider
+ handlerMap = CommandHandlerProvider.getInstance().namedHandlers();
+ httpServer.registerCommands(handlerMap);
+ // check same size
+ assertEquals(handlerMap.size(), HttpServer.handlerMap.size());
+ // check not same reference
+ assertTrue(handlerMap != HttpServer.handlerMap);
+ }
+}