Rails Testing — Solving Selenium Bind(2) Errors


Backstory

A while ago I setup a VirtualBox instance to run Ubuntu 12.04 – Precise Pangolin. I outlined the steps taken in previous blog posts here and here if you’d like a refresher. VM based testing with Selenium has allowed me to focus on code vs. waiting for a browser test to complete. It’s good stuff but let’s discuss the challenge at hand.

The Situation

Needing to work late one night, I took my laptop home and attempted to run browser tests. Instead of little red and green progress messages I got this:

Errno::EADDRNOTAVAIL: Cannot assign requested address - bind(2)

No matter, I assured myself, I probably need to reboot the VM or something. So I futzed with various settings for a while and made very little progress before calling it a night. The next day I brought my laptop back to work, plugged it in, and everything worked. Was the problem solved? No. Every time I took my laptop home Selenium would fail to load displaying the same bind(2) error message.

Web Server Conflict?

The most obvious conflict to check for is to see if the IP address of the Selenium server is already in use. HiringThing’s technology stack requires that we test using port 80. Naturally there could be bind issues if Apache or some other web server is running. But I don’t run a web server on my VM. Rails isn’t running. Nothing’s running except my test script.

Web Server Conflict

Hardware Changes?

My office setup is slightly different than home because I have a docking station of sorts by way of an Apple Thunderbolt display with an ethernet port. A hardware change might affect the configuration of my VM since it senses changes on the host machine (my Macbook Pro). This seemed logical to me. The host-only adapter probably wasn’t registering with the same network details.

So I unplugged my Thunderbolt display to simulate being at home (while still at my office) and ran the tests. Selenium loaded up correctly. Tests began firing. This was not the expected outcome.

Hardware Changes

Firewall, DNS , & Madness

VirtualBox is deceptively easy to setup at it’s most basic level but when you have to start port forwarding or tunneling protocols, I’m in over my head pretty quick.

That said, there are other pieces to this puzzle that need explaining since a bind error could refer to any number of things: Firewall settings, network/subnet configuration, DNS , HOSTS files

So one by one I knocked possible factors off my list:

Disable Ubuntu’s Firewall completely
sudo ufw disable

Verify ports in use
nmap localhost

These results are telling me, yeah, things look good. Except they’re misleading because Selenium would still fail outside of the office. I checked and rechecked my configuration a dozen times in the process.

Finding the solution

My colleague Joshua Siler suggested that I verify Ruby is seeing the same network information as my command lines tools. This was ultimately the nudge in the right direction that solved my problem.

Verify hostname is rubybook
ruby -rsocket -e 'p Socket.gethostname'

Verified.

Manually recreate the Selenium connection that is failing

When Selenium’s WebDriver initializes the instance of Firefox it looks for a connection to localhost. If localhost doesn’t resolve to the local machine then a bind error is produced.

What does Ruby think our localhost address is?

AH HA!

How could Ruby think that localhost is anything beside 127.0.0.1? Certainly my HOSTS file doesn’t have some strange pointer to these other IPs.

And there it was… or rather there it wasn’t.

My HOSTS file was missing the most common reference of all:

localhost 127.0.0.1

The missing the entry for localhost was resolving according to the DNS settings used by my ISP . Thus the disparity between home and work.

After adding that single entry all my tests ran as expected at home and at work.

Conclusion

Lesson learned? Check the HOSTS file first.

For the love of Pete, check it first.

HiringThing

Author: HiringThing

HiringThing is easy to use, intuitive online recruiting software that makes it easy to post jobs online, manage applicants and hire great employees.