package org.littlewings.hazelcast.reliabletopic;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import com.hazelcast.config.ClasspathXmlConfig;
import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.ITopic;
import com.hazelcast.topic.TopicOverloadException;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
public class HazelcastReliableTopicTest {
@Test
public void testSimpleUsage() {
withHazelcast(3, hazelcastInstance -> {
ITopic<String> topic = hazelcastInstance.getReliableTopic("default");
List<String> receivedMessage = new ArrayList<>();
topic.addMessageListener(message -> receivedMessage.add(message.getMessageObject()));
topic.publish("Hello World");
topic.publish("Hello Hazelcast!");
assertThat(receivedMessage)
.isEqualTo(Arrays.asList("Hello World", "Hello Hazelcast!"));
assertThat(topic.getLocalTopicStats().getPublishOperationCount())
.isEqualTo(2L);
assertThat(topic.getLocalTopicStats().getReceiveOperationCount())
.isEqualTo(2L);
});
}
@Test
public void testWithRingbufferTtl() {
withHazelcast(3, hazelcastInstance -> {
ITopic<String> topic = hazelcastInstance.getReliableTopic("with-ttl");
long start = System.currentTimeMillis();
IntStream
.rangeClosed(1, 10005)
.forEach(i -> topic.publish("message-" + i));
long elapsed = System.currentTimeMillis() - start;
assertThat(topic.getLocalTopicStats().getPublishOperationCount())
.isEqualTo(10005L);
assertThat(topic.getLocalTopicStats().getReceiveOperationCount())
.isEqualTo(0L);
assertThat(elapsed)
.isGreaterThanOrEqualTo(30 * 1000L);
});
}
@Test
public void testOverloadError() {
withHazelcast(3, hazelcastInstance -> {
ITopic<String> topic = hazelcastInstance.getReliableTopic("overload-error-policy");
List<String> receivedMessage = new ArrayList<>();
topic.addMessageListener(message -> {
receivedMessage.add(message.getMessageObject());
try {
TimeUnit.MICROSECONDS.sleep(500L);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
assertThatThrownBy(() -> {
IntStream
.rangeClosed(1, 15)
.forEach(i -> topic.publish("message-" + i));
try {
TimeUnit.SECONDS.sleep(10L);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
)
.isInstanceOf(TopicOverloadException.class)
.hasMessageContaining("Failed to publish message:");
});
}
@Test
public void testOverloadDiscardNewest() {
withHazelcast(3, hazelcastInstance -> {
ITopic<String> topic = hazelcastInstance.getReliableTopic("overload-discard-newest");
List<String> receivedMessage = new ArrayList<>();
topic.addMessageListener(message -> {
receivedMessage.add(message.getMessageObject());
try {
TimeUnit.SECONDS.sleep(1L);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
IntStream
.rangeClosed(1, 15)
.forEach(i -> topic.publish("message-" + i));
try {
TimeUnit.SECONDS.sleep(20);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
assertThat(receivedMessage)
.containsExactly("message-1",
"message-2",
"message-3",
"message-4",
"message-5",
"message-6",
"message-7",
"message-8",
"message-9",
"message-10");
});
}
@Test
public void testOverloadDiscardOldest() {
withHazelcast(3, hazelcastInstance -> {
ITopic<String> topic = hazelcastInstance.getReliableTopic("overload-discard-oldest");
List<String> receivedMessage = new ArrayList<>();
topic.addMessageListener(message -> {
receivedMessage.add(message.getMessageObject());
try {
TimeUnit.SECONDS.sleep(1L);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
IntStream
.rangeClosed(1, 15)
.forEach(i -> topic.publish("message-" + i));
try {
TimeUnit.SECONDS.sleep(20L);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
assertThat(receivedMessage)
.containsExactly("message-1");
});
}
protected void withHazelcast(int numInstances, Consumer<HazelcastInstance> f) {
List<HazelcastInstance> hazelcastInstances =
IntStream
.rangeClosed(1, numInstances)
.mapToObj(i -> Hazelcast.newHazelcastInstance(new ClasspathXmlConfig("hazelcast.xml")))
.collect(Collectors.toList());
try {
f.accept(hazelcastInstances.get(0));
} finally {
hazelcastInstances.forEach(h -> h.getLifecycleService().shutdown());
Hazelcast.shutdownAll();
}
}
}