package org.neo4j.smack.pipeline.http;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.buffer.HeapChannelBufferFactory;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelConfig;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.MessageEvent;
import org.junit.Test;
import org.neo4j.smack.pipeline.core.WorkPublisher;
import org.neo4j.smack.pipeline.http.HttpDecoder;
import org.neo4j.smack.pipeline.http.HttpTokens;
import org.neo4j.smack.routing.InvocationVerb;
public class TestHttpDecoder {
class Request
{
public Request(Long connectionId, InvocationVerb verb, String path, ChannelBuffer content, Channel channel, boolean keepAlive)
{
this.connectionId = connectionId;
this.verb = verb;
this.path = path;
this.content = content;
this.channel = channel;
this.keepAlive = keepAlive;
}
public Long connectionId;
public InvocationVerb verb;
public String path;
public ChannelBuffer content;
public Channel channel;
public boolean keepAlive;
}
class RequestMatcher
{
public Long connectionId;
public InvocationVerb verb;
public String path;
public byte [] content;
public Channel channel;
public boolean keepAlive;
public RequestMatcher(InvocationVerb verb, String path)
{
this(verb, path, new byte[]{}, null, true);
}
public RequestMatcher(InvocationVerb verb, String path, String message) throws UnsupportedEncodingException
{
this(verb, path, message.getBytes("UTF-8"), null, true);
}
public RequestMatcher(InvocationVerb verb, String path, byte[] content, Channel channel, boolean keepAlive)
{
this.connectionId = connectionId;
this.verb = verb;
this.path = path;
this.content = content;
this.channel = channel;
this.keepAlive = keepAlive;
}
public void assertMatches(Request work)
{
assertThat(work.verb, is(verb));
assertThat(work.path, is(path));
assertThat(work.keepAlive, is(keepAlive));
assertThat(work.content.readableBytes(),is(content.length));
}
}
class DummyInputGate implements WorkPublisher
{
ArrayList<Request> requests = new ArrayList<Request>();
@Override
public void addWork(Long connectionId, InvocationVerb verb,
String path, ChannelBuffer content, Channel channel,
boolean keepAlive)
{
Request work = new Request(connectionId,verb,path,content,channel,keepAlive);
requests.add(work);
}
@Override
public void addFailure(Long connectionId, Channel channel,
Throwable cause)
{
// TODO Auto-generated method stub
}
}
@Test
public void shouldDecodeSimpleMessage() throws Exception
{
ChannelBuffer buf = ChannelBuffers.dynamicBuffer();
buf.writeBytes("GET / HTTP/1.1".getBytes("ASCII"));
buf.writeByte(HttpTokens.CR);
buf.writeByte(HttpTokens.LF);
buf.writeBytes("Content-Length: 0".getBytes("ASCII"));
buf.writeByte(HttpTokens.CR);
buf.writeByte(HttpTokens.LF);
buf.writeByte(HttpTokens.CR);
buf.writeByte(HttpTokens.LF);
testDecoding(buf, new RequestMatcher(InvocationVerb.GET, "/"));
}
@Test
public void shouldDecodeMessageWithBody() throws Exception
{
ChannelBuffer buf = ChannelBuffers.dynamicBuffer();
String message = "{\"hello\":\"world!\"}";
byte[] messageBytes = message.getBytes("UTF-8");
buf.writeBytes("GET / HTTP/1.1".getBytes("ASCII"));
buf.writeByte(HttpTokens.CR);
buf.writeByte(HttpTokens.LF);
buf.writeBytes(("Content-Length: " + messageBytes.length).getBytes("ASCII"));
buf.writeByte(HttpTokens.CR);
buf.writeByte(HttpTokens.LF);
buf.writeByte(HttpTokens.CR);
buf.writeByte(HttpTokens.LF);
buf.writeBytes(messageBytes);
buf.writeByte(HttpTokens.CR);
buf.writeByte(HttpTokens.LF);
testDecoding(buf, new RequestMatcher(InvocationVerb.GET, "/", message));
}
private void testDecoding(ChannelBuffer buf, RequestMatcher ... requestMatchers) throws Exception
{
DummyInputGate inputGate = new DummyInputGate();
HttpDecoder decoder = new HttpDecoder(inputGate);
MessageEvent msg = mock(MessageEvent.class);
when(msg.getMessage()).thenReturn(buf);
ChannelConfig channelConfig = mock(ChannelConfig.class);
when(channelConfig.getBufferFactory()).thenReturn(new HeapChannelBufferFactory());
Channel channel = mock(Channel.class);
when(channel.getConfig()).thenReturn(channelConfig);
ChannelHandlerContext ctx = mock(ChannelHandlerContext.class);
when(ctx.getChannel()).thenReturn(channel);
// Decode
decoder.messageReceived(ctx, msg);
// Check result
assertThat("Should yield "+requestMatchers.length+" input requests", inputGate.requests.size(), is(requestMatchers.length));
for(int i=0;i<requestMatchers.length;i++) {
requestMatchers[i].assertMatches(inputGate.requests.get(i));
}
}
}