Debugging a Wiremock issue and thoughts on how to have better APIs
@Rule
public WireMockRule rule = new WireMockRule(
WireMockConfiguration.wireMockConfig()
.keystorePath("src/test/resources/ssl/yesbank/keystore.jks")
.keystorePassword("test")
.trustStorePath("src/test/resources/ssl/yesbank/truststore.jks")
.trustStorePassword("test")
.needClientAuth(true)
.httpsPort(6668));
Look at the above harmless piece of code. Running that tons of time consistently led to the infamous BindException.
I ran it multiple times and got the same BindException — Address in use.
I did all that could be done to make sure that the port is not being used. I ran `lsof -i:6668` and then `netstat -vanp tcp | grep 6668`. Whatever command I could run to check that 6668 isn’t in use.
To make matters more confusing the issue was happening only when I had the Jenkins docker container running.
docker run \
— rm \
-u root \
-p 8080:8080 \
-v $(which docker):/usr/bin/docker \
-v jenkins-data:/var/jenkins_home \
-v /var/run/docker.sock:/var/run/docker.sock \
-v “$HOME”:/home \
jenkins/jenkins:lts
That naturally added to the problem, because now I started to deep dive into how networking works with Docker.
I looked into whether the port 6668 is somehow used with this container. I changed from 6668 to 1111, and then to any other random number I could think of.
All led to the same exception. BindException — Address in use.
I started pulling my hair out and then throwing things at people sitting next to me. I was frustrated.
Finally I ran `python3 -m http.server 6668`, lo and behold it started to serve content! This convinced me that it was definitely not related to port 6668.
I now started deep-diving into Wiremock. Something was amiss.
Then it hit me.
After digging in a bit a tiny but crucial detail of Wiremock came out. 8080 is the default port it binds to.
In the above snippet to fire up Wiremock we had specified the https port. However, without a lack of the http port parameter Wiremock tried to bind to 8080 and the exception message never talked about this.
I added the port details in the config below as 6667 and viola! The tests were green.
@Rule
public WireMockRule rule = new WireMockRule(
WireMockConfiguration.wireMockConfig()
.keystorePath("src/test/resources/ssl/yesbank/keystore.jks")
.keystorePassword("test")
.trustStorePath("src/test/resources/ssl/yesbank/truststore.jks")
.trustStorePassword("test")
.needClientAuth(true)
.port(6667)
.httpsPort(6668));
There are two key takeaway from this:
- Make the apis intuitive. If I am only specifying the https port, don’t assume the http port, add a log that default port 8080 will be used, throw an exception stating that http port is required, among the numerous things that could have been done to make it more intuitive.
- Exception messages have to be super clear and tell why a certain issue is happening. A better message in this case would have been “Default port 8080 for http is already in use”.
Just these simple things would have saved a day of my bandwidth!