1111
1212import java .io .File ;
1313import java .io .IOException ;
14+ import java .net .InetSocketAddress ;
15+ import java .net .Socket ;
1416import java .nio .file .Files ;
1517
1618import javax .net .SocketFactory ;
@@ -38,6 +40,7 @@ public class ExternalDockerClientFilter implements ExternalTestServiceFilter {
3840 * Helpful when a developer wants to have repeatable behavior, or is remotely connected to a specific docker host.
3941 */
4042 private static final String FORCE_DOCKER_HOST = System .getProperty ("fat.test.docker.host" );
43+ private static final String CHECK_PORT_AVAILABLE = System .getProperty ("fat.test.docker.host.port" );
4144
4245 private boolean valid ;
4346 private String host ;
@@ -61,6 +64,14 @@ public boolean isForced() {
6164 return FORCE_DOCKER_HOST != null ;
6265 }
6366
67+ public boolean checkPortAvailability () {
68+ try {
69+ return CHECK_PORT_AVAILABLE != null && Integer .valueOf (CHECK_PORT_AVAILABLE ) >= 0 ;
70+ } catch (NumberFormatException nfe ) {
71+ return false ;
72+ }
73+ }
74+
6475 /**
6576 * Determines if this docker host is healthy.
6677 *
@@ -79,6 +90,13 @@ public boolean isMatched(ExternalTestService dockerService) {
7990 return false ;
8091 }
8192
93+ if (checkPortAvailability ()) {
94+ if (!isPortAvailable (dockerService .getAddress (), Integer .valueOf (CHECK_PORT_AVAILABLE ))) {
95+ Log .info (c , m , "Will not select " + dockerHostURL + " because port " + CHECK_PORT_AVAILABLE + " was not available." );
96+ return false ;
97+ }
98+ }
99+
82100 String ca = dockerService .getProperties ().get ("ca.pem" );
83101 String cert = dockerService .getProperties ().get ("cert.pem" );
84102 String key = dockerService .getProperties ().get ("key.pem" );
@@ -92,6 +110,7 @@ public boolean isMatched(ExternalTestService dockerService) {
92110
93111 File certDir = new File ("docker-certificates" );
94112 certDir .mkdirs ();
113+
95114 writeFile (new File (certDir , "ca.pem" ), ca );
96115 writeFile (new File (certDir , "cert.pem" ), cert );
97116 writeFile (new File (certDir , "key.pem" ), key );
@@ -121,6 +140,32 @@ public boolean isMatched(ExternalTestService dockerService) {
121140 return valid = true ;
122141 }
123142
143+ /**
144+ * isPortAvailable() is used to determine if the docker service has a specific host port available.
145+ * This is used as filter criteria for tests that need a specific host port available.
146+ *
147+ * @param host The host name or address to check
148+ * @param port The port on the host to test
149+ * @return True if the host does not accept a socket connection on the given port, false otherwise.
150+ */
151+ private boolean isPortAvailable (String host , int port ) {
152+ String prefix = "tcp://" ;
153+ if (host .startsWith (prefix )) {
154+ host = host .substring (prefix .length ());
155+ }
156+
157+ try (Socket socket = new Socket ()) {
158+ socket .connect (new InetSocketAddress (host , port ), 5000 );
159+ return false ;
160+ } catch (IOException ex ) {
161+ // An exception here means the host wasn't listening on the port specified. This means the port should be available
162+ // for the client to attach once it's started.
163+ Log .info (c , "isPortAvailable" , "Port " + port + " is available on host " + host );
164+ }
165+ return true ;
166+
167+ }
168+
124169 /**
125170 * Fail fast here! Never repeat this test!
126171 *
0 commit comments