package proj.zoie.dataprovider.jms; import static org.junit.Assert.assertFalse; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.when; import java.util.Collection; import java.util.Comparator; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.Session; import javax.jms.Topic; import javax.jms.TopicConnection; import javax.jms.TopicConnectionFactory; import javax.jms.TopicSession; import javax.jms.TopicSubscriber; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.invocation.InvocationOnMock; import org.mockito.runners.MockitoJUnitRunner; import org.mockito.stubbing.Answer; import proj.zoie.api.DataConsumer; import proj.zoie.api.DataConsumer.DataEvent; import proj.zoie.api.ZoieException; import proj.zoie.impl.indexing.ZoieConfig; @RunWith(MockitoJUnitRunner.class) public class TestJMSStreamDataProvider { @Mock TopicConnectionFactory connectionFactory; @Mock TopicFactory topicFactory; @Mock DataEventBuilder<Object> dataEventBuilder; @Mock TopicSubscriber subscriber; @Mock TopicSession session; @Mock TopicConnection connection; @Mock Message message; JMSStreamDataProvider<Object> provider; @Before public void setUpJMSStreamDataProvider() throws JMSException { final AtomicLong v = new AtomicLong(0); when(dataEventBuilder.buildDataEvent(any(Message.class))) .thenAnswer(new Answer<DataEvent<Object>>() { @Override public DataEvent<Object> answer( InvocationOnMock invocation) throws Throwable { return new DataEvent<Object>(new Object(), String.valueOf(v.incrementAndGet())); } }); provider = new JMSStreamDataProvider<Object>("topic", "clientID", connectionFactory, topicFactory, dataEventBuilder, ZoieConfig.DEFAULT_VERSION_COMPARATOR); } /** * The case, when JMS returns messages without problems * @throws JMSException * @throws ZoieException */ @Test public void testSuccessfulNext() throws JMSException, ZoieException { //stub successful connection when(connectionFactory.createTopicConnection()) .thenReturn(connection); when(connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE)) .thenReturn(session); when(session.createDurableSubscriber(any(Topic.class), anyString())) .thenReturn(subscriber); //stub successful receiving messages when(subscriber.receive()) .thenReturn(message, message, message); final AtomicBoolean failed = new AtomicBoolean(false); provider.setDataConsumer(new DataConsumer<Object>() { private volatile String version = null; private long v = 1; @Override public void consume( Collection<proj.zoie.api.DataConsumer.DataEvent<Object>> data) throws ZoieException { for (DataEvent<Object> e : data) { if (Long.valueOf(e.getVersion()) != v) { failed.set(true); } v++; version = e.getVersion(); } } @Override public String getVersion() { return version; } @Override public Comparator<String> getVersionComparator() { return ZoieConfig.DEFAULT_VERSION_COMPARATOR; } } ); provider.start(); String versionToSync = "100"; provider.syncWithVersion(5000, versionToSync); assertFalse(failed.get()); provider.stop(); } /** * The case, when JMS throws exception * @throws JMSException * @throws ZoieException */ @Test public void testExceptionRecovery() throws JMSException, ZoieException { //stub some problems with connecting to topic, but //at the end connect anyway when(connectionFactory.createTopicConnection()) .thenReturn(connection) .thenThrow(new JMSException("some problem 4")) .thenReturn(connection); //the last stubbed value will be repeatedly returned when(connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE)) .thenReturn(session) .thenThrow(new JMSException("some problem 5")) .thenReturn(session); when(session.createDurableSubscriber(any(Topic.class), anyString())) .thenReturn(subscriber) .thenThrow(new JMSException("some problem 6")) .thenReturn(subscriber); //the last stubbed value will be repeatedly returned //stub some problems with receiving messages, //in total receive 3 messages when(subscriber.receive()) .thenThrow(new JMSException("some problem 0")) .thenReturn(message) .thenThrow(new JMSException("some problem 1")) .thenReturn(message) .thenThrow(new JMSException("some problem 2")) .thenThrow(new JMSException("some problem 3")) .thenReturn(message); //the last stubbed value will be repeatedly returned //for testing set back off time very small provider.setJMSErrorBackOffTime(1); final AtomicBoolean failed = new AtomicBoolean(false); provider.setDataConsumer(new DataConsumer<Object>() { private volatile String version = null; private long v = 1; @Override public void consume( Collection<proj.zoie.api.DataConsumer.DataEvent<Object>> data) throws ZoieException { for (DataEvent<Object> e : data) { if (Long.valueOf(e.getVersion()) != v) { failed.set(true); } v++; version = e.getVersion(); } } @Override public String getVersion() { return version; } @Override public Comparator<String> getVersionComparator() { return ZoieConfig.DEFAULT_VERSION_COMPARATOR; } } ); provider.start(); String versionToSync = "100"; provider.syncWithVersion(5000, versionToSync); assertFalse(failed.get()); provider.stop(); } }