2222import static org .junit .jupiter .api .Assertions .assertTrue ;
2323
2424import java .io .IOException ;
25+ import java .net .BindException ;
2526import java .net .ServerSocket ;
2627import java .net .Socket ;
2728import java .net .SocketAddress ;
3334import java .nio .channels .SocketChannel ;
3435import java .time .Duration ;
3536import java .time .temporal .ChronoUnit ;
37+ import java .util .ArrayList ;
3638import java .util .Arrays ;
3739import java .util .List ;
3840import java .util .concurrent .CompletableFuture ;
@@ -73,28 +75,45 @@ public abstract class InterruptIssue158Test<A extends SocketAddress> extends Soc
7375 private static boolean DELAY_CLOSE = SystemPropertyUtil .getBooleanSystemProperty (
7476 "selftest.issue.158.delay-close" , true );
7577
76- private final A address ;
78+ private A address = newAddress () ;
7779 private TestInfo testInfo ;
80+ private List <AutoCloseable > closeables = new ArrayList <>();
7881
79- @ SuppressWarnings ("unchecked" )
8082 protected InterruptIssue158Test (AddressSpecifics <A > asp ) {
8183 super (asp );
84+ }
85+
86+ @ BeforeEach
87+ public void beforeEach (TestInfo info ) {
88+ this .testInfo = info ;
89+ this .address = newAddress ();
90+ }
8291
92+ @ SuppressWarnings ("unchecked" )
93+ private A newAddress () {
8394 try {
84- address = (A ) newTempAddress ();
95+ return (A ) newTempAddress ();
8596 } catch (IOException e ) {
8697 throw new RuntimeException (e );
8798 }
8899 }
89100
90- @ BeforeEach
91- public void beforeEach (TestInfo info ) {
92- this .testInfo = info ;
101+ private void closeAfterTest () {
102+ deleteSocketFile (address );
103+
104+ for (AutoCloseable cl : closeables ) {
105+ try {
106+ cl .close ();
107+ } catch (Exception e ) {
108+ // ignore
109+ }
110+ }
111+ closeables .clear ();
93112 }
94113
95114 @ AfterEach
96115 public void afterEach () {
97- deleteSocketFile ( address );
116+ closeAfterTest ( );
98117 }
99118
100119 protected abstract void deleteSocketFile (A sa );
@@ -119,7 +138,7 @@ public List<Arguments> clientProvider() {
119138
120139 public List <Arguments > serverProvider () {
121140 return Arrays .asList ( //
122- serverSocket (() -> newServerSocketBindOn (address ), ServerSocket ::accept ,
141+ serverSocket (() -> registerCloseable ( newServerSocketBindOn (address ) ), ServerSocket ::accept ,
123142 SocketException .class , ServerSocket ::isClosed ), //
124143 serverSocket (this ::bindServerSocketChannel , ServerSocketChannel ::accept ,
125144 ClosedByInterruptException .class , s -> !s .isOpen ())//
@@ -175,17 +194,30 @@ public <T extends AutoCloseable> void testSocketInterruption(boolean delay, IOSu
175194 t .interrupt ();
176195 t .join (Duration .of (1 , ChronoUnit .SECONDS ).toMillis ());
177196 if (t .isAlive ()) {
178- throw new RuntimeException ("Thread failed to terminate after interrupt" );
197+ // Thread.interrupt is not guaranteed to succeed
198+ // observed with graalvm-jdk-17.0.9+11.1 when building with agent for junixsocket-native-graalvm
199+ // What we need to do here is to close all socket-related resources and try again
200+ closeAfterTest ();
201+ t .interrupt ();
202+ t .join (Duration .of (1 , ChronoUnit .SECONDS ).toMillis ());
203+ if (t .isAlive ()) {
204+ throw new RuntimeException ("Thread failed to terminate after interrupt" );
205+ }
179206 }
180207 Throwable thrownException = exceptionHolder .get ();
181208 if (thrownException != null ) {
182209 throw thrownException ;
183210 }
184211 }
185212
213+ private <C extends AutoCloseable > C registerCloseable (C closeable ) {
214+ closeables .add (closeable );
215+ return closeable ;
216+ }
217+
186218 private void withServer (boolean acceptConnections , ThrowingRunnable func ) throws Throwable {
187219 Semaphore done = new Semaphore (0 );
188- try (ServerSocketChannel serverSocket = newServerSocketChannel ()) {
220+ try (ServerSocketChannel serverSocket = registerCloseable ( newServerSocketChannel () )) {
189221 serverSocket .bind (address );
190222 Thread serverThread = null ;
191223 if (acceptConnections ) {
@@ -249,7 +281,7 @@ <T extends AutoCloseable> Throwable runOperation(CountDownLatch ready, IOSupplie
249281 Exception exc = null ;
250282 try {
251283 @ SuppressWarnings ({"resource" })
252- T sock = socket .get ();
284+ T sock = registerCloseable ( socket .get () );
253285 ready .countDown ();
254286
255287 supported = true ;
@@ -314,14 +346,25 @@ private static <T> Arguments serverSocket(IOSupplier<T> socket, IOConsumer<T> bl
314346 }
315347
316348 private SocketChannel connectSocketChannel () throws IOException {
317- SocketChannel socket = newSocketChannel ();
349+ SocketChannel socket = registerCloseable ( newSocketChannel () );
318350 socket .connect (address );
319351 return socket ;
320352 }
321353
322354 private ServerSocketChannel bindServerSocketChannel () throws IOException {
323- ServerSocketChannel socket = newServerSocketChannel ();
324- socket .bind (address );
355+ ServerSocketChannel socket = registerCloseable (newServerSocketChannel ());
356+ try {
357+ try {
358+ socket .bind (address );
359+ } catch (BindException e ) {
360+ // With Inet sockets, our reserved address may just have been taken by another process
361+ // so let's try again
362+ address = newAddress ();
363+ socket .bind (address );
364+ }
365+ } catch (BindException e ) {
366+ throw (BindException ) new BindException (e .getMessage () + ": " + address ).initCause (e );
367+ }
325368 return socket ;
326369 }
327370
0 commit comments