package com.pekall.smartplug.test;
import com.pekall.smartplug.codec.SmartPlugDecoder;
import com.pekall.smartplug.codec.SmartPlugEncoder;
import com.pekall.smartplug.message.BaseMessage;
import com.pekall.smartplug.message.GetStatusRequest;
import com.pekall.smartplug.message.GetStatusResponse;
import com.pekall.smartplug.message.Heartbeat;
import com.pekall.smartplug.message.HelloRequest;
import com.pekall.smartplug.message.HelloResponse;
import com.pekall.smartplug.message.ReportStatusRequest;
import com.pekall.smartplug.message.ReportStatusResponse;
import com.pekall.smartplug.message.SetStatusRequest;
import com.pekall.smartplug.message.SetStatusResponse;
import junit.framework.JUnit4TestAdapter;
import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFactory;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
import org.jboss.netty.channel.group.ChannelGroup;
import org.jboss.netty.channel.group.ChannelGroupFuture;
import org.jboss.netty.channel.group.DefaultChannelGroup;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import java.net.InetSocketAddress;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
public class SmartPlugCodecTestCase {
private static final int SERVER_PORT = 8888;
private static ChannelGroup sAllChannels;
private static ChannelFactory sChannelFactory;
private ClientBootstrap mClientBootstrap;
private Channel mClientChannel;
private static void slog(String msg) {
System.out.println("server --> " + msg);
}
private static void clog(String msg) {
System.out.println("client --> " + msg);
}
private static class ServerHandler extends SimpleChannelUpstreamHandler {
@Override
public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
sAllChannels.add(e.getChannel());
super.channelOpen(ctx, e);
}
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
BaseMessage message = (BaseMessage) e.getMessage();
slog(message.toString());
switch (message.getMessageType()) {
case MSG_HELLO_REQ:
sendHelloResponse(message, e.getChannel());
break;
case MSG_REPORT_STATUS_REQ:
sendReportStatusResponse(message, e.getChannel());
break;
case MSG_GET_STATUS_REQ:
sendGetStatusResponse(message, e.getChannel());
break;
case MSG_SET_STATUS_REQ:
sendSetStatusResponse(message, e.getChannel());
break;
default:
break;
}
}
private void sendSetStatusResponse(BaseMessage message, Channel channel) {
SetStatusResponse response = new SetStatusResponse(message.getMessageId(), (short)0);
channel.write(response);
}
private void sendGetStatusResponse(BaseMessage message, Channel channel) {
GetStatusResponse response = new GetStatusResponse(message.getMessageId(), (short)0);
channel.write(response);
}
private void sendReportStatusResponse(BaseMessage message, Channel channel) {
ReportStatusResponse response = new ReportStatusResponse(message.getMessageId());
channel.write(response);
}
private void sendHelloResponse(BaseMessage request, Channel channel) {
HelloResponse response = new HelloResponse(request.getMessageId(), (short)0, "demo smart plug server");
channel.write(response);
}
}
private static class ClientHandler extends SimpleChannelUpstreamHandler {
// Stateful properties
private volatile Channel channel;
private final BlockingQueue<BaseMessage> answer = new LinkedBlockingQueue<BaseMessage>();
public BaseMessage getResponse(BaseMessage request) {
channel.write(request);
boolean interrupted = false;
BaseMessage response;
for (;;) {
try {
response = answer.take();
break;
} catch (InterruptedException e) {
interrupted = true;
}
}
if (interrupted) {
Thread.currentThread().interrupt();
}
return response;
}
@Override
public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
channel = e.getChannel();
super.channelOpen(ctx, e);
}
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
BaseMessage message = (BaseMessage) e.getMessage();
boolean offered = answer.offer(message);
assert offered;
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
System.out.println("exceptionCaught" + e);
e.getChannel().close();
}
}
@BeforeClass
public static void setUpBeforeClass() throws Exception {
System.out.println("BeforeClass");
sAllChannels = new DefaultChannelGroup("server channels");
sChannelFactory = new NioServerSocketChannelFactory(Executors.newCachedThreadPool(),
Executors.newCachedThreadPool());
ServerBootstrap bootstrap = new ServerBootstrap(sChannelFactory);
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
@Override
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline pipeline = Channels.pipeline();
pipeline.addLast("decoder", new SmartPlugDecoder());
pipeline.addLast("encoder", new SmartPlugEncoder());
pipeline.addLast("handler", new ServerHandler());
return pipeline;
}
});
Channel channel = bootstrap.bind(new InetSocketAddress(SERVER_PORT));
sAllChannels.add(channel);
}
@AfterClass
public static void tearDownAfterClass() throws Exception {
System.out.println("AfterClass");
ChannelGroupFuture future = sAllChannels.close();
future.awaitUninterruptibly();
sChannelFactory.releaseExternalResources();
}
@Before
public void setUp() throws Exception {
System.out.println("Before");
// Set up.
mClientBootstrap = new ClientBootstrap(
new NioClientSocketChannelFactory(
Executors.newCachedThreadPool(),
Executors.newCachedThreadPool()));
// Configure the event pipeline factory.
mClientBootstrap.setPipelineFactory(new ChannelPipelineFactory() {
@Override
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline pipeline = Channels.pipeline();
pipeline.addLast("decoder", new SmartPlugDecoder());
pipeline.addLast("encoder", new SmartPlugEncoder());
pipeline.addLast("handler", new ClientHandler());
return pipeline;
}
});
// Make a new connection.
ChannelFuture connectFuture =
mClientBootstrap.connect(new InetSocketAddress("localhost", SERVER_PORT));
// Wait until the connection is made successfully.
mClientChannel = connectFuture.awaitUninterruptibly().getChannel();
}
@After
public void tearDown() throws Exception {
System.out.println("After");
// Close the connection.
mClientChannel.close().awaitUninterruptibly();
// Shut down all thread pools to exit.
mClientBootstrap.releaseExternalResources();
}
@Test
public void testHello() {
System.out.println("testHello");
// Get the handler instance to initiate the request.
ClientHandler handler = mClientChannel.getPipeline().get(ClientHandler.class);
int messageId = 0;
String deviceId = "123456789";
String deviceMode = "abcdefghi";
HelloRequest request = new HelloRequest(messageId, deviceId, deviceMode);
// Request and get the response.
BaseMessage response = handler.getResponse(request);
clog(response.toString());
Assert.assertEquals(messageId, response.getMessageId());
}
@Test
public void testReportStatus() {
System.out.println("testReportStatus");
// Get the handler instance to initiate the request.
ClientHandler handler = mClientChannel.getPipeline().get(ClientHandler.class);
int messageId = 0;
short status = 0;
ReportStatusRequest request = new ReportStatusRequest(messageId, status);
// Request and get the response.
BaseMessage response = handler.getResponse(request);
clog(response.toString());
}
@Test
public void testGetStatus() {
System.out.println("testGetStatus");
// Get the handler instance to initiate the request.
ClientHandler handler = mClientChannel.getPipeline().get(ClientHandler.class);
int messageId = 0;
GetStatusRequest request = new GetStatusRequest(messageId);
// Request and get the response.
BaseMessage response = handler.getResponse(request);
clog(response.toString());
}
@Test
public void testSetStatus() {
System.out.println("testSetStatus");
// Get the handler instance to initiate the request.
ClientHandler handler = mClientChannel.getPipeline().get(ClientHandler.class);
int messageId = 0;
short status = 1;
SetStatusRequest request = new SetStatusRequest(messageId, status);
// Request and get the response.
BaseMessage response = handler.getResponse(request);
clog(response.toString());
}
@Test
public void testHeartbeat() {
System.out.println("testHeartbeat");
int messageId = 0;
short status = 1;
Heartbeat heartbeat = new Heartbeat(messageId, status);
mClientChannel.write(heartbeat);
}
public static junit.framework.Test suite() {
return new JUnit4TestAdapter(SmartPlugCodecTestCase.class);
}
}