package vnet.sms.gateway.nettysupport.window;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import org.jboss.netty.channel.ChannelEvent;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelDownstreamHandler;
import org.junit.Test;
import vnet.sms.common.messages.GsmPdu;
import vnet.sms.common.messages.LoginRequest;
import vnet.sms.common.messages.Msisdn;
import vnet.sms.common.messages.Sms;
import vnet.sms.common.wme.acknowledge.SendSmsAckContainer;
import vnet.sms.common.wme.acknowledge.SendSmsAckEvent;
import vnet.sms.common.wme.acknowledge.SendSmsNackContainer;
import vnet.sms.common.wme.acknowledge.SendSmsNackEvent;
import vnet.sms.common.wme.receive.ReceivedSmsEvent;
import vnet.sms.gateway.nettysupport.test.ObjectSerializationTransportProtocolAdaptingUpstreamChannelHandler;
import vnet.sms.gateway.nettysupport.window.incoming.IncomingWindowStore;
import vnet.sms.gateway.nettytest.embedded.ChannelEventFilters;
import vnet.sms.gateway.nettytest.embedded.ChannelPipelineEmbedder;
import vnet.sms.gateway.nettytest.embedded.DefaultChannelPipelineEmbedder;
import com.yammer.metrics.Metrics;
public class WindowingChannelHandlerTest {
@Test
public final void assertThatWindowedChannelHandlerCorrectlyPropagatesLoginRequest()
throws Throwable {
final WindowingChannelHandler<Integer> objectUnderTest = new WindowingChannelHandler<Integer>(
new IncomingWindowStore<Integer>(100, 1000),
Metrics.defaultRegistry());
final ChannelPipelineEmbedder embeddedPipeline = new DefaultChannelPipelineEmbedder(
new ObjectSerializationTransportProtocolAdaptingUpstreamChannelHandler(),
objectUnderTest);
embeddedPipeline.connectChannel();
embeddedPipeline
.receive(new LoginRequest(
"assertThatWindowedChannelHandlerCorrectlyPropagatesLoginRequest",
"secret"));
final MessageEvent propagatedMessageEvent = embeddedPipeline
.upstreamMessageEvents().nextMessageEvent();
assertNotNull("WindowingChannelHandler did not propagate LoginRequest",
propagatedMessageEvent);
assertEquals(
"WindowingChannelHandler converted LoginRequest to unexpected output",
LoginRequest.class, propagatedMessageEvent.getMessage()
.getClass());
}
@Test
public final void assertThatWindowedChannelHandlerIssuesNoWindowForIncomingMessageAvailableEventIfNoWindowIsAvailable()
throws Throwable {
final LoginRequest loginRequest = new LoginRequest(
"assertThatWindowedChannelHandlerIssuesNoWindowForIncomingMessageEventIfNoWindowIsAvailable",
"secret");
final WindowingChannelHandler<Integer> objectUnderTest = new WindowingChannelHandler<Integer>(
new IncomingWindowStore<Integer>(1, 1),
Metrics.defaultRegistry());
final ChannelPipelineEmbedder embeddedPipeline = new DefaultChannelPipelineEmbedder(
new ObjectSerializationTransportProtocolAdaptingUpstreamChannelHandler(),
objectUnderTest);
embeddedPipeline.connectChannel();
embeddedPipeline.receive(loginRequest);
embeddedPipeline.upstreamMessageEvents().nextMessageEvent();
embeddedPipeline.receive(loginRequest);
final ChannelEvent propagatedMessageEvent = embeddedPipeline
.upstreamChannelEvents()
.nextMatchingChannelEvent(
ChannelEventFilters
.ofType(NoWindowForIncomingMessageAvailableEvent.class));
assertNotNull(
"WindowingChannelHandler did not propagate error event when rejecting incoming message due to no window available",
propagatedMessageEvent);
assertEquals(
"WindowingChannelHandler propagated unexpected event when rejecting incoming message due to no window available",
NoWindowForIncomingMessageAvailableEvent.class,
propagatedMessageEvent.getClass());
}
@Test
public final void assertThatWindowedChannelHandlerStoresReceivedSmsInIncomingWindowingStore()
throws Throwable {
final IncomingWindowStore<Integer> incomingWindowStore = new IncomingWindowStore<Integer>(
100, 1000);
final WindowingChannelHandler<Integer> objectUnderTest = new WindowingChannelHandler<Integer>(
incomingWindowStore, Metrics.defaultRegistry());
final ChannelPipelineEmbedder embeddedPipeline = new DefaultChannelPipelineEmbedder(
new ObjectSerializationTransportProtocolAdaptingUpstreamChannelHandler(),
objectUnderTest);
embeddedPipeline.connectChannel();
final Sms receivedSms = new Sms(new Msisdn("01686754432"), new Msisdn(
"01686754432"),
"assertThatWindowedChannelHandlerStoresReceivedSmsInIncomingWindowingStore");
embeddedPipeline.receive(receivedSms);
final MessageEvent propagatedMessageEvent = embeddedPipeline
.upstreamMessageEvents().nextMessageEvent();
assertNotNull("WindowingChannelHandler did not propagate Sms",
propagatedMessageEvent);
assertEquals(
"WindowingChannelHandler converted Sms to unexpected output",
ReceivedSmsEvent.class, propagatedMessageEvent.getClass());
final Integer messageRef = (Integer) ReceivedSmsEvent.class.cast(
propagatedMessageEvent).getMessageReference();
final GsmPdu storedMessage = incomingWindowStore
.releaseWindow(messageRef);
assertEquals(
"WindowingChannelHandler did not store received SMS in incoming windowing store but some other message",
receivedSms, storedMessage);
}
@Test
public final void assertThatWindowedChannelHandlerReleasesSmsStoredInIncomingWindowingStoreWhenReceivingAnAck()
throws Throwable {
final IncomingWindowStore<Integer> incomingWindowStore = new IncomingWindowStore<Integer>(
100, 1000);
final WindowingChannelHandler<Integer> objectUnderTest = new WindowingChannelHandler<Integer>(
incomingWindowStore, Metrics.defaultRegistry());
final SimpleChannelDownstreamHandler converterHandler = new SimpleChannelDownstreamHandler() {
@Override
public void writeRequested(final ChannelHandlerContext ctx,
final MessageEvent e) throws Exception {
final SendSmsAckEvent<Integer> ackedEvent = SendSmsAckEvent
.convert(e);
ctx.sendDownstream(ackedEvent);
}
};
final ChannelPipelineEmbedder embeddedPipeline = new DefaultChannelPipelineEmbedder(
new ObjectSerializationTransportProtocolAdaptingUpstreamChannelHandler(),
objectUnderTest, converterHandler);
embeddedPipeline.connectChannel();
final Sms receivedSms = new Sms(
new Msisdn("01686754432"),
new Msisdn("01686754432"),
"assertThatWindowedChannelHandlerReleasesSmsStoredInIncomingWindowingStoreWhenReceivingAnAck");
embeddedPipeline.receive(receivedSms);
assertEquals(
"WindowingChannelHandler should have stored received SMS in incoming windowing store",
1, incomingWindowStore.getCurrentMessageCount());
final MessageEvent propagatedMessageEvent = embeddedPipeline
.upstreamMessageEvents().nextMessageEvent();
final Integer messageRef = (Integer) ReceivedSmsEvent.class.cast(
propagatedMessageEvent).getMessageReference();
embeddedPipeline.send(new SendSmsAckContainer<Integer>(messageRef, 0,
receivedSms));
assertEquals(
"WindowingChannelHandler should have released received SMS when processing an Ack for that SMS",
0, incomingWindowStore.getCurrentMessageCount());
}
@Test
public final void assertThatWindowedChannelHandlerPropagatesFailedToReleaseAcknowledgedMessageEventUpstreamIfReleasedMessagesDoNotMatch()
throws Throwable {
final IncomingWindowStore<Integer> incomingWindowStore = new IncomingWindowStore<Integer>(
100, 1000);
final WindowingChannelHandler<Integer> objectUnderTest = new WindowingChannelHandler<Integer>(
incomingWindowStore, Metrics.defaultRegistry());
final SimpleChannelDownstreamHandler converterHandler = new SimpleChannelDownstreamHandler() {
@Override
public void writeRequested(final ChannelHandlerContext ctx,
final MessageEvent e) throws Exception {
final SendSmsAckEvent<Integer> ackedEvent = SendSmsAckEvent
.convert(e);
ctx.sendDownstream(ackedEvent);
}
};
final ChannelPipelineEmbedder embeddedPipeline = new DefaultChannelPipelineEmbedder(
new ObjectSerializationTransportProtocolAdaptingUpstreamChannelHandler(),
objectUnderTest, converterHandler);
embeddedPipeline.connectChannel();
final Sms smsToAcknowledge = new Sms(
new Msisdn("01686754432"),
new Msisdn("01686754432"),
"assertThatWindowedChannelHandlerPropagatesFailedToReleaseAcknowledgedMessageEventUpstreamIfReleasedMessagesDoNotMatch");
embeddedPipeline.receive(smsToAcknowledge);
assertEquals(
"WindowingChannelHandler should have stored received SMS in incoming windowing store",
1, incomingWindowStore.getCurrentMessageCount());
final MessageEvent propagatedMessageEvent = embeddedPipeline
.upstreamMessageEvents().nextMessageEvent();
final Sms actuallyAcknowledgedSms = new Sms(new Msisdn("01686754432"),
new Msisdn("01686754432"), "actually");
final Integer messageRef = (Integer) ReceivedSmsEvent.class.cast(
propagatedMessageEvent).getMessageReference();
embeddedPipeline.send(new SendSmsAckContainer<Integer>(messageRef, 0,
actuallyAcknowledgedSms));
final ChannelEvent expectedFailedToReleaseEvent = embeddedPipeline
.upstreamChannelEvents()
.nextMatchingChannelEvent(
ChannelEventFilters
.ofType(FailedToReleaseAcknowledgedMessageEvent.class));
assertNotNull(
"WindowingChannelHandler should have sent a "
+ FailedToReleaseAcknowledgedMessageEvent.class
.getName()
+ " upstream when realizing that the released SMS is not the formerly stored SMS",
expectedFailedToReleaseEvent);
}
@Test
public final void assertThatWindowedChannelHandlerReleasesSmsStoredInIncomingWindowingStoreWhenReceivingANack()
throws Throwable {
final IncomingWindowStore<Integer> incomingWindowStore = new IncomingWindowStore<Integer>(
100, 1000);
final WindowingChannelHandler<Integer> objectUnderTest = new WindowingChannelHandler<Integer>(
incomingWindowStore, Metrics.defaultRegistry());
final SimpleChannelDownstreamHandler converterHandler = new SimpleChannelDownstreamHandler() {
@Override
public void writeRequested(final ChannelHandlerContext ctx,
final MessageEvent e) throws Exception {
final SendSmsNackEvent<Integer> nackedEvent = SendSmsNackEvent
.convert(e);
ctx.sendDownstream(nackedEvent);
}
};
final ChannelPipelineEmbedder embeddedPipeline = new DefaultChannelPipelineEmbedder(
new ObjectSerializationTransportProtocolAdaptingUpstreamChannelHandler(),
objectUnderTest, converterHandler);
embeddedPipeline.connectChannel();
final Sms receivedSms = new Sms(
new Msisdn("01686754432"),
new Msisdn("01686754432"),
"assertThatWindowedChannelHandlerReleasesSmsStoredInIncomingWindowingStoreWhenReceivingANack");
embeddedPipeline.receive(receivedSms);
assertEquals(
"WindowingChannelHandler should have stored received SMS in incoming windowing store",
1, incomingWindowStore.getCurrentMessageCount());
final MessageEvent propagatedMessageEvent = embeddedPipeline
.upstreamMessageEvents().nextMessageEvent();
final Integer messageRef = (Integer) ReceivedSmsEvent.class.cast(
propagatedMessageEvent).getMessageReference();
embeddedPipeline
.send(new SendSmsNackContainer<Integer>(
1,
"assertThatWindowedChannelHandlerReleasesSmsStoredInIncomingWindowingStoreWhenReceivingANack",
messageRef, 0, receivedSms));
assertEquals(
"WindowingChannelHandler should have released received SMS when processing an Nack for that SMS",
0, incomingWindowStore.getCurrentMessageCount());
}
@Test
public final void assertThatWindowedChannelHandlerPropagatesFailedToReleaseAcknowledgedMessageEventUpstreamIfMessageReferenceIsUnknown()
throws Throwable {
final IncomingWindowStore<Integer> incomingWindowStore = new IncomingWindowStore<Integer>(
100, 1000);
final WindowingChannelHandler<Integer> objectUnderTest = new WindowingChannelHandler<Integer>(
incomingWindowStore, Metrics.defaultRegistry());
final SimpleChannelDownstreamHandler converterHandler = new SimpleChannelDownstreamHandler() {
@Override
public void writeRequested(final ChannelHandlerContext ctx,
final MessageEvent e) throws Exception {
final SendSmsAckEvent<Integer> ackedEvent = SendSmsAckEvent
.convert(e);
ctx.sendDownstream(ackedEvent);
}
};
final ChannelPipelineEmbedder embeddedPipeline = new DefaultChannelPipelineEmbedder(
new ObjectSerializationTransportProtocolAdaptingUpstreamChannelHandler(),
objectUnderTest, converterHandler);
embeddedPipeline.connectChannel();
final Sms smsToAcknowledge = new Sms(
new Msisdn("01686754432"),
new Msisdn("01686754432"),
"assertThatWindowedChannelHandlerPropagatesFailedToReleaseAcknowledgedMessageEventUpstreamIfMessageReferenceIsUnknown");
embeddedPipeline.receive(smsToAcknowledge);
assertEquals(
"WindowingChannelHandler should have stored received SMS in incoming windowing store",
1, incomingWindowStore.getCurrentMessageCount());
final MessageEvent propagatedMessageEvent = embeddedPipeline
.upstreamMessageEvents().nextMessageEvent();
final Integer messageRef = (Integer) ReceivedSmsEvent.class.cast(
propagatedMessageEvent).getMessageReference();
embeddedPipeline.send(new SendSmsAckContainer<Integer>(messageRef + 1,
0, smsToAcknowledge));
final ChannelEvent expectedFailedToReleaseEvent = embeddedPipeline
.upstreamChannelEvents()
.nextMatchingChannelEvent(
ChannelEventFilters
.ofType(FailedToReleaseAcknowledgedMessageEvent.class));
assertNotNull(
"WindowingChannelHandler should have sent a "
+ FailedToReleaseAcknowledgedMessageEvent.class
.getName()
+ " upstream when realizing that the supplied message reference is unknown",
expectedFailedToReleaseEvent);
}
}