INT-1069: Add MessageGroupQueue and JDBC tests for rollback

This commit is contained in:
David Syer
2010-06-18 10:49:51 +00:00
parent 4e4cb559d1
commit 0a5ce33f9b
18 changed files with 562 additions and 37 deletions

View File

@@ -0,0 +1,11 @@
log4j.rootCategory=WARN, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %t %c{2}:%L - %m%n
log4j.category.org.springframework=WARN
log4j.category.org.springframework.integration=DEBUG
log4j.category.org.springframework.integration.jdbc=WARN
log4j.category.org.springframework.jdbc=DEBUG

View File

@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:int-jdbc="http://www.springframework.org/schema/integration/jdbc"
xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration/jdbc http://www.springframework.org/schema/integration/jdbc/spring-integration-jdbc.xsd">
<jdbc:embedded-database id="dataSource" type="DERBY">
<jdbc:script location="${int.schema.script}" />
</jdbc:embedded-database>
<int-jdbc:message-store id="messageStore" data-source="dataSource" />
<channel id="input" xmlns="http://www.springframework.org/schema/integration">
<queue ref="queue"/>
</channel>
<int:channel id="output"/>
<int:logging-channel-adapter channel="output"/>
<bean id="queue" class="org.springframework.integration.store.MessageGroupQueue">
<constructor-arg ref="messageStore" />
<constructor-arg value="input-queue" />
</bean>
<service-activator id="service-activator" input-channel="input" output-channel="output" xmlns="http://www.springframework.org/schema/integration">
<beans:bean class="org.springframework.integration.jdbc.JdbcMessageStoreChannelTests$Service" />
<poller>
<interval-trigger interval="200"/>
<transactional />
</poller>
</service-activator>
<bean id="placeholderProperties" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:int-${ENVIRONMENT:derby}.properties" />
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
<property name="ignoreUnresolvablePlaceholders" value="true" />
<property name="order" value="1" />
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
</beans>

View File

@@ -0,0 +1,95 @@
package org.springframework.integration.jdbc;
import static org.junit.Assert.assertEquals;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.core.MessageChannel;
import org.springframework.integration.message.StringMessage;
import org.springframework.integration.store.MessageGroup;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class JdbcMessageStoreChannelTests {
@Autowired
private MessageChannel input;
@Autowired
private JdbcMessageStore messageStore;
@Before
public void clear() {
for (MessageGroup group : messageStore) {
messageStore.removeMessageGroup(group.getCorrelationKey());
}
}
@Test
public void testSendAndActivate() throws Exception {
Service.reset(1);
input.send(new StringMessage("foo"));
Service.await(1000);
assertEquals(1, Service.messages.size());
assertEquals(0, messageStore.getMessageGroup("input-queue").size());
}
@Test
public void testSendAndActivateWithRollback() throws Exception {
Service.reset(1);
Service.fail = true;
input.send(new StringMessage("foo"));
Service.await(1000);
assertEquals(1, Service.messages.size());
// After a rollback in the poller the message is still waiting to be delivered
assertEquals(1, messageStore.getMessageGroup("input-queue").size());
assertEquals(1, messageStore.getMessageGroup("input-queue").getUnmarked().size());
}
@Test
@Transactional
public void testSendAndActivateTransactionalSend() throws Exception {
Service.reset(1);
input.send(new StringMessage("foo"));
// This will time out because the transaction has not committed yet
Service.await(1000);
// So no activation
assertEquals(0, Service.messages.size());
// But inside the transaction the message is still there
assertEquals(1, messageStore.getMessageGroup("input-queue").size());
assertEquals(1, messageStore.getMessageGroup("input-queue").getUnmarked().size());
}
public static class Service {
private static boolean fail = false;
private static List<String> messages = new ArrayList<String>();
private static CountDownLatch latch = new CountDownLatch(0);
public static void reset(int count) {
fail = false;
messages.clear();
latch = new CountDownLatch(count);
}
public static void await(long timeout) throws InterruptedException {
latch.await(timeout, TimeUnit.MILLISECONDS);
}
public String echo(String input) {
latch.countDown();
messages.add(input);
if (fail) {
throw new RuntimeException("Planned failure");
}
return input;
}
}
}

View File

@@ -2,7 +2,7 @@
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<jdbc:embedded-database id="dataSource" type="DERBY">

View File

@@ -8,6 +8,7 @@ import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.springframework.integration.test.matcher.PayloadAndHeaderMatcher.sameExceptIgnorableHeaders;
import java.util.Iterator;
import java.util.UUID;
import javax.sql.DataSource;
@@ -19,6 +20,8 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.core.Message;
import org.springframework.integration.message.MessageBuilder;
import org.springframework.integration.store.MessageGroup;
import org.springframework.integration.store.MessageGroupCallback;
import org.springframework.integration.store.MessageGroupStore;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
@@ -100,7 +103,7 @@ public class JdbcMessageStoreTests {
@Test
@Transactional
public void testAddAndDelete() throws Exception {
public void testAddAndRemoveMessageGroup() throws Exception {
Message<String> message = MessageBuilder.withPayload("foo").build();
message = messageStore.addMessage(message);
assertNotNull(messageStore.removeMessage(message.getHeaders().getId()));
@@ -118,6 +121,32 @@ public class JdbcMessageStoreTests {
assertTrue("Timestamp too early: " + group.getTimestamp() + "<" + now, group.getTimestamp() >= now);
}
@Test
@Transactional
public void testAddAndRemoveMessageFromMessageGroup() throws Exception {
String correlationId = "X";
Message<String> message = MessageBuilder.withPayload("foo").setCorrelationId(correlationId).build();
messageStore.addMessageToGroup(correlationId, message);
messageStore.removeMessageFromGroup(correlationId, message);
MessageGroup group = messageStore.getMessageGroup(correlationId);
assertEquals(0, group.size());
}
@Test
@Transactional
public void testOrderInMessageGroup() throws Exception {
String correlationId = "X";
Message<String> message = MessageBuilder.withPayload("foo").setCorrelationId(correlationId).build();
messageStore.addMessageToGroup(correlationId, message);
message = MessageBuilder.withPayload("bar").setCorrelationId(correlationId).build();
messageStore.addMessageToGroup(correlationId, message);
MessageGroup group = messageStore.getMessageGroup(correlationId);
assertEquals(2, group.size());
Iterator<Message<?>> iterator = group.getUnmarked().iterator();
assertEquals("foo", iterator.next().getPayload());
assertEquals("bar", iterator.next().getPayload());
}
@Test
@Transactional
public void testAddAndMarkMessageGroup() throws Exception {
@@ -135,9 +164,14 @@ public class JdbcMessageStoreTests {
String correlationId = "X";
Message<String> message = MessageBuilder.withPayload("foo").setCorrelationId(correlationId).build();
messageStore.addMessageToGroup(correlationId, message);
messageStore.registerMessageGroupExpiryCallback(new MessageGroupCallback() {
public void execute(MessageGroupStore messageGroupStore, MessageGroup group) {
messageGroupStore.removeMessageGroup(group.getCorrelationKey());
}
});
messageStore.expireMessageGroups(-10000);
MessageGroup group = messageStore.getMessageGroup(correlationId);
assertEquals(0, group.getMarked().size());
assertEquals(0, group.size());
}
}