Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Getting Hold of an Unused Port When Writing a Test

DZone's Guide to

Getting Hold of an Unused Port When Writing a Test

How to use an unused port when writing a test with JAX-RS and Java.

· DevOps Zone
Free Resource

“Automated Testing: The Glue That Holds DevOps Together” to learn about the key role automated testing plays in a DevOps workflow, brought to you in partnership with Sauce Labs.

A really quick post today, I was writing a unit test that needed to put up a temporary JAX-RS resource in order to test something very specific with out the need of a large testing framework. Unfortunately the code I was using didn't know about replacing zero with a random allocated port so I had to do something different. The nice tidy code that does this looks like the following:

try(ServerSocket ss = new ServerSocket(0)) {
 freePort = ss.getLocalPort();
}

server = createServerWithPort(freePort);

But of course there is a race condition here as there could be another process on the machine running the exact same code that gets lucky with its time on the CPU — note the API I was using couldn't use the ServerSocket directly so there is a gap where the port is not tied up. So to rule out the one in a million failure chance, which always comes on a Friday at 5pm, we need to wrap this code in a loop.

while(server==null) {
 try(ServerSocket ss = new ServerSocket(0)) {
 freePort = ss.getLocalPort();
 }

 server = createServerWithPort(freePort);
}

This may seem extreme; but if you are running some kind of CI system like Hudson or Jenkins it is not unusual to be running multiple executors on the same machine. You might have two developers running preflights at the same time causing an annoying intermittent failure as described above.

Finally a version using a JDK 8 stream with a helper method to convert the IOException from ServerSocket into a RuntimeException. Some would argue this is less readable; but I find it more explicit.

server = Stream.generate(convertException(() -> {
 try(ServerSocket ss = new ServerSocket(0)) {
 return ss.getLocalPort();
 }
})).map(TestClass::createServerWithPort)
.filter(Objects::nonNull)
.findFirst().get();

Learn about the importance of automated testing as part of a healthy DevOps practice, brought to you in partnership with Sauce Labs.

Topics:
java ,ci

Published at DZone with permission of Gerard Davison, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}