Browse Source

Add some unit test for sentinel-transport-netty-http module (#321)

master
cdfive Eric Zhao 6 years ago
parent
commit
4fbccd879b
4 changed files with 403 additions and 0 deletions
  1. +10
    -0
      sentinel-transport/sentinel-transport-netty-http/pom.xml
  2. +212
    -0
      sentinel-transport/sentinel-transport-netty-http/src/test/java/com/alibaba/csp/sentinel/transport/command/netty/HttpServerHandlerTest.java
  3. +64
    -0
      sentinel-transport/sentinel-transport-netty-http/src/test/java/com/alibaba/csp/sentinel/transport/command/netty/HttpServerInitializerTest.java
  4. +117
    -0
      sentinel-transport/sentinel-transport-netty-http/src/test/java/com/alibaba/csp/sentinel/transport/command/netty/HttpServerTest.java

+ 10
- 0
sentinel-transport/sentinel-transport-netty-http/pom.xml View File

@@ -41,5 +41,15 @@
<artifactId>httpcore</artifactId>
<version>4.4.5</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

+ 212
- 0
sentinel-transport/sentinel-transport-netty-http/src/test/java/com/alibaba/csp/sentinel/transport/command/netty/HttpServerHandlerTest.java View File

@@ -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<FlowRule> rules = new ArrayList<FlowRule>();
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);
}
}

+ 64
- 0
sentinel-transport/sentinel-transport-netty-http/src/test/java/com/alibaba/csp/sentinel/transport/command/netty/HttpServerInitializerTest.java View File

@@ -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));
}
}

+ 117
- 0
sentinel-transport/sentinel-transport-netty-http/src/test/java/com/alibaba/csp/sentinel/transport/command/netty/HttpServerTest.java View File

@@ -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<String, CommandHandler> 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);
}
}

Loading…
Cancel
Save