package vnet.sms.gateway.server.framework.channel; import static org.easymock.EasyMock.createNiceMock; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.replay; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.lang.management.ManagementFactory; import javax.management.Notification; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.group.DefaultChannelGroup; import org.jboss.netty.handler.codec.base64.Base64Decoder; import org.jboss.netty.handler.codec.base64.Base64Encoder; import org.jboss.netty.handler.codec.frame.DelimiterBasedFrameDecoder; import org.jboss.netty.handler.codec.serialization.ClassResolvers; import org.jboss.netty.handler.codec.serialization.ObjectDecoder; import org.jboss.netty.handler.codec.serialization.ObjectEncoder; import org.jboss.netty.util.HashedWheelTimer; import org.junit.Test; import org.springframework.jms.core.JmsTemplate; import org.springframework.jmx.export.MBeanExporter; import org.springframework.jmx.export.notification.NotificationPublisher; import org.springframework.jmx.export.notification.UnableToSendNotificationException; import org.springframework.security.authentication.AuthenticationManager; import vnet.sms.common.messages.GsmPdu; import vnet.sms.common.messages.LoginRequest; import vnet.sms.common.messages.LoginResponse; import vnet.sms.common.messages.PingRequest; import vnet.sms.common.messages.PingResponse; import vnet.sms.gateway.nettysupport.login.incoming.ChannelSuccessfullyAuthenticatedEvent; import vnet.sms.gateway.nettysupport.monitor.incoming.InitialChannelEventsMonitor; import vnet.sms.gateway.nettysupport.window.NoWindowForIncomingMessageAvailableEvent; import vnet.sms.gateway.nettytest.embedded.ChannelEventFilters; import vnet.sms.gateway.nettytest.embedded.ChannelPipelineEmbedder; import vnet.sms.gateway.nettytest.embedded.DefaultChannelPipelineEmbedder; import vnet.sms.gateway.server.framework.internal.channel.GatewayServerChannelPipelineFactory; import vnet.sms.gateway.server.framework.internal.jmsbridge.IncomingMessagesForwardingJmsBridge; import vnet.sms.gateway.server.framework.test.AcceptAllAuthenticationManager; import vnet.sms.gateway.server.framework.test.DenyAllAuthenticationManager; import vnet.sms.gateway.server.framework.test.SerialIntegersMessageReferenceGenerator; import vnet.sms.gateway.server.framework.test.SerializationUtils; import vnet.sms.gateway.transports.serialization.ReferenceableMessageContainer; import vnet.sms.gateway.transports.serialization.incoming.SerializationTransportProtocolAdaptingUpstreamChannelHandler; import vnet.sms.gateway.transports.serialization.outgoing.SerializationTransportProtocolAdaptingDownstreamChannelHandler; import com.yammer.metrics.Metrics; public class GatewayServerChannelPipelineFactoryTest { @Test(expected = IllegalArgumentException.class) public final void assertThatConstructorRejectsNullPduType() { final JmsTemplate jmsTemplate = createNiceMock(JmsTemplate.class); new GatewayServerChannelPipelineFactory<Integer, ReferenceableMessageContainer>( "assertThatConstructorRejectsNullPduType", null, new DelimiterBasedFrameDecoder(0, ChannelBuffers.EMPTY_BUFFER), new Base64Decoder(), new Base64Encoder(), new SerializationTransportProtocolAdaptingUpstreamChannelHandler(), new SerializationTransportProtocolAdaptingDownstreamChannelHandler(), new IncomingMessagesForwardingJmsBridge<Integer>(jmsTemplate), 10, 1000L, new AcceptAllAuthenticationManager(), 1000L, new SerialIntegersMessageReferenceGenerator(), 2, 2000L, new MBeanExporter(), new InitialChannelEventsMonitor(), Metrics .defaultRegistry(), new HashedWheelTimer(), new DefaultChannelGroup()); } @Test(expected = IllegalArgumentException.class) public final void assertThatConstructorRejectsNullFrameDecoder() { final JmsTemplate jmsTemplate = createNiceMock(JmsTemplate.class); new GatewayServerChannelPipelineFactory<Integer, ReferenceableMessageContainer>( "assertThatConstructorRejectsNullFrameDecoder", ReferenceableMessageContainer.class, null, new Base64Decoder(), new Base64Encoder(), new SerializationTransportProtocolAdaptingUpstreamChannelHandler(), new SerializationTransportProtocolAdaptingDownstreamChannelHandler(), new IncomingMessagesForwardingJmsBridge<Integer>(jmsTemplate), 10, 1000L, new AcceptAllAuthenticationManager(), 1000L, new SerialIntegersMessageReferenceGenerator(), 2, 2000L, new MBeanExporter(), new InitialChannelEventsMonitor(), Metrics .defaultRegistry(), new HashedWheelTimer(), new DefaultChannelGroup()); } @Test(expected = IllegalArgumentException.class) public final void assertThatConstructorRejectsNullEncoder() { final JmsTemplate jmsTemplate = createNiceMock(JmsTemplate.class); new GatewayServerChannelPipelineFactory<Integer, ReferenceableMessageContainer>( "assertThatConstructorRejectsNullEncoder", ReferenceableMessageContainer.class, new DelimiterBasedFrameDecoder(0, ChannelBuffers.EMPTY_BUFFER), new Base64Decoder(), null, new SerializationTransportProtocolAdaptingUpstreamChannelHandler(), new SerializationTransportProtocolAdaptingDownstreamChannelHandler(), new IncomingMessagesForwardingJmsBridge<Integer>(jmsTemplate), 10, 1000L, new AcceptAllAuthenticationManager(), 1000L, new SerialIntegersMessageReferenceGenerator(), 2, 2000L, new MBeanExporter(), new InitialChannelEventsMonitor(), Metrics .defaultRegistry(), new HashedWheelTimer(), new DefaultChannelGroup()); } @Test(expected = IllegalArgumentException.class) public final void assertThatConstructorRejectsNullTransportProtocolAdpatingUpstreamChannelHandler() { final JmsTemplate jmsTemplate = createNiceMock(JmsTemplate.class); new GatewayServerChannelPipelineFactory<Integer, ReferenceableMessageContainer>( "assertThatConstructorRejectsNullTransportProtocolAdpatingUpstreamChannelHandler", ReferenceableMessageContainer.class, new DelimiterBasedFrameDecoder(0, ChannelBuffers.EMPTY_BUFFER), new Base64Decoder(), new Base64Encoder(), null, new SerializationTransportProtocolAdaptingDownstreamChannelHandler(), new IncomingMessagesForwardingJmsBridge<Integer>(jmsTemplate), 10, 1000L, new AcceptAllAuthenticationManager(), 1000L, new SerialIntegersMessageReferenceGenerator(), 2, 2000L, new MBeanExporter(), new InitialChannelEventsMonitor(), Metrics .defaultRegistry(), new HashedWheelTimer(), new DefaultChannelGroup()); } @Test(expected = IllegalArgumentException.class) public final void assertThatConstructorRejectsNullTransportProtocolAdaptingDownstreamChannelHandler() { final JmsTemplate jmsTemplate = createNiceMock(JmsTemplate.class); new GatewayServerChannelPipelineFactory<Integer, ReferenceableMessageContainer>( "assertThatConstructorRejectsNullTransportProtocolAdaptingDownstreamChannelHandler", ReferenceableMessageContainer.class, new DelimiterBasedFrameDecoder(0, ChannelBuffers.EMPTY_BUFFER), new Base64Decoder(), new Base64Encoder(), new SerializationTransportProtocolAdaptingUpstreamChannelHandler(), null, new IncomingMessagesForwardingJmsBridge<Integer>( jmsTemplate), 10, 1000L, new AcceptAllAuthenticationManager(), 1000L, new SerialIntegersMessageReferenceGenerator(), 2, 2000L, new MBeanExporter(), new InitialChannelEventsMonitor(), Metrics .defaultRegistry(), new HashedWheelTimer(), new DefaultChannelGroup()); } @Test(expected = IllegalArgumentException.class) public final void assertThatConstructorRejectsNullAuthenticationManager() { final JmsTemplate jmsTemplate = createNiceMock(JmsTemplate.class); new GatewayServerChannelPipelineFactory<Integer, ReferenceableMessageContainer>( "assertThatConstructorRejectsNullAuthenticationManager", ReferenceableMessageContainer.class, new DelimiterBasedFrameDecoder(0, ChannelBuffers.EMPTY_BUFFER), new Base64Decoder(), new Base64Encoder(), new SerializationTransportProtocolAdaptingUpstreamChannelHandler(), new SerializationTransportProtocolAdaptingDownstreamChannelHandler(), new IncomingMessagesForwardingJmsBridge<Integer>(jmsTemplate), 10, 1000L, null, 1000L, new SerialIntegersMessageReferenceGenerator(), 2, 2000L, new MBeanExporter(), new InitialChannelEventsMonitor(), Metrics .defaultRegistry(), new HashedWheelTimer(), new DefaultChannelGroup()); } @Test(expected = IllegalArgumentException.class) public final void assertThatConstructorRejectsNullMessageReferenceGenerator() { final JmsTemplate jmsTemplate = createNiceMock(JmsTemplate.class); new GatewayServerChannelPipelineFactory<Integer, ReferenceableMessageContainer>( "assertThatConstructorRejectsNullMessageReferenceGenerator", ReferenceableMessageContainer.class, new DelimiterBasedFrameDecoder(0, ChannelBuffers.EMPTY_BUFFER), new Base64Decoder(), new Base64Encoder(), new SerializationTransportProtocolAdaptingUpstreamChannelHandler(), new SerializationTransportProtocolAdaptingDownstreamChannelHandler(), new IncomingMessagesForwardingJmsBridge<Integer>(jmsTemplate), 10, 1000L, new AcceptAllAuthenticationManager(), 1000L, null, 2, 2000L, new MBeanExporter(), new InitialChannelEventsMonitor(), Metrics.defaultRegistry(), new HashedWheelTimer(), new DefaultChannelGroup()); } @Test(expected = IllegalArgumentException.class) public final void assertThatConstructorRejectsNullMBeanServer() { final JmsTemplate jmsTemplate = createNiceMock(JmsTemplate.class); new GatewayServerChannelPipelineFactory<Integer, ReferenceableMessageContainer>( "assertThatConstructorRejectsNullMBeanServer", ReferenceableMessageContainer.class, new DelimiterBasedFrameDecoder(0, ChannelBuffers.EMPTY_BUFFER), new Base64Decoder(), new Base64Encoder(), new SerializationTransportProtocolAdaptingUpstreamChannelHandler(), new SerializationTransportProtocolAdaptingDownstreamChannelHandler(), new IncomingMessagesForwardingJmsBridge<Integer>(jmsTemplate), 10, 1000L, new AcceptAllAuthenticationManager(), 1000L, new SerialIntegersMessageReferenceGenerator(), 2, 2000L, null, new InitialChannelEventsMonitor(), Metrics.defaultRegistry(), new HashedWheelTimer(), new DefaultChannelGroup()); } @Test(expected = IllegalArgumentException.class) public final void assertThatConstructorRejectsNullChannelGroup() { final JmsTemplate jmsTemplate = createNiceMock(JmsTemplate.class); new GatewayServerChannelPipelineFactory<Integer, ReferenceableMessageContainer>( "assertThatConstructorRejectsNullMBeanServer", ReferenceableMessageContainer.class, new DelimiterBasedFrameDecoder(0, ChannelBuffers.EMPTY_BUFFER), new Base64Decoder(), new Base64Encoder(), new SerializationTransportProtocolAdaptingUpstreamChannelHandler(), new SerializationTransportProtocolAdaptingDownstreamChannelHandler(), new IncomingMessagesForwardingJmsBridge<Integer>(jmsTemplate), 10, 1000L, new AcceptAllAuthenticationManager(), 1000L, new SerialIntegersMessageReferenceGenerator(), 2, 2000L, new MBeanExporter(), new InitialChannelEventsMonitor(), Metrics .defaultRegistry(), new HashedWheelTimer(), null); } @Test(expected = IllegalArgumentException.class) public final void assertThatConstructorRejectsNullInitialChannelEventsMonitor() { final JmsTemplate jmsTemplate = createNiceMock(JmsTemplate.class); new GatewayServerChannelPipelineFactory<Integer, ReferenceableMessageContainer>( "assertThatConstructorRejectsNullMBeanServer", ReferenceableMessageContainer.class, new DelimiterBasedFrameDecoder(0, ChannelBuffers.EMPTY_BUFFER), new Base64Decoder(), new Base64Encoder(), new SerializationTransportProtocolAdaptingUpstreamChannelHandler(), new SerializationTransportProtocolAdaptingDownstreamChannelHandler(), new IncomingMessagesForwardingJmsBridge<Integer>(jmsTemplate), 10, 1000L, new AcceptAllAuthenticationManager(), 1000L, new SerialIntegersMessageReferenceGenerator(), 2, 2000L, new MBeanExporter(), null, Metrics.defaultRegistry(), new HashedWheelTimer(), new DefaultChannelGroup()); } @Test public final void assertThatTheProducedPipelineRespondsWithASuccessfulLoginResponseToASuccessfulLoginRequest() throws Throwable { final int availableIncomingWindows = 10; final long incomingWindowWaitTimeMillis = 1000L; final long failedLoginResponseMillis = 1000L; final int pingIntervalSeconds = 100; final long pingResponseTimeoutMillis = 2000L; final AuthenticationManager authenticationManager = new AcceptAllAuthenticationManager(); final GatewayServerChannelPipelineFactory<Integer, ReferenceableMessageContainer> objectUnderTest = newObjectUnderTest( availableIncomingWindows, incomingWindowWaitTimeMillis, failedLoginResponseMillis, pingIntervalSeconds, pingResponseTimeoutMillis, authenticationManager); final ChannelPipelineEmbedder embeddedPipeline = new DefaultChannelPipelineEmbedder( objectUnderTest); embeddedPipeline.connectChannel(); final LoginRequest successfulLoginRequest = new LoginRequest( "assertThatTheProducedPipelineRespondsWithASuccessfulLoginResponseToASuccessfulLoginRequest", "whatever"); embeddedPipeline.receive(SerializationUtils.serialize(1, successfulLoginRequest)); final MessageEvent encodedLoginResponse = embeddedPipeline .downstreamMessageEvents().nextMessageEvent(); assertNotNull( "Expected channel pipeline to send SendLoginRequestAckEvent to client after successful login, yet it sent NO message in reply", encodedLoginResponse); final GsmPdu decodedLoginResponse = SerializationUtils .deserialize(encodedLoginResponse); assertEquals( "Expected channel pipeline to send LoginResponse to client after successful login, yet it sent a different reply", LoginResponse.class, decodedLoginResponse.getClass()); assertTrue( "Expected channel pipeline to send SUCCESSFUL LoginResponse to client after successful login, yet it sent a FAILED LoginResponse", LoginResponse.class.cast(decodedLoginResponse).loginSucceeded()); } private GatewayServerChannelPipelineFactory<Integer, ReferenceableMessageContainer> newObjectUnderTest( final int availableIncomingWindows, final long incomingWindowWaitTimeMillis, final long failedLoginResponseMillis, final int pingIntervalSeconds, final long pingResponseTimeoutMillis, final AuthenticationManager authenticationManager) { final JmsTemplate jmsTemplate = createNiceMock(JmsTemplate.class); expect(jmsTemplate.getDefaultDestinationName()).andReturn( "queue.test.defaultDestination"); replay(jmsTemplate); final MBeanExporter mbeanExporter = new MBeanExporter(); mbeanExporter.setServer(ManagementFactory.getPlatformMBeanServer()); final NotificationPublisher notPublisher = new NotificationPublisher() { @Override public void sendNotification(final Notification notification) throws UnableToSendNotificationException { } }; final InitialChannelEventsMonitor initialChannelEventsMonitor = new InitialChannelEventsMonitor( notPublisher); return new GatewayServerChannelPipelineFactory<Integer, ReferenceableMessageContainer>( "newObjectUnderTest", ReferenceableMessageContainer.class, new ObjectDecoder(ClassResolvers.cacheDisabled(null)), null, new ObjectEncoder(), new SerializationTransportProtocolAdaptingUpstreamChannelHandler(), new SerializationTransportProtocolAdaptingDownstreamChannelHandler(), new IncomingMessagesForwardingJmsBridge<Integer>(jmsTemplate), availableIncomingWindows, incomingWindowWaitTimeMillis, authenticationManager, failedLoginResponseMillis, new SerialIntegersMessageReferenceGenerator(), pingIntervalSeconds, pingResponseTimeoutMillis, mbeanExporter, initialChannelEventsMonitor, Metrics.defaultRegistry(), new HashedWheelTimer(), new DefaultChannelGroup()); } @Test public final void assertThatTheProducedPipelineRespondsWithAFailedLoginResponseToAFailedLoginRequest() throws Throwable { final int availableIncomingWindows = 10; final long incomingWindowWaitTimeMillis = 1000L; final long failedLoginResponseMillis = 200L; final int pingIntervalSeconds = 100; final long pingResponseTimeoutMillis = 2000L; final AuthenticationManager authenticationManager = new DenyAllAuthenticationManager(); final GatewayServerChannelPipelineFactory<Integer, ReferenceableMessageContainer> objectUnderTest = newObjectUnderTest( availableIncomingWindows, incomingWindowWaitTimeMillis, failedLoginResponseMillis, pingIntervalSeconds, pingResponseTimeoutMillis, authenticationManager); final ChannelPipelineEmbedder embeddedPipeline = new DefaultChannelPipelineEmbedder( objectUnderTest); embeddedPipeline.connectChannel(); final LoginRequest failedLoginRequest = new LoginRequest( "assertThatTheProducedPipelineRespondsWithAFailedLoginResponseToAFailedLoginRequest", "whatever"); embeddedPipeline.receive(SerializationUtils.serialize(1, failedLoginRequest)); Thread.sleep(failedLoginResponseMillis + 100); final MessageEvent encodedLoginResponse = embeddedPipeline .downstreamMessageEvents().nextMessageEvent(); assertNotNull( "Expected channel pipeline to send SendLoginRequestNackEvent to client after failed login, yet it sent NO message in reply", encodedLoginResponse); final GsmPdu decodedLoginResponse = SerializationUtils .deserialize(encodedLoginResponse); assertEquals( "Expected channel pipeline to send LoginResponse to client after failed login, yet it sent a different reply", LoginResponse.class, decodedLoginResponse.getClass()); assertFalse( "Expected channel pipeline to send FAILED LoginResponse to client after failed login, yet it sent a SUCCESSFUL LoginResponse", LoginResponse.class.cast(decodedLoginResponse).loginSucceeded()); } @Test public final void assertThatTheProducedPipelineDelaysResponseToAFailedLoginRequest() throws Throwable { final int availableIncomingWindows = 10; final long incomingWindowWaitTimeMillis = 1000L; final long failedLoginResponseMillis = 400L; final int pingIntervalSeconds = 100; final long pingResponseTimeoutMillis = 2000L; final AuthenticationManager authenticationManager = new DenyAllAuthenticationManager(); final GatewayServerChannelPipelineFactory<Integer, ReferenceableMessageContainer> objectUnderTest = newObjectUnderTest( availableIncomingWindows, incomingWindowWaitTimeMillis, failedLoginResponseMillis, pingIntervalSeconds, pingResponseTimeoutMillis, authenticationManager); final ChannelPipelineEmbedder embeddedPipeline = new DefaultChannelPipelineEmbedder( objectUnderTest); embeddedPipeline.connectChannel(); final LoginRequest failedLoginRequest = new LoginRequest( "assertThatTheProducedPipelineRespondsWithAFailedLoginResponseToAFailedLoginRequest", "whatever"); embeddedPipeline.receive(SerializationUtils.serialize(1, failedLoginRequest)); final MessageEvent noLoginResponseExpectedYet = embeddedPipeline .downstreamMessageEvents().nextMessageEvent(); assertNull( "Expected channel pipeline to delay response to failed login request for " + failedLoginResponseMillis + " milliseconds, yet it immediately sent a response", noLoginResponseExpectedYet); Thread.sleep(failedLoginResponseMillis + 100); final MessageEvent expectedLoginResponse = embeddedPipeline .downstreamMessageEvents().nextMessageEvent(); assertNotNull( "Expected channel pipeline to send SendLoginRequestNackEvent to client after " + failedLoginResponseMillis + " milliseconds, yet it sent NO message in reply", expectedLoginResponse); } @Test public final void assertThatTheProducedPipelineRejectsNonLoginMessagesOnAnUnauthenticatedChannel() throws Throwable { final int availableIncomingWindows = 10; final long incomingWindowWaitTimeMillis = 1000L; final long failedLoginResponseMillis = 200L; final int pingIntervalSeconds = 100; final long pingResponseTimeoutMillis = 2000L; final AuthenticationManager authenticationManager = new DenyAllAuthenticationManager(); final GatewayServerChannelPipelineFactory<Integer, ReferenceableMessageContainer> objectUnderTest = newObjectUnderTest( availableIncomingWindows, incomingWindowWaitTimeMillis, failedLoginResponseMillis, pingIntervalSeconds, pingResponseTimeoutMillis, authenticationManager); final ChannelPipelineEmbedder embeddedPipeline = new DefaultChannelPipelineEmbedder( objectUnderTest); embeddedPipeline.connectChannel(); final PingRequest nonLoginRequest = new PingRequest(); embeddedPipeline.receive(SerializationUtils.serialize(1, nonLoginRequest)); final MessageEvent encodedPingResponse = embeddedPipeline .downstreamMessageEvents().nextMessageEvent(); assertNotNull( "Expected channel pipeline to send (failed) PingResponse to client when receiving a PingRequest on an unauthenticated channel, yet it sent NO message in reply", encodedPingResponse); final GsmPdu decodedPingResponse = SerializationUtils .deserialize(encodedPingResponse); assertEquals( "Expected channel pipeline to send (failed) PingResponse to client after failed login, yet it sent a different reply", PingResponse.class, decodedPingResponse.getClass()); assertFalse( "Expected channel pipeline to send FAILED PingResponse to client after failed login, yet it sent a SUCCESSFUL PingResponse", PingResponse.class.cast(decodedPingResponse).pingSucceeded()); } @Test public final void assertThatTheProducedPipelineSendsFirstPingRequestToClientAfterPingIntervalHasElapsed() throws Throwable { final int availableIncomingWindows = 10; final long incomingWindowWaitTimeMillis = 1000L; final long failedLoginResponseMillis = 400L; final int pingIntervalSeconds = 1; final long pingResponseTimeoutMillis = 10000L; final AuthenticationManager authenticationManager = new DenyAllAuthenticationManager(); final GatewayServerChannelPipelineFactory<Integer, ReferenceableMessageContainer> objectUnderTest = newObjectUnderTest( availableIncomingWindows, incomingWindowWaitTimeMillis, failedLoginResponseMillis, pingIntervalSeconds, pingResponseTimeoutMillis, authenticationManager); final ChannelPipelineEmbedder embeddedPipeline = new DefaultChannelPipelineEmbedder( 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 * 1000L + 100L); final MessageEvent expectedEncodedPingRequst = embeddedPipeline .downstreamMessageEvents().nextMessageEvent(); assertNotNull( "Expected channel pipeline to send PingRequest to client " + pingIntervalSeconds + " seconds after the channel had been connected, yet it sent NO message", expectedEncodedPingRequst); final GsmPdu decodedPingRequest = SerializationUtils .deserialize(expectedEncodedPingRequst); assertEquals( "Expected channel pipeline to send LoginResponse to client after failed login, yet it sent a different reply", PingRequest.class, decodedPingRequest.getClass()); } @Test public final void assertThatTheProducedPipelineContinuesSendingPingRequestsAfterReceivingPingResponse() throws Throwable { final int availableIncomingWindows = 10; final long incomingWindowWaitTimeMillis = 1000L; final long failedLoginResponseMillis = 400L; final int pingIntervalSeconds = 1; final long pingResponseTimeoutMillis = 10000L; final AuthenticationManager authenticationManager = new AcceptAllAuthenticationManager(); final GatewayServerChannelPipelineFactory<Integer, ReferenceableMessageContainer> objectUnderTest = newObjectUnderTest( availableIncomingWindows, incomingWindowWaitTimeMillis, failedLoginResponseMillis, pingIntervalSeconds, pingResponseTimeoutMillis, authenticationManager); // Will fire "channel connected" and thus start ping interval final ChannelPipelineEmbedder embeddedPipeline = new DefaultChannelPipelineEmbedder( objectUnderTest); embeddedPipeline.connectChannel(); // First, authenticate channel since otherwise we won't accept a // PingResponse final LoginRequest successfulLoginRequest = new LoginRequest( "assertThatTheProducedPipelineContinuesSendingPingRequestsAfterReceivingPingResponse", "whatever"); embeddedPipeline.receive(SerializationUtils.serialize(1, successfulLoginRequest)); // Consume LoginResponse - we don't care about it embeddedPipeline.downstreamMessageEvents().nextMessageEvent(); Thread.sleep(pingIntervalSeconds * 1000L + 100L); final MessageEvent expectedInitialPingRequest = embeddedPipeline .downstreamMessageEvents().nextMessageEvent(); assertNotNull( "Expected channel pipeline to send PingRequest to client " + pingIntervalSeconds + " seconds after the channel had been connected, yet it sent NO message", expectedInitialPingRequest); final GsmPdu decodedPingRequest = SerializationUtils .deserialize(expectedInitialPingRequest); assertEquals( "Expected channel pipeline to send PingRequest to client after ping interval has expired, yet it sent a different message", PingRequest.class, decodedPingRequest.getClass()); embeddedPipeline .receive(SerializationUtils.serialize(2, PingResponse .accept(PingRequest.class.cast(decodedPingRequest)))); Thread.sleep(pingIntervalSeconds * 1000L + 100L); final MessageEvent expectedSecondPingRequest = embeddedPipeline .downstreamMessageEvents().nextMessageEvent(); assertNotNull( "Expected channel pipeline to send PingRequest to client " + pingIntervalSeconds + " seconds after receiving a PingResponse, yet it sent NO message", expectedSecondPingRequest); } @Test public final void assertThatTheProducedPipelineIssuesNoWindowForIncomingMessageAvailableEventIfNoWindowIsAvailable() throws Throwable { final int availableIncomingWindows = 10; final long incomingWindowWaitTimeMillis = 1000L; final long failedLoginResponseMillis = 400L; final int pingIntervalSeconds = 1; final long pingResponseTimeoutMillis = 10000L; final AuthenticationManager authenticationManager = new AcceptAllAuthenticationManager(); final GatewayServerChannelPipelineFactory<Integer, ReferenceableMessageContainer> objectUnderTest = newObjectUnderTest( availableIncomingWindows, incomingWindowWaitTimeMillis, failedLoginResponseMillis, pingIntervalSeconds, pingResponseTimeoutMillis, authenticationManager); // Will fire "channel connected" and thus register our // IncomingWindowStore final ChannelPipelineEmbedder embeddedPipeline = new DefaultChannelPipelineEmbedder( objectUnderTest); embeddedPipeline.connectChannel(); // First, authenticate channel since otherwise we won't accept any // incoming messages final LoginRequest successfulLoginRequest = new LoginRequest( "assertThatTheProducedPipelineIssuesNoWindowForIncomingMessageAvailableEventIfNoWindowIsAvailable", "whatever"); embeddedPipeline.receive(SerializationUtils.serialize(1, successfulLoginRequest)); // Discard LoginResponse - we don't care embeddedPipeline.downstreamMessageEvents().nextMessageEvent(); for (int i = 0; i < availableIncomingWindows; i++) { embeddedPipeline.receive(SerializationUtils.serialize((i + 2), new PingRequest())); } embeddedPipeline.receive(SerializationUtils.serialize(12, new PingRequest())); final ChannelEvent propagatedMessageEvent = embeddedPipeline .upstreamChannelEvents() .nextMatchingChannelEvent( ChannelEventFilters .ofType(NoWindowForIncomingMessageAvailableEvent.class)); assertNotNull( "Expected channel pipeline to propagate error event when rejecting incoming message due to no window available", propagatedMessageEvent); assertEquals( "Channel pipeline propagated unexpected event when rejecting incoming message due to no window available", NoWindowForIncomingMessageAvailableEvent.class, propagatedMessageEvent.getClass()); } }