Fix Race Conditions in TcpNioConnectionReadTests
https://build.spring.io/browse/INT-SI43X-60 After introduction the `sendErrorToListener()` function for the `TcpConnectionSupport`, all the tests in the `TcpNioConnectionReadTests` have flaw to be affected by the race condition to release semaphore in the `onMessage()` and don't get a connection as closed yet. * Fix the tests adding `CountDownLatch` for the `ErrorMessage` and `AtomicReference` to assert an Exception message afterwards. **Cherry-pick to 4.3.x** Add Travis diagnostic to determine what is the difference if that Revert Travis diagnostic Looks like would be better to wait for CI failure to determine the root of sporadic cause Conflicts: spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/TcpNioConnectionReadTests.java
This commit is contained in:
committed by
Gary Russell
parent
6a51da65e6
commit
3127f25bfe
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,7 +16,9 @@
|
||||
|
||||
package org.springframework.integration.ip.tcp.connection;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Mockito.mock;
|
||||
@@ -27,6 +29,7 @@ import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import javax.net.SocketFactory;
|
||||
|
||||
@@ -40,9 +43,11 @@ import org.springframework.integration.ip.tcp.serializer.ByteArrayStxEtxSerializ
|
||||
import org.springframework.integration.ip.util.SocketTestUtils;
|
||||
import org.springframework.integration.ip.util.TestingUtilities;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.support.ErrorMessage;
|
||||
|
||||
/**
|
||||
* @author Gary Russell
|
||||
* @author Artem Bilan
|
||||
* @since 2.0
|
||||
*/
|
||||
public class TcpNioConnectionReadTests {
|
||||
@@ -210,14 +215,16 @@ public class TcpNioConnectionReadTests {
|
||||
final Semaphore semaphore = new Semaphore(0);
|
||||
final List<TcpConnection> added = new ArrayList<TcpConnection>();
|
||||
final List<TcpConnection> removed = new ArrayList<TcpConnection>();
|
||||
AbstractServerConnectionFactory scf = getConnectionFactory(serializer, new TcpListener() {
|
||||
|
||||
@Override
|
||||
public boolean onMessage(Message<?> message) {
|
||||
semaphore.release();
|
||||
return false;
|
||||
final CountDownLatch errorMessageLetch = new CountDownLatch(1);
|
||||
final AtomicReference<Throwable> errorMessageRef = new AtomicReference<Throwable>();
|
||||
|
||||
AbstractServerConnectionFactory scf = getConnectionFactory(serializer, message -> {
|
||||
if (message instanceof ErrorMessage) {
|
||||
errorMessageRef.set(((ErrorMessage) message).getPayload());
|
||||
errorMessageLetch.countDown();
|
||||
}
|
||||
|
||||
return false;
|
||||
}, new TcpSender() {
|
||||
|
||||
@Override
|
||||
@@ -239,6 +246,12 @@ public class TcpNioConnectionReadTests {
|
||||
CountDownLatch done = SocketTestUtils.testSendLengthOverflow(scf.getPort());
|
||||
whileOpen(semaphore, added);
|
||||
assertEquals(1, added.size());
|
||||
|
||||
assertTrue(errorMessageLetch.await(10, TimeUnit.SECONDS));
|
||||
|
||||
assertThat(errorMessageRef.get().getMessage(),
|
||||
containsString("Message length 2147483647 exceeds max message length: 2048"));
|
||||
|
||||
assertTrue(semaphore.tryAcquire(10000, TimeUnit.MILLISECONDS));
|
||||
assertTrue(removed.size() > 0);
|
||||
scf.stop();
|
||||
@@ -252,14 +265,16 @@ public class TcpNioConnectionReadTests {
|
||||
final Semaphore semaphore = new Semaphore(0);
|
||||
final List<TcpConnection> added = new ArrayList<TcpConnection>();
|
||||
final List<TcpConnection> removed = new ArrayList<TcpConnection>();
|
||||
AbstractServerConnectionFactory scf = getConnectionFactory(serializer, new TcpListener() {
|
||||
|
||||
@Override
|
||||
public boolean onMessage(Message<?> message) {
|
||||
semaphore.release();
|
||||
return false;
|
||||
final CountDownLatch errorMessageLetch = new CountDownLatch(1);
|
||||
final AtomicReference<Throwable> errorMessageRef = new AtomicReference<Throwable>();
|
||||
|
||||
AbstractServerConnectionFactory scf = getConnectionFactory(serializer, message -> {
|
||||
if (message instanceof ErrorMessage) {
|
||||
errorMessageRef.set(((ErrorMessage) message).getPayload());
|
||||
errorMessageLetch.countDown();
|
||||
}
|
||||
|
||||
return false;
|
||||
}, new TcpSender() {
|
||||
|
||||
@Override
|
||||
@@ -281,6 +296,12 @@ public class TcpNioConnectionReadTests {
|
||||
CountDownLatch done = SocketTestUtils.testSendStxEtxOverflow(scf.getPort());
|
||||
whileOpen(semaphore, added);
|
||||
assertEquals(1, added.size());
|
||||
|
||||
assertTrue(errorMessageLetch.await(10, TimeUnit.SECONDS));
|
||||
|
||||
assertThat(errorMessageRef.get().getMessage(),
|
||||
containsString("ETX not found before max message length: 1024"));
|
||||
|
||||
assertTrue(semaphore.tryAcquire(10000, TimeUnit.MILLISECONDS));
|
||||
assertTrue(removed.size() > 0);
|
||||
scf.stop();
|
||||
@@ -294,14 +315,16 @@ public class TcpNioConnectionReadTests {
|
||||
final Semaphore semaphore = new Semaphore(0);
|
||||
final List<TcpConnection> added = new ArrayList<TcpConnection>();
|
||||
final List<TcpConnection> removed = new ArrayList<TcpConnection>();
|
||||
AbstractServerConnectionFactory scf = getConnectionFactory(serializer, new TcpListener() {
|
||||
|
||||
@Override
|
||||
public boolean onMessage(Message<?> message) {
|
||||
semaphore.release();
|
||||
return false;
|
||||
final CountDownLatch errorMessageLetch = new CountDownLatch(1);
|
||||
final AtomicReference<Throwable> errorMessageRef = new AtomicReference<Throwable>();
|
||||
|
||||
AbstractServerConnectionFactory scf = getConnectionFactory(serializer, message -> {
|
||||
if (message instanceof ErrorMessage) {
|
||||
errorMessageRef.set(((ErrorMessage) message).getPayload());
|
||||
errorMessageLetch.countDown();
|
||||
}
|
||||
|
||||
return false;
|
||||
}, new TcpSender() {
|
||||
|
||||
@Override
|
||||
@@ -323,6 +346,12 @@ public class TcpNioConnectionReadTests {
|
||||
CountDownLatch done = SocketTestUtils.testSendCrLfOverflow(scf.getPort());
|
||||
whileOpen(semaphore, added);
|
||||
assertEquals(1, added.size());
|
||||
|
||||
assertTrue(errorMessageLetch.await(10, TimeUnit.SECONDS));
|
||||
|
||||
assertThat(errorMessageRef.get().getMessage(),
|
||||
containsString("CRLF not found before max message length: 1024"));
|
||||
|
||||
assertTrue(semaphore.tryAcquire(10000, TimeUnit.MILLISECONDS));
|
||||
assertTrue(removed.size() > 0);
|
||||
scf.stop();
|
||||
@@ -331,7 +360,6 @@ public class TcpNioConnectionReadTests {
|
||||
|
||||
/**
|
||||
* Tests socket closure when no data received.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
@@ -341,14 +369,16 @@ public class TcpNioConnectionReadTests {
|
||||
final Semaphore semaphore = new Semaphore(0);
|
||||
final List<TcpConnection> added = new ArrayList<TcpConnection>();
|
||||
final List<TcpConnection> removed = new ArrayList<TcpConnection>();
|
||||
AbstractServerConnectionFactory scf = getConnectionFactory(serializer, new TcpListener() {
|
||||
|
||||
@Override
|
||||
public boolean onMessage(Message<?> message) {
|
||||
semaphore.release();
|
||||
return false;
|
||||
final CountDownLatch errorMessageLetch = new CountDownLatch(1);
|
||||
final AtomicReference<Throwable> errorMessageRef = new AtomicReference<Throwable>();
|
||||
|
||||
AbstractServerConnectionFactory scf = getConnectionFactory(serializer, message -> {
|
||||
if (message instanceof ErrorMessage) {
|
||||
errorMessageRef.set(((ErrorMessage) message).getPayload());
|
||||
errorMessageLetch.countDown();
|
||||
}
|
||||
|
||||
return false;
|
||||
}, new TcpSender() {
|
||||
|
||||
@Override
|
||||
@@ -368,6 +398,12 @@ public class TcpNioConnectionReadTests {
|
||||
socket.close();
|
||||
whileOpen(semaphore, added);
|
||||
assertEquals(1, added.size());
|
||||
|
||||
assertTrue(errorMessageLetch.await(10, TimeUnit.SECONDS));
|
||||
|
||||
assertThat(errorMessageRef.get().getMessage(),
|
||||
containsString("Connection is closed"));
|
||||
|
||||
assertTrue(semaphore.tryAcquire(10000, TimeUnit.MILLISECONDS));
|
||||
assertTrue(removed.size() > 0);
|
||||
scf.stop();
|
||||
@@ -375,7 +411,6 @@ public class TcpNioConnectionReadTests {
|
||||
|
||||
/**
|
||||
* Tests socket closure when no data received.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
@@ -385,14 +420,16 @@ public class TcpNioConnectionReadTests {
|
||||
final Semaphore semaphore = new Semaphore(0);
|
||||
final List<TcpConnection> added = new ArrayList<TcpConnection>();
|
||||
final List<TcpConnection> removed = new ArrayList<TcpConnection>();
|
||||
AbstractServerConnectionFactory scf = getConnectionFactory(serializer, new TcpListener() {
|
||||
|
||||
@Override
|
||||
public boolean onMessage(Message<?> message) {
|
||||
semaphore.release();
|
||||
return false;
|
||||
final CountDownLatch errorMessageLetch = new CountDownLatch(1);
|
||||
final AtomicReference<Throwable> errorMessageRef = new AtomicReference<Throwable>();
|
||||
|
||||
AbstractServerConnectionFactory scf = getConnectionFactory(serializer, message -> {
|
||||
if (message instanceof ErrorMessage) {
|
||||
errorMessageRef.set(((ErrorMessage) message).getPayload());
|
||||
errorMessageLetch.countDown();
|
||||
}
|
||||
|
||||
return false;
|
||||
}, new TcpSender() {
|
||||
|
||||
@Override
|
||||
@@ -413,6 +450,12 @@ public class TcpNioConnectionReadTests {
|
||||
socket.close();
|
||||
whileOpen(semaphore, added);
|
||||
assertEquals(1, added.size());
|
||||
|
||||
assertTrue(errorMessageLetch.await(10, TimeUnit.SECONDS));
|
||||
|
||||
assertThat(errorMessageRef.get().getMessage(),
|
||||
containsString("Connection is closed"));
|
||||
|
||||
assertTrue(semaphore.tryAcquire(10000, TimeUnit.MILLISECONDS));
|
||||
assertTrue(removed.size() > 0);
|
||||
scf.stop();
|
||||
@@ -420,7 +463,6 @@ public class TcpNioConnectionReadTests {
|
||||
|
||||
/**
|
||||
* Tests socket closure when mid-message
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
@@ -431,10 +473,8 @@ public class TcpNioConnectionReadTests {
|
||||
|
||||
/**
|
||||
* Tests socket closure when mid-message
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testCloseCleanupStxEtx() throws Exception {
|
||||
ByteArrayCrLfSerializer serializer = new ByteArrayCrLfSerializer();
|
||||
@@ -443,10 +483,8 @@ public class TcpNioConnectionReadTests {
|
||||
|
||||
/**
|
||||
* Tests socket closure when mid-message
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testCloseCleanupLengthHeader() throws Exception {
|
||||
ByteArrayLengthHeaderSerializer serializer = new ByteArrayLengthHeaderSerializer();
|
||||
@@ -455,16 +493,19 @@ public class TcpNioConnectionReadTests {
|
||||
|
||||
private void testClosureMidMessageGuts(AbstractByteArraySerializer serializer, String shortMessage)
|
||||
throws Exception {
|
||||
final List<Message<?>> responses = new ArrayList<Message<?>>();
|
||||
final Semaphore semaphore = new Semaphore(0);
|
||||
final List<TcpConnection> added = new ArrayList<TcpConnection>();
|
||||
final List<TcpConnection> removed = new ArrayList<TcpConnection>();
|
||||
AbstractServerConnectionFactory scf = getConnectionFactory(serializer, new TcpListener() {
|
||||
@Override
|
||||
public boolean onMessage(Message<?> message) {
|
||||
responses.add(message);
|
||||
return false;
|
||||
|
||||
final CountDownLatch errorMessageLetch = new CountDownLatch(1);
|
||||
final AtomicReference<Throwable> errorMessageRef = new AtomicReference<Throwable>();
|
||||
|
||||
AbstractServerConnectionFactory scf = getConnectionFactory(serializer, message -> {
|
||||
if (message instanceof ErrorMessage) {
|
||||
errorMessageRef.set(((ErrorMessage) message).getPayload());
|
||||
errorMessageLetch.countDown();
|
||||
}
|
||||
return false;
|
||||
}, new TcpSender() {
|
||||
@Override
|
||||
public void addNewConnection(TcpConnection connection) {
|
||||
@@ -482,6 +523,12 @@ public class TcpNioConnectionReadTests {
|
||||
socket.close();
|
||||
whileOpen(semaphore, added);
|
||||
assertEquals(1, added.size());
|
||||
|
||||
assertTrue(errorMessageLetch.await(10, TimeUnit.SECONDS));
|
||||
|
||||
assertThat(errorMessageRef.get().getMessage(),
|
||||
containsString("Connection is closed"));
|
||||
|
||||
assertTrue(semaphore.tryAcquire(10000, TimeUnit.MILLISECONDS));
|
||||
assertTrue(removed.size() > 0);
|
||||
scf.stop();
|
||||
|
||||
Reference in New Issue
Block a user