package net.serenitybdd.integration.jenkins.environment.rules;
import net.serenitybdd.integration.jenkins.JenkinsInstance;
import org.junit.rules.TestRule;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.net.ServerSocket;
import static com.google.common.base.Preconditions.checkArgument;
import static java.lang.String.format;
public class FindFreePort implements ApplicativeTestRule<JenkinsInstance> {
private static final Logger Log = LoggerFactory.getLogger(FindFreePort.class);
private static final int Dynamic_Range_Start = 49152;
private static final int Dynamic_Range_End = 65535;
private final int rangeStart;
private final int rangeEnd;
public static FindFreePort useFreePortFromDynamicRange() {
return new FindFreePort(Dynamic_Range_Start, Dynamic_Range_End);
}
public static FindFreePort useFreePortFromTheFollowingRange(int rangeStart, int rangeEnd) {
return new FindFreePort(rangeStart, rangeEnd);
}
public FindFreePort(int rangeStart, int rangeEnd) {
checkArgument(rangeStart <= rangeEnd, format("Start of the port range (%d) should be lower than the end of the range (%d)", rangeStart, rangeEnd));
this.rangeStart = rangeStart;
this.rangeEnd = rangeEnd;
}
@Override
public TestRule applyTo(final JenkinsInstance instance) {
return new TestWatcher() {
@Override
protected void starting(Description description) {
int portNumber = anyFreeLocalPortInRange(rangeStart, rangeEnd);
Log.info("Found a free port: {}", portNumber);
instance.setPort(portNumber);
}
};
}
private int anyFreeLocalPortInRange(int from, int to){
while(true){
int candidate = (int) ((Math.random() * (to - from)) + from);
if(isFree(candidate)){
return candidate;
}
}
}
private boolean isFree(int port){
try {
ServerSocket ss = new ServerSocket(port);
ss.close();
return true;
}
catch (IOException ex) {
return false;
}
}
}