polygene-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From paulmer...@apache.org
Subject zest-java git commit: Review FreePortFinder test utility to reduce test flakiness on CI
Date Mon, 07 Nov 2016 10:15:23 GMT
Repository: zest-java
Updated Branches:
  refs/heads/develop 246e588cd -> 420054295


Review FreePortFinder test utility to reduce test flakiness on CI


Project: http://git-wip-us.apache.org/repos/asf/zest-java/repo
Commit: http://git-wip-us.apache.org/repos/asf/zest-java/commit/42005429
Tree: http://git-wip-us.apache.org/repos/asf/zest-java/tree/42005429
Diff: http://git-wip-us.apache.org/repos/asf/zest-java/diff/42005429

Branch: refs/heads/develop
Commit: 420054295fe5138f61051bb33676afb7280b9ba5
Parents: 246e588
Author: Paul Merlin <paulmerlin@apache.org>
Authored: Mon Nov 7 11:15:09 2016 +0100
Committer: Paul Merlin <paulmerlin@apache.org>
Committed: Mon Nov 7 11:15:09 2016 +0100

----------------------------------------------------------------------
 .../apache/zest/test/util/FreePortFinder.java   | 190 +++++++++++++++++--
 .../zest/library/rest/admin/RestTest.java       |   2 +-
 .../zest/library/servlet/ServletTest.java       |   2 +-
 .../library/shiro/web/WebHttpShiroTest.java     |   2 +-
 .../library/shiro/web/WebRealmServiceTest.java  |   2 +-
 .../library/shiro/web/WebServletShiroTest.java  |   2 +-
 6 files changed, 176 insertions(+), 24 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/zest-java/blob/42005429/core/testsupport/src/main/java/org/apache/zest/test/util/FreePortFinder.java
----------------------------------------------------------------------
diff --git a/core/testsupport/src/main/java/org/apache/zest/test/util/FreePortFinder.java
b/core/testsupport/src/main/java/org/apache/zest/test/util/FreePortFinder.java
index f52a485..7f4eef5 100644
--- a/core/testsupport/src/main/java/org/apache/zest/test/util/FreePortFinder.java
+++ b/core/testsupport/src/main/java/org/apache/zest/test/util/FreePortFinder.java
@@ -20,42 +20,194 @@
 package org.apache.zest.test.util;
 
 import java.io.IOException;
+import java.io.UncheckedIOException;
 import java.net.InetAddress;
 import java.net.ServerSocket;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.OptionalInt;
