/ Rspec

Getting Vagrant + Guard + rspec to work together!

For one of my recent projects, I’ve decided to try new style of coding: writing code directly on my machine as I usually do, but this time run all unit tests and code itself within project dedicated VM managed by Vagrant.

Overall, it works really well and allows to manage project dependencies efficiently, without cluttering your system. Biggest challange for this type of setups is how to quickly share the code between host system and the VM. I’ve seen many different solutions to this problem - starting from rsync, through scp, git ending with the simplest one - shared folders. I believe that simple solutions, are the best solutions, so this is how it’s setup on my box.

After hours spent on setting up initial project and its dependencies (looking at you FreeTDS…), the time has come to write some specs.

When developing on my local machine, I run my specs automatically through Guard which monitors selected project files for changes and runs respective tests if something has changed.

I was really confused when I wrote the first test and nothing has happened. I’ve triple checked if paths are correct but it all looked good. Forcing tests to be run manually worked without problem.

After investigating this further, I found out that Virtualbox does not forward low-level filesystem notifications to shared folders and that’s a reason why changes are not being detected.

There are at least two possible solutions in this scenario:

Solution 1: Use Polling

This feature simply checks if there are any changes in regular periods of time by asking for modification timestamps. As you can imagine, this works for relatively small projects, but can be CPU intensive if you have lots of files.

To use this feature, start Guard as follows

guard -p

If you find that your CPU usage goes through roof, increase polling interval by specifying -l option. For example, to poll every 10 seconds:

guard -p -l 10

Solution 2: Forward host filesystem change events through TCP

This solution is much more efficient, as the guard is being notified about all the changes that occur on host filesystem rather then actively looking for them. The downside is that it requires additional configuration but in my opinion it’s worth it. This is how to set it up:

On the host system

Installation

  1. Forward TCP port to the guest machine, so the listen daemon can send the events to the guest VM. If you are using Vagrant, the example Vagrantfile entry would be as follows:

    config.vm.network :forwarded_port, guest: 4000, host: 4000
    
  2. Install listen gem

    gem install listen thor celluloid-io
    
  3. Restart your guest VM so that port forward takes effect.

Usage

Now, every time you work on this project you will have to start monitoring with those two simple steps:

  1. On the host system, run:

    listen -f 127.0.0.1:4000
    
  2. On the guest VM, run:

    bundle exec guard -o '10.0.2.2:4000' -w '/Users/marek/devel/project'
    

Remember to replace 10.2.2.2 with IP address of your host machine on the vboxnetX interface and /Users/marek/devel/project with actual path to the project on your host system.

From now on, your specs should start only when you make a change and CPU usage should be reasonable.