package vnet.sms.gateway.nettysupport.ping.outgoing;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import java.util.concurrent.atomic.AtomicInteger;
import org.jboss.netty.channel.ChannelEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.util.HashedWheelTimer;
import org.junit.Test;
import vnet.sms.common.messages.LoginRequest;
import vnet.sms.common.messages.PingRequest;
import vnet.sms.common.messages.PingResponse;
import vnet.sms.common.wme.send.SendPingRequestEvent;
import vnet.sms.gateway.nettysupport.login.incoming.ChannelSuccessfullyAuthenticatedEvent;
import vnet.sms.gateway.nettysupport.test.ObjectSerializationTransportProtocolAdaptingUpstreamChannelHandler;
import vnet.sms.gateway.nettysupport.window.spi.MessageReferenceGenerator;
import vnet.sms.gateway.nettytest.embedded.ChannelEventFilters;
import vnet.sms.gateway.nettytest.embedded.ChannelPipelineEmbedder;
import vnet.sms.gateway.nettytest.embedded.DefaultChannelPipelineEmbedder;
import com.google.common.base.Predicate;
public class OutgoingPingChannelHandlerTest {
@Test(expected = IllegalArgumentException.class)
public final void assertThatConstructorRejectsNullWindowIdGenerator() {
new OutgoingPingChannelHandler<Integer>(10, 10, null,
new HashedWheelTimer(), new HashedWheelTimer());
}
@Test
public final void assertThatOutgoingPingChannelHandlerSendsPingAfterChannelHasBeenAuthenticatedAndPingIntervalElapsed()
throws Throwable {
final int pingIntervalSeconds = 1;
final int pingTimeoutMillis = 20000;
final OutgoingPingChannelHandler<Integer> objectUnderTest = new OutgoingPingChannelHandler<Integer>(
pingIntervalSeconds, pingTimeoutMillis,
new TestWindowIdGenerator(), new HashedWheelTimer(),
new HashedWheelTimer());
final ChannelPipelineEmbedder embeddedPipeline = new DefaultChannelPipelineEmbedder(
new ObjectSerializationTransportProtocolAdaptingUpstreamChannelHandler(),
objectUnderTest);
embeddedPipeline.connectChannel();
// Simulate successful channel authentication => we start to ping after
// pingIntervalSeconds
embeddedPipeline
.injectUpstreamChannelEvent(new ChannelSuccessfullyAuthenticatedEvent(
embeddedPipeline.getChannel(),
new LoginRequest(
"assertThatOutgoingPingChannelHandlerSendsPingAfterChannelHasBeenAuthenticatedAndPingIntervalElapsed",
"password")));
Thread.sleep(pingIntervalSeconds * 1000 + 100);
final MessageEvent pingRequestCandidate = embeddedPipeline
.downstreamMessageEvents().nextMessageEvent();
assertNotNull(
"OutgoingPingChannelHandler did not send any message after channel has been authenticated and ping interval elapsed",
pingRequestCandidate);
assertEquals(
"OutgoingPingChannelHandler sent wrong message event after channel has been authenticated and ping interval elapsed",
SendPingRequestEvent.class, pingRequestCandidate.getClass());
}
@Test
public final void assertThatOutgoingPingChannelHandlerSendsStarteToPingEventUpstreamAfterChannelHasBeenAuthenticatedAndPingIntervalElapsed()
throws Throwable {
final int pingIntervalSeconds = 1;
final int pingTimeoutMillis = 20000;
final OutgoingPingChannelHandler<Integer> objectUnderTest = new OutgoingPingChannelHandler<Integer>(
pingIntervalSeconds, pingTimeoutMillis,
new TestWindowIdGenerator(), new HashedWheelTimer(),
new HashedWheelTimer());
final ChannelPipelineEmbedder embeddedPipeline = new DefaultChannelPipelineEmbedder(
new ObjectSerializationTransportProtocolAdaptingUpstreamChannelHandler(),
objectUnderTest);
embeddedPipeline.connectChannel();
// Simulate successful channel authentication => we start to ping after
// pingIntervalSeconds
embeddedPipeline
.injectUpstreamChannelEvent(new ChannelSuccessfullyAuthenticatedEvent(
embeddedPipeline.getChannel(),
new LoginRequest(
"assertThatOutgoingPingChannelHandlerSendsStarteToPingEventUpstreamAfterChannelHasBeenAuthenticatedAndPingIntervalElapsed",
"password")));
Thread.sleep(pingIntervalSeconds * 1000 + 100);
final ChannelEvent startedToPing = embeddedPipeline
.upstreamChannelEvents().nextMatchingChannelEvent(
new Predicate<ChannelEvent>() {
@Override
public boolean apply(final ChannelEvent event) {
return event instanceof StartedToPingEvent;
}
});
assertNotNull(
"OutgoingPingChannelHandler did not send "
+ StartedToPingEvent.class.getName()
+ " after channel has been authenticated and ping interval elapsed",
startedToPing);
}
@Test
public final void assertThatOutgoingPingChannelHandlerSendsNoPingResponseReceivedWithinTimeoutEventUpstreamIfPingResponseTimeoutExpires()
throws Throwable {
final int pingIntervalSeconds = 1;
final int pingTimeoutMillis = 1000;
final OutgoingPingChannelHandler<Integer> objectUnderTest = new OutgoingPingChannelHandler<Integer>(
pingIntervalSeconds, pingTimeoutMillis,
new TestWindowIdGenerator(), new HashedWheelTimer(),
new HashedWheelTimer());
final ChannelPipelineEmbedder embeddedPipeline = new DefaultChannelPipelineEmbedder(
new ObjectSerializationTransportProtocolAdaptingUpstreamChannelHandler(),
objectUnderTest);
embeddedPipeline.connectChannel();
// Simulate successful channel authentication => we start to ping after
// pingIntervalSeconds
embeddedPipeline
.injectUpstreamChannelEvent(new ChannelSuccessfullyAuthenticatedEvent(
embeddedPipeline.getChannel(),
new LoginRequest(
"assertThatOutgoingPingChannelHandlerSendsNoPingResponseReceivedWithinTimeoutEventUpstreamIfPingResponseTimeoutExpires",
"password")));
Thread.sleep(pingIntervalSeconds * 1000 + pingTimeoutMillis + 100);
final MessageEvent pingRequestCandidate = embeddedPipeline
.downstreamMessageEvents().nextMessageEvent();
assertNotNull(
"OutgoingPingChannelHandler did not send any message after channel has been connected and ping interval elapsed",
pingRequestCandidate);
Thread.sleep(pingTimeoutMillis + 100);
final ChannelEvent noPingResponseReceived = embeddedPipeline
.upstreamChannelEvents().nextMatchingChannelEvent(
ChannelEventFilters
.ofType(PingResponseTimeoutExpiredEvent.class));
assertNotNull(
"OutgoingPingChannelHandler did not send expected PingResponseTimeoutExpiredEvent although ping response timeout expired",
noPingResponseReceived);
}
@Test
public final void assertThatOutgoingPingChannelHandlerDoesNotSendNoPingResponseReceivedWithinTimeoutEventUpstreamIfItReceivesPingResponseWithinTimeout()
throws Throwable {
final int pingIntervalSeconds = 1;
final int pingTimeoutMillis = 1000;
final OutgoingPingChannelHandler<Integer> objectUnderTest = new OutgoingPingChannelHandler<Integer>(
pingIntervalSeconds, pingTimeoutMillis,
new TestWindowIdGenerator(), new HashedWheelTimer(),
new HashedWheelTimer());
final ChannelPipelineEmbedder embeddedPipeline = new DefaultChannelPipelineEmbedder(
new ObjectSerializationTransportProtocolAdaptingUpstreamChannelHandler(),
objectUnderTest);
embeddedPipeline.connectChannel();
// Simulate successful channel authentication => we start to ping after
// pingIntervalSeconds
embeddedPipeline
.injectUpstreamChannelEvent(new ChannelSuccessfullyAuthenticatedEvent(
embeddedPipeline.getChannel(),
new LoginRequest(
"assertThatOutgoingPingChannelHandlerDoesNotSendNoPingResponseReceivedWithinTimeoutEventUpstreamIfItReceivesPingResponseWithinTimeout",
"password")));
Thread.sleep(pingIntervalSeconds * 1000 + 200);
final MessageEvent pingRequestCandidate = embeddedPipeline
.downstreamMessageEvents().nextMessageEvent();
assertNotNull(
"OutgoingPingChannelHandler did not send any message after channel has been connected and ping interval elapsed",
pingRequestCandidate);
embeddedPipeline.receive(PingResponse
.accept((PingRequest) pingRequestCandidate.getMessage()));
Thread.sleep(pingTimeoutMillis + 100);
final ChannelEvent noPingResponseReceived = embeddedPipeline
.upstreamChannelEvents().nextMatchingChannelEvent(
ChannelEventFilters
.ofType(PingResponseTimeoutExpiredEvent.class));
assertNull(
"OutgoingPingChannelHandler sent unexpected PingResponseTimeoutExpiredEvent although it received a ping response within timeout",
noPingResponseReceived);
}
private static final class TestWindowIdGenerator implements
MessageReferenceGenerator<Integer> {
private final AtomicInteger nextId = new AtomicInteger();
@Override
public Integer nextMessageReference() {
return this.nextId.incrementAndGet();
}
}
}