+import java.util.function.IntPredicate;
+import java.util.stream.Stream;
+
+import static java.util.Collections.shuffle;
+import static java.util.stream.Collectors.collectingAndThen;
+import static java.util.stream.Collectors.toList;
+import static java.util.stream.IntStream.rangeClosed;
 
 public class FreePortFinder
 {
+    private static class Range
+    {
+        final int lowerBound;
+        final int higherBound;
+
+        private Range( int lowerBound, int higherBound )
+        {
+            this.lowerBound = lowerBound;
+            this.higherBound = higherBound;
+        }
+    }
+
+    // Presumably the least used port ranges with >500 slots
+    // See http://stackoverflow.com/a/28369841/300053
+    private static final List<Range> LEAST_USED_RANGES = Arrays.asList(
+        new Range( 29170, 29998 ),
+        new Range( 38866, 39680 ),
+        new Range( 41798, 42507 ),
+        new Range( 43442, 44122 ),
+        new Range( 46337, 46997 ),
+        new Range( 35358, 36000 ),
+        new Range( 36866, 37474 ),
+        new Range( 38204, 38799 ),
+        new Range( 33657, 34248 ),
+        new Range( 30261, 30831 ),
+        new Range( 41231, 41793 ),
+        new Range( 21011, 21552 ),
+        new Range( 28590, 29117 ),
+        new Range( 14415, 14935 ),
+        new Range( 26490, 26999 )
+    );
+
+    private static final int MAX_PORT_CHECKS = 20;
+
+    public static boolean isFreePortOnLocalHost( int port )
+    {
+        return isFreePort( getLocalHostUnchecked(), port );
+    }
+
+    public static boolean isFreePort( InetAddress address, int port )
+    {
+        try
+        {
+            checkFreePort( address, port );
+            return true;
+        }
+        catch( IOException ex )
+        {
+            return false;
+        }
+    }
+
+    public static void checkFreePortOnLocalHost( int port ) throws IOException
+    {
+        checkFreePort( getLocalHostUnchecked(), port );
+    }
 
-    public static int findFreePortOnLoopback()
-            throws IOException
+    public static void checkFreePort( InetAddress address, int port ) throws IOException
     {
-        return findFreePortOnIface( InetAddress.getLocalHost() );
+        ServerSocket server = null;
+        try
+        {
+            server = new ServerSocket( port, 1, address );
+        }
+        finally
+        {
+            if( server != null )
+            {
+                try
+                {
+                    server.close();
+                }
+                catch( IOException e )
+                {
+                    // Ignore
+                }
+            }
+        }
     }
 
-    public static int findFreePortOnLoopback( int prefered )
-            throws IOException
+    public static int findFreePortOnLocalHost()
+        throws IOException
     {
-        return findFreePortOnIface( InetAddress.getLocalHost(), prefered );
+        return findFreePort( getLocalHostUnchecked() );
     }
 
-    public static int findFreePortOnIface( InetAddress address )
-            throws IOException
+    public static int findFreePort( InetAddress address )
+        throws IOException
     {
-        return findFreePortOnIface( address, -1 );
+        FreePortPredicate check = new FreePortPredicate( address );
+        // Randomly choose MAX_PORT_CHECKS ports from the least used ranges
+        OptionalInt port = LEAST_USED_RANGES.stream()
+            .flatMapToInt( range -> rangeClosed( range.lowerBound, range.higherBound )
)
+            .boxed()
+            .collect( collectingAndThen( toList(), collected ->
+            {
+              shuffle( collected );
+              return collected.stream();
+            } ) )
+            .limit( MAX_PORT_CHECKS )
+            .mapToInt( Integer::intValue )
+            .filter( check )
+            .findFirst();
+        return port.orElseThrow( () ->
+        {
+            IOException exception = new IOException( "Unable to find a free port on " + address
);
+            check.errors.build().forEach( exception::addSuppressed );
+            return exception;
+        } );
     }
 
-    public static int findFreePortOnIface( InetAddress address, int prefered )
-            throws IOException
+    public static int findFreePortInRangeOnLocalhost( int lowerBound, int higherBound )
+        throws IOException
     {
-        ServerSocket server;
-        if ( prefered > 0 ) {
-            server = new ServerSocket( prefered, 1, address );
-        } else {
-            server = new ServerSocket( 0, 1, address );
+        return findFreePortInRange( getLocalHostUnchecked(), lowerBound, higherBound );
+    }
+
+    public static int findFreePortInRange( InetAddress address, int lowerBound, int higherBound
)
+        throws IOException
+    {
+        if( higherBound - lowerBound < 0 )
+        {
+            throw new IllegalArgumentException( "Invalid port range " + lowerBound + '-'
+ higherBound );
         }
-        int port = server.getLocalPort();
-        server.close();
-        return port;
+        FreePortPredicate check = new FreePortPredicate( address );
+        OptionalInt port = rangeClosed( lowerBound, higherBound ).filter( check ).findFirst();
+        return port.orElseThrow( () ->
+        {
+            String message = "Unable to find a free port in range " + lowerBound + '-' +
higherBound + " on " + address;
+            IOException exception = new IOException( message );
+            check.errors.build().forEach( exception::addSuppressed );
+            return exception;
+        } );
     }
 
+    private static class FreePortPredicate implements IntPredicate
+    {
+        private final InetAddress address;
+        private final Stream.Builder<Throwable> errors;
+
+        private FreePortPredicate( InetAddress address )
+        {
+            this.address = address;
+            this.errors = Stream.builder();
+        }
+
+        @Override
+        public boolean test( int candidate )
+        {
+            try
+            {
+                checkFreePort( address, candidate );
+                return true;
+            }
+            catch( IOException ex )
+            {
+                errors.add( ex );
+                return false;
+            }
+        }
+    }
+
+    private static InetAddress getLocalHostUnchecked()
+    {
+        try
+        {
+            return InetAddress.getLocalHost();
+        }
+        catch( UnknownHostException ex )
+        {
+            throw new UncheckedIOException( ex );
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/zest-java/blob/42005429/libraries/rest/src/test/java/org/apache/zest/library/rest/admin/RestTest.java
----------------------------------------------------------------------
diff --git a/libraries/rest/src/test/java/org/apache/zest/library/rest/admin/RestTest.java
b/libraries/rest/src/test/java/org/apache/zest/library/rest/admin/RestTest.java
index fef807b..0bec7e8 100644
--- a/libraries/rest/src/test/java/org/apache/zest/library/rest/admin/RestTest.java
+++ b/libraries/rest/src/test/java/org/apache/zest/library/rest/admin/RestTest.java
@@ -74,7 +74,7 @@ public class RestTest extends AbstractZestTest
     {
         try
         {
-            ADMIN_PORT = FreePortFinder.findFreePortOnLoopback();
+            ADMIN_PORT = FreePortFinder.findFreePortOnLocalHost();
         }
         catch( IOException ex )
         {

http://git-wip-us.apache.org/repos/asf/zest-java/blob/42005429/libraries/servlet/src/test/java/org/apache/zest/library/servlet/ServletTest.java
----------------------------------------------------------------------
diff --git a/libraries/servlet/src/test/java/org/apache/zest/library/servlet/ServletTest.java
b/libraries/servlet/src/test/java/org/apache/zest/library/servlet/ServletTest.java
index 29aa1eb..a0dda4e 100644
--- a/libraries/servlet/src/test/java/org/apache/zest/library/servlet/ServletTest.java
+++ b/libraries/servlet/src/test/java/org/apache/zest/library/servlet/ServletTest.java
@@ -88,7 +88,7 @@ public class ServletTest
     public void test()
             throws Exception
     {
-        int port = FreePortFinder.findFreePortOnLoopback( 9001 );
+        int port = FreePortFinder.findFreePortOnLocalHost();
         Server server = new Server( port );
         try {
 

http://git-wip-us.apache.org/repos/asf/zest-java/blob/42005429/libraries/shiro-web/src/test/java/org/apache/zest/library/shiro/web/WebHttpShiroTest.java
----------------------------------------------------------------------
diff --git a/libraries/shiro-web/src/test/java/org/apache/zest/library/shiro/web/WebHttpShiroTest.java
b/libraries/shiro-web/src/test/java/org/apache/zest/library/shiro/web/WebHttpShiroTest.java
index c6d54a9..95d9dca 100644
--- a/libraries/shiro-web/src/test/java/org/apache/zest/library/shiro/web/WebHttpShiroTest.java
+++ b/libraries/shiro-web/src/test/java/org/apache/zest/library/shiro/web/WebHttpShiroTest.java
@@ -49,7 +49,7 @@ public class WebHttpShiroTest
             new JettyServiceAssembler().withConfig( configModule, Visibility.layer ).assemble(
module );
             // END SNIPPET: assembly
 
-            port = FreePortFinder.findFreePortOnLoopback();
+            port = FreePortFinder.findFreePortOnLocalHost();
             JettyConfiguration config = module.forMixin( JettyConfiguration.class ).declareDefaults();
             config.hostName().set( "127.0.0.1" );
             config.port().set( port );

http://git-wip-us.apache.org/repos/asf/zest-java/blob/42005429/libraries/shiro-web/src/test/java/org/apache/zest/library/shiro/web/WebRealmServiceTest.java
----------------------------------------------------------------------
diff --git a/libraries/shiro-web/src/test/java/org/apache/zest/library/shiro/web/WebRealmServiceTest.java
b/libraries/shiro-web/src/test/java/org/apache/zest/library/shiro/web/WebRealmServiceTest.java
index d810dd3..0b2aaea 100644
--- a/libraries/shiro-web/src/test/java/org/apache/zest/library/shiro/web/WebRealmServiceTest.java
+++ b/libraries/shiro-web/src/test/java/org/apache/zest/library/shiro/web/WebRealmServiceTest.java
@@ -143,7 +143,7 @@ public class WebRealmServiceTest
             new JettyServiceAssembler().withConfig( configModule, Visibility.layer ).assemble(
module );
             // END SNIPPET: assembly
 
-            port = FreePortFinder.findFreePortOnLoopback();
+            port = FreePortFinder.findFreePortOnLocalHost();
             JettyConfiguration config = module.forMixin( JettyConfiguration.class ).declareDefaults();
             config.hostName().set( "127.0.0.1" );
             config.port().set( port );

http://git-wip-us.apache.org/repos/asf/zest-java/blob/42005429/libraries/shiro-web/src/test/java/org/apache/zest/library/shiro/web/WebServletShiroTest.java
----------------------------------------------------------------------
diff --git a/libraries/shiro-web/src/test/java/org/apache/zest/library/shiro/web/WebServletShiroTest.java
b/libraries/shiro-web/src/test/java/org/apache/zest/library/shiro/web/WebServletShiroTest.java
index 73c9a4a..7eb5245 100644
--- a/libraries/shiro-web/src/test/java/org/apache/zest/library/shiro/web/WebServletShiroTest.java
+++ b/libraries/shiro-web/src/test/java/org/apache/zest/library/shiro/web/WebServletShiroTest.java
@@ -36,7 +36,7 @@ public class WebServletShiroTest
     public void test()
             throws Exception
     {
-        int port = FreePortFinder.findFreePortOnLoopback( 9001 );
+        int port = FreePortFinder.findFreePortOnLocalHost();
         Server server = new Server( port );
         try {
 


Mime
View raw message