Skip to content

Commit

Permalink
Add some unit test for sentinel-transport-netty-http module (alibaba#321
Browse files Browse the repository at this point in the history
)
  • Loading branch information
cdfive authored and sczyh30 committed Dec 26, 2018
1 parent f046194 commit 4fbccd8
Show file tree
Hide file tree
Showing 4 changed files with 403 additions and 0 deletions.
10 changes: 10 additions & 0 deletions sentinel-transport/sentinel-transport-netty-http/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -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));
}
}
Loading

0 comments on commit 4fbccd8

Please sign in to comment.