[TESTS] Set SO_LINGER and SO_REUSEADDR on the mock socket (#34211)

In SessionFactoryLoadBalancingTests#testRoundRobinWithFailures()
we kill ldap servers randomly and immediately bind to that port
connecting to mock server socket. This is done to avoid someone else
listening to this port. As the creation of mock socket and binding to the
port is immediate, sometimes the earlier socket would be in TIME_WAIT state
thereby having problems with either bind or connect.
This commit sets the SO_REUSEADDR explicitly to true and also sets
the linger on time to 0(as we are not writing any data) so as to
allow re-use of the port and close immediately.

Note: I could not find other places where this might be problematic
but looking at test runs and netstat output I do see lot of sockets
in TIME_WAIT. If we find that this needs to be addressed we can
wrap ServerSocketFactory to set these options and use that with in
memory ldap server configuration during tests.

Closes #32190
This commit is contained in:
Yogesh Gaikwad 2018-10-04 08:23:59 +10:00 committed by GitHub
parent a21a99da18
commit f79282e47d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 15 additions and 1 deletions

View File

@ -8,6 +8,7 @@ package org.elasticsearch.xpack.security.authc.ldap.support;
import com.unboundid.ldap.listener.InMemoryDirectoryServer;
import com.unboundid.ldap.sdk.LDAPConnection;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
@ -17,6 +18,7 @@ import org.elasticsearch.mocksocket.MockSocket;
import org.elasticsearch.test.junit.annotations.TestLogging;
import org.elasticsearch.threadpool.TestThreadPool;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.xpack.core.common.socket.SocketAccess;
import org.elasticsearch.xpack.core.security.authc.RealmConfig;
import org.elasticsearch.xpack.core.security.authc.ldap.support.LdapSearchScope;
import org.elasticsearch.xpack.core.ssl.SSLService;
@ -25,6 +27,7 @@ import org.junit.Before;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Arrays;
@ -112,7 +115,7 @@ public class SessionFactoryLoadBalancingTests extends LdapTestCase {
// of the ldap server and the opening of the socket
logger.debug("opening mock server socket listening on [{}]", port);
Runnable runnable = () -> {
try (Socket socket = new MockSocket(InetAddress.getByName("localhost"), mockServerSocket.getLocalPort(), local, port)) {
try (Socket socket = openMockSocket(local, mockServerSocket.getLocalPort(), local, port)) {
logger.debug("opened socket [{}]", socket);
latch.countDown();
closeLatch.await();
@ -149,6 +152,17 @@ public class SessionFactoryLoadBalancingTests extends LdapTestCase {
}
}
@SuppressForbidden(reason = "Allow opening socket for test")
private MockSocket openMockSocket(InetAddress remoteAddress, int remotePort, InetAddress localAddress, int localPort)
throws IOException {
final MockSocket socket = new MockSocket();
socket.setReuseAddress(true); // allow binding even if the previous socket is in timed wait state.
socket.setSoLinger(true, 0); // close immediately as we are not writing anything here.
socket.bind(new InetSocketAddress(localAddress, localPort));
SocketAccess.doPrivileged(() -> socket.connect(new InetSocketAddress(localAddress, remotePort)));
return socket;
}
public void testFailover() throws Exception {
assumeTrue("at least one ldap server should be present for this test", ldapServers.length > 1);
logger.debug("using [{}] ldap servers, urls {}", ldapServers.length, ldapUrls());