package vnet.sms.gateway.server.framework; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.ObjectMessage; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 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.server.framework.dummy.DummyAuthenticationProvider; import vnet.sms.gateway.server.framework.test.ForwardingJmsMessageListener; import vnet.sms.gateway.server.framework.test.IntegrationTestClient; import vnet.sms.gateway.server.framework.test.JmsMessagePredicate; import vnet.sms.gateway.transports.serialization.ReferenceableMessageContainer; @RunWith(SpringJUnit4ClassRunner.class) @ActiveProfiles("itest") @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) @ContextConfiguration({ "classpath:META-INF/services/gateway-server-application-context.xml", "classpath:META-INF/services/gateway-server-authentication-manager-context.xml", "classpath:META-INF/services/gateway-server-jms-client-context.xml", "classpath:META-INF/services/gateway-server-shell-context.xml", "classpath*:META-INF/module/module-context.xml", "classpath:META-INF/itest/itest-gateway-server-embedded-activemq-broker-context.xml", "classpath:META-INF/itest/itest-serialization-transport-plugin-context.xml", "classpath:META-INF/itest/itest-test-client-context.xml", "classpath:META-INF/itest/itest-test-jms-listener-context.xml", "classpath:META-INF/itest/itest-gateway-server-description-context.xml" }) public class LoginIT { @Autowired private IntegrationTestClient testClient; @Autowired private GatewayServer<Integer, ReferenceableMessageContainer> gatewayServer; @Autowired private ForwardingJmsMessageListener incomingMessagesListener; @Value("#{ '${gateway.server.failedLoginResponseDelayMillis}' }") private long failedLoginResponseMillis; @Test public final void assertThatGatewayServerIsInStateRUNNINGAfterApplicationContextLoad() throws Exception { assertEquals( "Initialization of ApplicationContext should started GatewayServer", ServerStatus.RUNNING, this.gatewayServer.getCurrentStatus()); } @Test public final void assertThatGatewayServerRespondsWithASuccessfulLoginResponseToASuccessfulLoginRequest() throws Throwable { final int messageReference = 1; final LoginRequest successfulLoginRequest = new LoginRequest( "assertThatGatewayServerRespondsWithASuccessfulLoginResponseToASuccessfulLoginRequest", "whatever"); this.testClient.connect(); final ReferenceableMessageContainer response = this.testClient .sendMessageAndWaitForResponse(messageReference, successfulLoginRequest); this.testClient.disconnect(); assertEquals( "GatewayServer should have returned messageReference of LoginRequest passed in", messageReference, response.getMessageReference()); assertEquals("GatewayServer should have returned LoginResponse", LoginResponse.class, response.getMessage().getClass()); assertTrue( "GatewayServer should have returned a SUCCESSFUL LoginResponse", LoginResponse.class.cast(response.getMessage()) .loginSucceeded()); } @Test public final void assertThatGatewayServerRespondsWithAFailedLoginResponseToAFailedLoginRequest() throws Throwable { final int messageReference = 1; final LoginRequest failedLoginRequest = new LoginRequest( "assertThatGatewayServerRespondsWithAFailedLoginResponseToAFailedLoginRequest", DummyAuthenticationProvider.REJECTED_PASSWORD); this.testClient.connect(); final ReferenceableMessageContainer response = this.testClient .sendMessageAndWaitForResponse(messageReference, failedLoginRequest); this.testClient.disconnect(); assertEquals( "GatewayServer should have returned messageReference of LoginRequest passed in", messageReference, response.getMessageReference()); assertEquals("GatewayServer should have returned LoginResponse", LoginResponse.class, response.getMessage().getClass()); assertFalse( "GatewayServer should have returned a FAILED LoginResponse", LoginResponse.class.cast(response.getMessage()) .loginSucceeded()); } @Test public final void assertThatGatewayServerForwardsSuccessfulLoginRequestToJmsServer() throws Throwable { final int messageReference = 1; final String username = "assertThatGatewayServerForwardsSuccessfulLoginRequestToJmsServer"; final LoginRequest successfulLoginRequest = new LoginRequest(username, "whatever"); final JmsMessagePredicate isExpectedLoginRequest = new JmsMessagePredicate() { @Override public boolean evaluate(final Message msg) { try { if (!(msg instanceof ObjectMessage)) { return false; } final ObjectMessage omsg = ObjectMessage.class.cast(msg); final Object payload = omsg.getObject(); if (!(payload instanceof LoginRequest)) { return false; } final LoginRequest loginRequest = LoginRequest.class .cast(payload); if (!loginRequest.getUsername().equals(username)) { return false; } return true; } catch (final JMSException e) { throw new RuntimeException(e); } } }; final CountDownLatch expectedLoginRequestDelivered = this.incomingMessagesListener .awaitMatchingMessage(isExpectedLoginRequest); this.testClient.connect(); this.testClient.sendMessageAndWaitForResponse(messageReference, successfulLoginRequest); this.testClient.disconnect(); assertTrue( "GatewayServer should have forwarded successful LoginRequest to JMS server", expectedLoginRequestDelivered.await(2, TimeUnit.SECONDS)); } @Test public final void assertThatGatewayServerForwardsFailedLoginRequestToJmsServer() throws Throwable { final int messageReference = 1; final String username = "assertThatGatewayServerForwardsFailedLoginRequestToJmsServer"; final LoginRequest failedLoginRequest = new LoginRequest(username, DummyAuthenticationProvider.REJECTED_PASSWORD); final JmsMessagePredicate isExpectedLoginRequest = new JmsMessagePredicate() { @Override public boolean evaluate(final Message msg) { try { if (!(msg instanceof ObjectMessage)) { return false; } final ObjectMessage omsg = ObjectMessage.class.cast(msg); final Object payload = omsg.getObject(); if (!(payload instanceof LoginRequest)) { return false; } final LoginRequest loginRequest = LoginRequest.class .cast(payload); if (!loginRequest.getUsername().equals(username)) { return false; } return true; } catch (final JMSException e) { throw new RuntimeException(e); } } }; final CountDownLatch expectedLoginRequestDelivered = this.incomingMessagesListener .awaitMatchingMessage(isExpectedLoginRequest); this.testClient.connect(); this.testClient.sendMessageAndWaitForResponse(messageReference, failedLoginRequest); this.testClient.disconnect(); assertTrue( "GatewayServer should have forwarded failed LoginRequest to JMS server", expectedLoginRequestDelivered.await(2, TimeUnit.SECONDS)); } @Test public final void assertThatGatewayServerDelaysResponseToFailedLoginRequest() throws Throwable { final int messageReference = 78; final String username = "assertThatGatewayServerDelaysResponseToFailedLoginRequest"; final LoginRequest failedLoginRequest = new LoginRequest(username, DummyAuthenticationProvider.REJECTED_PASSWORD); this.testClient.connect(); final long before = System.currentTimeMillis(); this.testClient.sendMessageAndWaitForResponse(messageReference, failedLoginRequest); final long after = System.currentTimeMillis(); this.testClient.disconnect(); assertTrue( "GatewayServer should have delayed response to failed LoginRequest for at least " + this.failedLoginResponseMillis + " ms", after - before >= this.failedLoginResponseMillis); } @Test public final void assertThatGatewayServerRejectsNonLoginMessagesOnAnUnauthenticatedChannel() throws Throwable { final int messageReference = 78; final PingRequest nonLoginMessage = new PingRequest(); this.testClient.connect(); final ReferenceableMessageContainer nonLoginResponse = this.testClient .sendMessageAndWaitForResponse(messageReference, nonLoginMessage); this.testClient.disconnect(); assertEquals( "Expected channel pipeline to send (failed) PingResponse to client after failed login, yet it sent a different reply", PingResponse.class, nonLoginResponse.getMessage().getClass()); assertFalse( "Expected channel pipeline to send FAILED PingResponse to client after failed login, yet it sent a SUCCESSFUL PingResponse", PingResponse.class.cast(nonLoginResponse.getMessage()) .pingSucceeded()); } }