INT-3646: Add TCP Server Exception Events

JIRA: https://jira.spring.io/browse/INT-3646

Publish `TcpConnectionServerExceptionEvent`s when unexpected
exceptions occur on server sockets.

INT-3646: Polishing
Fix Reactor tests
This commit is contained in:
Gary Russell
2015-02-18 20:16:51 +02:00
committed by Artem Bilan
parent f248394682
commit f4e775ec18
9 changed files with 251 additions and 97 deletions

View File

@@ -16,25 +16,49 @@
package org.springframework.integration.ip.tcp.connection;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import java.io.OutputStream;
import java.net.BindException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import javax.net.ServerSocketFactory;
import org.apache.commons.logging.Log;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import org.mockito.internal.stubbing.answers.DoesNothing;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.core.serializer.Serializer;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.util.SocketUtils;
/**
* @author Gary Russell
@@ -44,7 +68,7 @@ import org.springframework.messaging.support.GenericMessage;
public class ConnectionEventTests {
@Test
public void test() throws Exception {
public void testConnectionEvents() throws Exception {
Socket socket = mock(Socket.class);
final List<TcpConnectionEvent> theEvent = new ArrayList<TcpConnectionEvent>();
TcpNetConnection conn = new TcpNetConnection(socket, false, false, new ApplicationEventPublisher() {
@@ -56,9 +80,9 @@ public class ConnectionEventTests {
@Override
public void publishEvent(Object event) {
}
}, "foo");
/*
* Open is not published by the connection itself; the factory publishes it after initialization.
@@ -85,7 +109,72 @@ public class ConnectionEventTests {
assertSame(toBeThrown, event.getCause());
assertTrue(theEvent.size() > 1);
assertNotNull(theEvent.get(1));
assertTrue(theEvent.get(1).toString().endsWith("[factory=foo, connectionId=" + conn.getConnectionId() + "] **CLOSED**"));
assertTrue(theEvent.get(1).toString()
.endsWith("[factory=foo, connectionId=" + conn.getConnectionId() + "] **CLOSED**"));
}
@Test
public void testNetServerExceptionEvent() throws Exception {
int port = SocketUtils.findAvailableTcpPort();
AbstractServerConnectionFactory factory = new TcpNetServerConnectionFactory(port);
testServerExceptionGuts(port, factory);
}
@Test
public void testNioServerExceptionEvent() throws Exception {
int port = SocketUtils.findAvailableTcpPort();
AbstractServerConnectionFactory factory = new TcpNioServerConnectionFactory(port);
testServerExceptionGuts(port, factory);
}
private void testServerExceptionGuts(int port, AbstractServerConnectionFactory factory) throws Exception {
ServerSocket ss = ServerSocketFactory.getDefault().createServerSocket(port);
final AtomicReference<TcpConnectionServerExceptionEvent> theEvent =
new AtomicReference<TcpConnectionServerExceptionEvent>();
final CountDownLatch latch = new CountDownLatch(1);
factory.setApplicationEventPublisher(new ApplicationEventPublisher() {
@Override
public void publishEvent(ApplicationEvent event) {
theEvent.set((TcpConnectionServerExceptionEvent) event);
latch.countDown();
}
@Override
public void publishEvent(Object event) {
}
});
factory.setBeanName("sf");
factory.registerListener(new TcpListener() {
@Override
public boolean onMessage(Message<?> message) {
return false;
}
});
Log logger = spy(TestUtils.getPropertyValue(factory, "logger", Log.class));
doAnswer(new DoesNothing()).when(logger).error(anyString(), any(Throwable.class));
new DirectFieldAccessor(factory).setPropertyValue("logger", logger);
factory.start();
assertTrue(latch.await(10, TimeUnit.SECONDS));
String actual = theEvent.toString();
assertThat(actual, containsString("cause=java.net.BindException"));
assertThat(actual, containsString("[factory="
+ (factory instanceof TcpNetServerConnectionFactory
? "tcp-net-server-connection-factory"
: "tcp-nio-server-connection-factory")
+ ":sf, port=" + port + "]"));
ArgumentCaptor<String> reasonCaptor = ArgumentCaptor.forClass(String.class);
ArgumentCaptor<Throwable> throwableCaptor = ArgumentCaptor.forClass(Throwable.class);
verify(logger).error(reasonCaptor.capture(), throwableCaptor.capture());
assertThat(reasonCaptor.getValue(), startsWith("Error on Server"));
assertThat(reasonCaptor.getValue(), endsWith("; port = " + port));
assertThat(throwableCaptor.getValue(), instanceOf(BindException.class));
ss.close();
}
}

View File

@@ -2,7 +2,6 @@ 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 %c{1} [%t] : %m%n
log4j.appender.stdout.layout.ConversionPattern=%d %5p %c{1} [%t] : %m%n
log4j.category.org.springframework.integration=WARN
log4j.category.org.springframework.integration.ip=WARN