package vnet.sms.gateway.server.framework;
import static org.junit.Assert.assertTrue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.ObjectMessage;
import javax.jms.Session;
import org.jboss.netty.channel.MessageEvent;
import org.junit.After;
import org.junit.Before;
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.jms.core.JmsOperations;
import org.springframework.jms.core.MessageCreator;
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.Acknowledgement;
import vnet.sms.common.messages.Headers;
import vnet.sms.common.messages.LoginRequest;
import vnet.sms.common.messages.LoginResponse;
import vnet.sms.common.messages.Msisdn;
import vnet.sms.common.messages.Sms;
import vnet.sms.common.wme.MessageEventType;
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.server.framework.test.MessageEventPredicate;
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/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 SendOutgoingAcknowledgementsIT {
@Autowired
private IntegrationTestClient testClient;
@Autowired
private JmsOperations jmsClient;
@Autowired
private ForwardingJmsMessageListener incomingMessagesListener;
@Value("#{ '${gateway.server.jmsserver.queues.outgoingMtSmsAck}' }")
private String outgoingMtSmsAckQueueName;
@Value("#{ '${gateway.server.jmsserver.queues.outgoingMtSmsNack}' }")
private String outgoingMtSmsNackQueueName;
@Before
public void connectTestClient() throws Throwable {
this.testClient.connect();
}
@After
public void disconnectTestClient() throws Throwable {
this.testClient.disconnect();
}
@Test(timeout = 2000L)
public final void assertThatGatewayServerSendsSmsAckReceivedViaJmsToConnectedClient()
throws Throwable {
// 1. Login
final int loginReference = 1;
final String username = "assertThatGatewayServerSendsSmsAckReceivedViaJmsToConnectedClient";
final LoginRequest successfulLoginRequest = new LoginRequest(username,
"whatever");
final ReferenceableMessageContainer loginResponseContainer = this.testClient
.sendMessageAndWaitForResponse(loginReference,
successfulLoginRequest);
assertTrue(
"PRECONDITION VIOLATED: Login failed",
(loginResponseContainer.getMessage() instanceof LoginResponse)
&& loginResponseContainer.getMessage(
LoginResponse.class).loginSucceeded());
// 2. Send MT SMS
final int mtSmsReference = 2;
final Sms mtSms = new Sms(new Msisdn("01686754432"), new Msisdn(
"01686754432"),
"assertThatGatewayServerSendsMoSmsReceivedViaJmsToConnectedClient");
final JmsMessagePredicate isExpectedMtSms = 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 Sms)) {
return false;
}
final Sms sms = Sms.class.cast(payload);
if (!sms.equals(mtSms)) {
return false;
}
return true;
} catch (final JMSException e) {
throw new RuntimeException(e);
}
}
};
final Future<Message> forwardedMtSms = this.incomingMessagesListener
.receiveMatchingMessage(isExpectedMtSms);
this.testClient.sendMessage(mtSmsReference, mtSms);
// 3. Make test client wait for expected MT SMS Ack
final MessageEventPredicate isExpectedMtSmsAck = new MessageEventPredicate() {
@Override
public boolean evaluate(final MessageEvent e) {
final vnet.sms.common.messages.GsmPdu gsmPdu = ReferenceableMessageContainer.class
.cast(e.getMessage()).getMessage();
if (!(gsmPdu instanceof Acknowledgement)) {
return false;
}
return Acknowledgement.class.cast(gsmPdu).is(
Acknowledgement.Status.ACK);
}
};
final CountDownLatch expectedAckReceived = this.testClient
.listen(isExpectedMtSmsAck);
// 4. Create ack for forwarded MT SMS and send it via JMS
final ObjectMessage forwardedMtSmsMsg = (ObjectMessage) forwardedMtSms
.get();
final Integer smsReference = (Integer) forwardedMtSmsMsg
.getObjectProperty(Headers.MESSAGE_REFERENCE);
final int receivingChannelId = forwardedMtSmsMsg
.getIntProperty(Headers.RECEIVING_CHANNEL_ID);
this.jmsClient.send(this.outgoingMtSmsAckQueueName,
new MessageCreator() {
@Override
public Message createMessage(final Session session)
throws JMSException {
final ObjectMessage mtSmsAckObjectMessage = session
.createObjectMessage(mtSms);
mtSmsAckObjectMessage.setStringProperty(
Headers.EVENT_TYPE,
MessageEventType.SEND_SMS_ACK.name());
mtSmsAckObjectMessage.setIntProperty(
Headers.RECEIVING_CHANNEL_ID,
receivingChannelId);
mtSmsAckObjectMessage.setObjectProperty(
Headers.MESSAGE_REFERENCE, smsReference);
return mtSmsAckObjectMessage;
}
});
assertTrue(
"Expected to receive Ack for previously sent MT SMS, yet didn't",
expectedAckReceived.await(2000L, TimeUnit.MILLISECONDS));
}
@Test(timeout = 2000L)
public final void assertThatGatewayServerSendsSmsNackReceivedViaJmsToConnectedClient()
throws Throwable {
// 1. Login
final int loginReference = 1;
final String username = "assertThatGatewayServerSendsSmsNackReceivedViaJmsToConnectedClient";
final LoginRequest successfulLoginRequest = new LoginRequest(username,
"whatever");
final ReferenceableMessageContainer loginResponseContainer = this.testClient
.sendMessageAndWaitForResponse(loginReference,
successfulLoginRequest);
assertTrue(
"PRECONDITION VIOLATED: Login failed",
(loginResponseContainer.getMessage() instanceof LoginResponse)
&& loginResponseContainer.getMessage(
LoginResponse.class).loginSucceeded());
// 2. Send MT SMS
final int mtSmsReference = 2;
final Sms mtSms = new Sms(new Msisdn("01686754432"), new Msisdn(
"01686754432"),
"assertThatGatewayServerSendsSmsNackReceivedViaJmsToConnectedClient");
final JmsMessagePredicate isExpectedMtSms = 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 Sms)) {
return false;
}
final Sms sms = Sms.class.cast(payload);
if (!sms.equals(mtSms)) {
return false;
}
return true;
} catch (final JMSException e) {
throw new RuntimeException(e);
}
}
};
final Future<Message> forwardedMtSms = this.incomingMessagesListener
.receiveMatchingMessage(isExpectedMtSms);
this.testClient.sendMessage(mtSmsReference, mtSms);
// 3. Make test client wait for expected MT SMS Nack
final MessageEventPredicate isExpectedMtSmsAck = new MessageEventPredicate() {
@Override
public boolean evaluate(final MessageEvent e) {
final vnet.sms.common.messages.GsmPdu gsmPdu = ReferenceableMessageContainer.class
.cast(e.getMessage()).getMessage();
if (!(gsmPdu instanceof Acknowledgement)) {
return false;
}
return Acknowledgement.class.cast(gsmPdu).is(
Acknowledgement.Status.NACK);
}
};
final CountDownLatch expectedAckReceived = this.testClient
.listen(isExpectedMtSmsAck);
// 4. Create ack for forwarded MT SMS and send it via JMS
final ObjectMessage forwardedMtSmsMsg = (ObjectMessage) forwardedMtSms
.get();
final Integer smsReference = (Integer) forwardedMtSmsMsg
.getObjectProperty(Headers.MESSAGE_REFERENCE);
final int receivingChannelId = forwardedMtSmsMsg
.getIntProperty(Headers.RECEIVING_CHANNEL_ID);
this.jmsClient.send(this.outgoingMtSmsNackQueueName,
new MessageCreator() {
@Override
public Message createMessage(final Session session)
throws JMSException {
final ObjectMessage mtSmsNackObjectMessage = session
.createObjectMessage(mtSms);
mtSmsNackObjectMessage.setStringProperty(
Headers.EVENT_TYPE,
MessageEventType.SEND_SMS_NACK.name());
mtSmsNackObjectMessage.setIntProperty(
Headers.RECEIVING_CHANNEL_ID,
receivingChannelId);
mtSmsNackObjectMessage.setObjectProperty(
Headers.MESSAGE_REFERENCE, smsReference);
mtSmsNackObjectMessage.setIntProperty(
Headers.ERROR_KEY, 1);
mtSmsNackObjectMessage
.setStringProperty(Headers.ERROR_DESCRIPTION,
"assertThatGatewayServerSendsSmsNackReceivedViaJmsToConnectedClient");
return mtSmsNackObjectMessage;
}
});
assertTrue(
"Expected to receive Ack for previously sent MT SMS, yet didn't",
expectedAckReceived.await(2000L, TimeUnit.MILLISECONDS));
}
}