/**
*
*/
package vnet.sms.gateway.nettysupport.window.incoming;
import static org.easymock.EasyMock.createNiceMock;
import static org.easymock.EasyMock.replay;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.UpstreamMessageEvent;
import org.junit.Test;
import vnet.sms.common.messages.GsmPdu;
import vnet.sms.common.messages.Msisdn;
import vnet.sms.common.messages.Sms;
import vnet.sms.common.wme.receive.ReceivedSmsEvent;
/**
* @author obergner
*
*/
public class IncomingWindowStoreConcurrentTest {
/**
* Test method for
* {@link vnet.sms.gateway.nettysupport.window.incoming.IncomingWindowStore#tryAcquireWindow(long, java.io.Serializable)}
* .
*
* @throws InterruptedException
* @throws ExecutionException
*/
@Test
public final void assertThatStoreMessageFillsWindowStoreToCapacity()
throws InterruptedException, ExecutionException {
final int capacity = 10000;
final long waitTimeMillis = 10L;
final BlockingQueue<IdPlusMessage> queue = new ArrayBlockingQueue<IdPlusMessage>(
capacity);
final Set<IdPlusMessage> backup = new HashSet<IdPlusMessage>(capacity);
for (long key = 0; key < capacity; key++) {
final IdPlusMessage idPlusMessage = new IdPlusMessage(key, new Sms(
new Msisdn("01686754432"), new Msisdn("01686754432"),
"assertThatStoreMessageFillsWindowStoreToCapacity"));
queue.put(idPlusMessage);
backup.add(idPlusMessage);
}
final IncomingWindowStore<Long> objectUnderTest = new IncomingWindowStore<Long>(
capacity, waitTimeMillis);
final int numberOfTasks = 100;
final Set<MessageStoreTask> messageStoreTasks = new HashSet<MessageStoreTask>(
numberOfTasks);
for (int i = 0; i < numberOfTasks; i++) {
messageStoreTasks.add(new MessageStoreTask(objectUnderTest, queue));
}
final ExecutorService executor = Executors
.newFixedThreadPool(numberOfTasks);
final Set<Future<?>> completions = new HashSet<Future<?>>();
for (final MessageStoreTask messageStoreTask : messageStoreTasks) {
completions.add(executor.submit(messageStoreTask));
}
for (final Future<?> completion : completions) {
completion.get();
}
executor.shutdown();
executor.awaitTermination(3, TimeUnit.SECONDS);
executor.shutdownNow();
assertEquals(
"IncomingWindowStore should be completely filled, yet it isn't",
capacity, objectUnderTest.getCurrentMessageCount());
for (final IdPlusMessage idPlusMessage : backup) {
final GsmPdu storedMessage = objectUnderTest
.releaseWindow(idPlusMessage.id);
assertNotNull("IncomingWindowStore should contain id "
+ idPlusMessage.id + ", yet it doesn't", storedMessage);
assertEquals("IncomingWindowStore stored wrong message under id "
+ idPlusMessage.id, idPlusMessage.message, storedMessage);
}
}
private static class IdPlusMessage {
final long id;
final Sms message;
public IdPlusMessage(final long id, final Sms message) {
this.id = id;
this.message = message;
}
}
private static class MessageStoreTask implements Runnable {
private final IncomingWindowStore<Long> objectUnderTest;
private final BlockingQueue<IdPlusMessage> queue;
public MessageStoreTask(
final IncomingWindowStore<Long> objectUnderTest,
final BlockingQueue<IdPlusMessage> queue) {
this.objectUnderTest = objectUnderTest;
this.queue = queue;
}
@Override
public void run() {
try {
final Channel mockChannel = createNiceMock(Channel.class);
replay(mockChannel);
while (true) {
final IdPlusMessage next = this.queue.poll();
if (next == null) {
break;
}
final boolean success = this.objectUnderTest
.tryAcquireWindow(new ReceivedSmsEvent<Long>(
next.id, new UpstreamMessageEvent(
mockChannel, next, null),
next.message));
if (!success) {
throw new IllegalStateException(
"Failed to store message [id = " + next.id
+ "|message = " + next.message + "]");
}
}
} catch (final InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
/**
* Test method for
* {@link vnet.sms.gateway.nettysupport.window.incoming.IncomingWindowStore#tryAcquireWindow(long, java.io.Serializable)}
* .
*
* @throws Throwable
*/
@Test(expected = IllegalStateException.class)
public final void assertThatStoreMessageRefusesToFillWindowStoreBeyondCapacity()
throws Throwable {
ExecutorService executor = null;
try {
final int capacity = 10000;
final long waitTimeMillis = 10L;
final int numberOfMessagesToStore = capacity + 1;
final BlockingQueue<IdPlusMessage> queue = new ArrayBlockingQueue<IdPlusMessage>(
numberOfMessagesToStore);
for (long key = 0; key < numberOfMessagesToStore; key++) {
final IdPlusMessage idPlusMessage = new IdPlusMessage(key,
new Sms(new Msisdn("01686754432"), new Msisdn(
"01686754432"), String.valueOf(key)));
queue.put(idPlusMessage);
}
final IncomingWindowStore<Long> objectUnderTest = new IncomingWindowStore<Long>(
capacity, waitTimeMillis);
final int numberOfTasks = 100;
final Set<MessageStoreTask> messageStoreTasks = new HashSet<MessageStoreTask>(
numberOfTasks);
for (int i = 0; i < numberOfTasks; i++) {
messageStoreTasks.add(new MessageStoreTask(objectUnderTest,
queue));
}
executor = Executors.newFixedThreadPool(numberOfTasks);
final Set<Future<?>> completions = new HashSet<Future<?>>();
for (final MessageStoreTask messageStoreTask : messageStoreTasks) {
completions.add(executor.submit(messageStoreTask));
}
for (final Future<?> completion : completions) {
completion.get();
}
} catch (final ExecutionException e) {
throw e.getCause();
} finally {
if (executor != null) {
executor.shutdown();
executor.awaitTermination(3, TimeUnit.SECONDS);
executor.shutdownNow();
}
}
}
}