8264190: Harden TLS interop tests

Reviewed-by: rhalade
diff --git a/test/jdk/javax/net/ssl/TLSCommon/interop/BaseInteropTest.java b/test/jdk/javax/net/ssl/TLSCommon/interop/BaseInteropTest.java
index c5ef03d..1e83c47 100644
--- a/test/jdk/javax/net/ssl/TLSCommon/interop/BaseInteropTest.java
+++ b/test/jdk/javax/net/ssl/TLSCommon/interop/BaseInteropTest.java
@@ -39,6 +39,7 @@
 
     protected final Product serverProduct;
     protected final Product clientProduct;
+    private static final int MAX_SERVER_RETRIES = 3;
 
     public BaseInteropTest(Product serverProduct, Product clientProduct) {
         this.serverProduct = serverProduct;
@@ -169,8 +170,7 @@
         ExecutorService executor = Executors.newFixedThreadPool(1);
         AbstractServer server = null;
         try {
-            server = createServer(testCase.serverCase);
-            executor.submit(new ServerTask(server));
+            server = startAndGetServer(testCase.serverCase, executor);
             int port = server.getPort();
             System.out.println("Server is listening " + port);
             serverStatus = Status.PASS;
@@ -226,6 +226,33 @@
     }
 
     /*
+     * Return a server once it is properly started to avoid client connection issues.
+     * Retry operation if needed, server may fail to bind a port
+     */
+    protected AbstractServer startAndGetServer(U useCase, ExecutorService executor)
+            throws Exception {
+        int maxRetries = getServerMaxRetries();
+        boolean serverAlive;
+        AbstractServer server;
+
+        do {
+            server = createServer(useCase, executor);
+            serverAlive = Utilities.waitFor(Server::isAlive, server);
+            if (!serverAlive) {
+                server.signalStop();
+            }
+
+            maxRetries--;
+        } while (!serverAlive && maxRetries > 0);
+
+        if (!serverAlive) {
+            throw new RuntimeException("Server failed to start");
+        }
+
+        return server;
+    }
+
+    /*
      * Handles server side exception, and determines the status.
      */
     protected Status handleServerException(Exception exception) {
@@ -251,8 +278,10 @@
     /*
      * Creates server.
      */
-    protected AbstractServer createServer(U useCase) throws Exception {
-        return createServerBuilder(useCase).build();
+    protected AbstractServer createServer(U useCase, ExecutorService executor) throws Exception {
+        AbstractServer server = createServerBuilder(useCase).build();
+        executor.submit(new ServerTask(server));
+        return server;
     }
 
     protected AbstractServer.Builder createServerBuilder(U useCase)
@@ -280,6 +309,13 @@
     }
 
     /*
+     * Returns the maximum number of attempts to start a server.
+     */
+    protected int getServerMaxRetries() {
+        return MAX_SERVER_RETRIES;
+    }
+
+    /*
      * Determines the negotiated application protocol.
      * Generally, using JDK client to get this value.
      */
diff --git a/test/jdk/javax/net/ssl/TLSCommon/interop/JdkServer.java b/test/jdk/javax/net/ssl/TLSCommon/interop/JdkServer.java
index 8082aa7..6519e89 100644
--- a/test/jdk/javax/net/ssl/TLSCommon/interop/JdkServer.java
+++ b/test/jdk/javax/net/ssl/TLSCommon/interop/JdkServer.java
@@ -142,7 +142,7 @@
 
     @Override
     public void close() throws IOException {
-        if (isAlive()) {
+        if (!serverSocket.isClosed()) {
             serverSocket.close();
         }
     }
diff --git a/test/jdk/javax/net/ssl/TLSCommon/interop/ProcUtils.java b/test/jdk/javax/net/ssl/TLSCommon/interop/ProcUtils.java
index f365ade..10cb3d6 100644
--- a/test/jdk/javax/net/ssl/TLSCommon/interop/ProcUtils.java
+++ b/test/jdk/javax/net/ssl/TLSCommon/interop/ProcUtils.java
@@ -21,8 +21,10 @@
  * questions.
  */
 
+import java.io.IOException;
 import java.nio.file.Path;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 
@@ -40,7 +42,7 @@
      */
     public static OutputAnalyzer java(Path javaPath, Class<?> clazz,
             Map<String, String> props) {
-        ProcessBuilder pb = createProcessBuilder(javaPath, clazz, props);
+        ProcessBuilder pb = createJavaProcessBuilder(javaPath, clazz, props);
         try {
             return ProcessTools.executeCommand(pb);
         } catch (Throwable e) {
@@ -48,7 +50,7 @@
         }
     }
 
-    private static ProcessBuilder createProcessBuilder(Path javaPath,
+    private static ProcessBuilder createJavaProcessBuilder(Path javaPath,
             Class<?> clazz, Map<String, String> props) {
         List<String> cmds = new ArrayList<>();
         cmds.add(javaPath.toString());
@@ -66,4 +68,77 @@
         pb.redirectErrorStream(true);
         return pb;
     }
+
+    /*
+     * Executes a shell command and return a OutputAnalyzer wrapping the process.
+     */
+    public static OutputAnalyzer shell(String command, Map<String, String> env)
+            throws IOException {
+        Process process = shellProc(command, null, env);
+        return getProcessOutput(process);
+    }
+
+    /*
+     * Executes win command and return a OutputAnalyzer wrapping the process.
+     */
+    public static OutputAnalyzer win(String command, Map<String, String> env)
+            throws IOException {
+        Process process = winProc(command, null, env);
+        return getProcessOutput(process);
+    }
+
+    /*
+     * Executes a shell command and return the process.
+     */
+    public static Process shellProc(String command, Path outputPath,
+                                    Map<String, String> env) throws IOException {
+        String[] cmds = new String[3];
+        cmds[0] = "sh";
+        cmds[1] = "-c";
+        cmds[2] = command;
+        return startAndGetProc(cmds, outputPath, env);
+    }
+
+    /*
+     * Executes a win command and returns the process.
+     */
+    public static Process winProc(String command, Path outputPath,
+                                  Map<String, String> env)
+            throws IOException {
+        String[] cmds = new String[3];
+        cmds[0] = "cmd.exe";
+        cmds[1] = "/C";
+        cmds[2] = command;
+        return startAndGetProc(cmds, outputPath, env);
+    }
+
+    /*
+     * Returns a OutputAnalyzer wrapping the process.
+     */
+    private static OutputAnalyzer getProcessOutput (Process process) throws IOException {
+        OutputAnalyzer oa = new OutputAnalyzer(process);
+        try {
+            process.waitFor();
+            return oa;
+        } catch (InterruptedException e) {
+            throw new RuntimeException("Process is interrupted!", e);
+        }
+    }
+
+    /*
+     * Executes a command, redirects the output to a local file and returns the process.
+     */
+    private static Process startAndGetProc(String[] cmds, Path outputPath, Map<String,
+            String> env) throws IOException {
+        System.out.println("command to run: " + Arrays.toString(cmds));
+        ProcessBuilder pb = new ProcessBuilder(cmds);
+        if (env != null) {
+            pb.environment().putAll(env);
+        }
+        pb.redirectErrorStream(true);
+        if (outputPath != null) {
+            pb.redirectOutput(outputPath.toFile());
+        }
+        return pb.start();
+    }
 }
diff --git a/test/jdk/javax/net/ssl/TLSCommon/interop/Server.java b/test/jdk/javax/net/ssl/TLSCommon/interop/Server.java
index b8fd72f..50f546f 100644
--- a/test/jdk/javax/net/ssl/TLSCommon/interop/Server.java
+++ b/test/jdk/javax/net/ssl/TLSCommon/interop/Server.java
@@ -42,7 +42,7 @@
     /*
      * Checks if the peer is alive.
      */
-    public boolean isAlive() throws IOException;
+    public boolean isAlive();
 
     /*
      * Signals the server to stop if necessary.
diff --git a/test/jdk/javax/net/ssl/TLSCommon/interop/Utilities.java b/test/jdk/javax/net/ssl/TLSCommon/interop/Utilities.java
index 735c72a..34cccb5 100644
--- a/test/jdk/javax/net/ssl/TLSCommon/interop/Utilities.java
+++ b/test/jdk/javax/net/ssl/TLSCommon/interop/Utilities.java
@@ -219,15 +219,17 @@
      */
     public static <T> boolean waitFor(Predicate<T> predicate, T t) {
         long deadline = System.currentTimeMillis() + Utilities.TIMEOUT * 1000;
-        while (!predicate.test(t) && System.currentTimeMillis() < deadline) {
+        boolean predicateResult = predicate.test(t);
+        while (!predicateResult && System.currentTimeMillis() < deadline) {
             try {
                 TimeUnit.SECONDS.sleep(1);
+                predicateResult = predicate.test(t);
             } catch (InterruptedException e) {
                 throw new RuntimeException("Sleep is interrupted.", e);
             }
         }
 
-        return predicate.test(t);
+        return predicateResult;
     }
 
     /*
@@ -278,48 +280,6 @@
     }
 
     /*
-     * Executes shell command and return a OutputAnalyzer wrapping the process.
-     */
-    public static OutputAnalyzer shell(String command) throws IOException {
-        Process process = shellProc(command);
-        OutputAnalyzer oa = new OutputAnalyzer(process);
-        try {
-            process.waitFor();
-            return oa;
-        } catch (InterruptedException e) {
-            throw new RuntimeException("Shell process is interruptted!", e);
-        }
-    }
-
-    /*
-     * Executes shell command and redirect the output to a local file,
-     * and return the process.
-     */
-    public static Process shellProc(String command, Path outputPath)
-            throws IOException {
-        String[] cmds = new String[3];
-        cmds[0] = "sh";
-        cmds[1] = "-c";
-        cmds[2] = command;
-        if (DEBUG) {
-            System.out.println("[sh -c " + command + "]");
-        }
-        ProcessBuilder pb = new ProcessBuilder(cmds);
-        pb.redirectErrorStream(true);
-        if (outputPath != null) {
-            pb.redirectOutput(outputPath.toFile());
-        }
-        return pb.start();
-    }
-
-    /*
-     * Executes shell command and return the process.
-     */
-    public static Process shellProc(String command) throws IOException {
-        return shellProc(command, null);
-    }
-
-    /*
      * Determines if the specified process is alive.
      */
     public static boolean isAliveProcess(Process process) {
@@ -377,14 +337,14 @@
      */
     public static boolean isSessionResumed(ResumptionMode mode,
             byte[] firstSessionId, byte[] secondSessionId,
-            long secondConnStartTime, long secondSessionCreationTime) {
+            long firstSessionCreationTime, long secondSessionCreationTime) {
         System.out.println("ResumptionMode: " + mode);
         System.out.println("firstSessionId: " + Arrays.toString(firstSessionId));
         System.out.println("secondSessionId: " + Arrays.toString(secondSessionId));
-        System.out.println("secondConnStartTime: " + secondConnStartTime);
+        System.out.println("firstSessionCreationTime: " + firstSessionCreationTime);
         System.out.println("secondSessionCreationTime: " + secondSessionCreationTime);
 
-        boolean resumed = secondConnStartTime > secondSessionCreationTime;
+        boolean resumed = firstSessionCreationTime == secondSessionCreationTime;
         if (mode == ResumptionMode.ID) {
             resumed = resumed && firstSessionId.length > 0
                     && Arrays.equals(firstSessionId, secondSessionId);