Taking your cucumber tests back to the future with Delorean

I’m currently working on an API for Vquence’s VQdata product which allows our customers to use a REST interface to retrieve videos with certain keywords they have previously stored. While writing tests I need to be able to mock out the Time object so that my tests were deterministic relative to time.

I remembered listening to a Ruby5 podcast which mentioned a great little gem called Delorean.

Delorean easily allows you to mock time in your tests. In no time I had hooked it up to cucumber.

In features/support/delorean.rb:

require 'delorean'  
                    
# Make sure we fix the time up after each scenario
After do
  Delorean.back_to_the_present
end

and then in features/step_definitions/delorean_steps.rb

Given /^I time travel to (.+)$/ do |period|
  Delorean.time_travel_to(period)
end      

this lets me create steps like

  Scenario: Link attributes are correct for yesterday
    Given I time travel to 2010-02-01 05:00
    When I GET the videos keywords feeds page
    Then I should see "start_time=2010-02-01T00:00:00"

Some other examples you can use with Delorean are

  • 2 weeks ago
  • tomorrow
  • next tuesday 5pm

You can find more examples in the Chronic gem documentation which Delorean uses to achieve this functionality.

Careful what you call your server!

I was setting up a server recently and I was using KVM to virtualise a whole lot of hosts. Being fairly unimaginative I decided to call the machine kvm. As usual I used LVM for the disks. Now on Ubuntu this means that by default the VG will be called the same as the host name. This means the root LV will appear on the system as /dev/kvm/root.

When they KVM modules are loaded, they try and create a device called /dev/kvm. This fails pretty miserably since /dev/kvm is already a directory due to LVM shenanigans.

Not all is lost though if you’ve done a lot of setup like I had. You can rename VGs. Simply boot from your Ubuntu install CD, choose rescue mode and then jump into a shell. First you deactivate the LVs using

vgchange -a n

then you can rename the VG using

vgrename kvm kvmvg

Not sure whether I should file this problem as a bug. It is a bit of a weird situation.

Less is more for ISOs

I was tidying up some data recently and found a couple of ISO images lying around with cryptic file names. I didn’t have cdinfo installed, so I though I’d run less hoping that the binary data would have some useful text in it. Instead I was surprised to see the following:

CD-ROM is in ISO 9660 format
System id: LINUX
Volume id: Ubuntu-Server 9.10 i386
Volume set id: 
Publisher id: 
Data preparer id: 
Application id: GENISOIMAGE ISO 9660/HFS FILESYSTEM CREATOR
   (C) 1993 E.YOUNGDALE (C) 1997-2006 J.PEARSON/J.SCHILLING 
   (C) 2006-2007 CDRKIT TEAM
Copyright File id: 
Abstract File id: 
Bibliographic File id: 
Volume set size is: 1
Volume set sequence number is: 1
Logical block size is: 2048
Volume size is: 327972
El Torito VD version 1 found, boot catalog is in sector 1804
Joliet with UCS level 3 found
Rock Ridge signatures version 1 found
Eltorito validation header:
    Hid 1
    Arch 0 (x86)
    ID ''
    Key 55 AA
    Eltorito defaultboot header:
        Bootid 88 (bootable)
        Boot media 0 (No Emulation Boot)
        Load segment 0
        Sys type 0
        Nsect 4
        Bootoff 704 1796

/.disk
/README.diskdefines
<snip>File system listing</snip>

Looks like less runs isoinfo -f -R -J -i ubuntu-9.10-server-i386.iso. So I did have the tools I needed installed, I just didn’t know it yet :).

Linux Australia Elections, Last chance to vote!

If you haven’t done so, please go and vote in the Linux Australia elections. If you aren’t a member then just join first, membership is free.

I’m running for the position of Treasurer, but you don’t need to vote for me since I’m running unopposed.

I’m running on a common platform with a group of other like minded individuals. You can find the details of the platform here.

The main reason I’m running is I believe that Linux Australia can achieve so much more than it does today. Linux Australia should not simply be a conduit for linux.conf.au.

I want to help turn Linux Australia into an organisation that is relevant to all of us. It should be an organisation that not only fosters and supports the community but also represents the community.

We should offer supportive services to our members, spread the FOSS message through the community as well as actively lobby government for the things we believe in.

Most importantly it is essential that we all become involved. The community is nothing without people to move it forwards. So I would encourage you to vote for

President James Turnbull
Vice President Lindsay Holmwood
Secretary Peter Lieverdink
Treasurer John Ferlito

Ordinary Committee Members
Alice Boxhall
Elspeth Thorne

Once you have finished voting, go and join the mailing lists and get involved.

Adding multiple database support to Cucumber

The Vqmetrics application needs to connect to two different databases. The first holds the videos, authors and their relevant statistics, while the second database holds the users, monitors and trackers.

We do this by specifying two databases in config/database.yml.

development:
  database: vqmetrics_devel
  < <: *login_dev_local

vqdata_development: &VQDATA_TEST
  database: vqdata_devel
  <<: *login_dev_local

So by default the vqmetrics_devel database will be used. When we need to specify a model where we need to connect to the vqdata_devel database we use

class Video < ActiveRecord::Base
  establish_connection "vqdata_#{RAILS_ENV}"
end

and for migrations that need to connect to this database we do the following.

class InitialSetup < ActiveRecord::Migration
  def self.connection
    Video.connection
  end
end

This setup works really well. However recently I moved this application to using Cucumber for testing. Tests worked fine the first time they are run but not the second time.

I discovered that the transaction on the second database where not being rolled back as they should be. Cucumber only sets up the first database for roll back by using

ActiveRecord::Base.connection

where it should be rolling them all back by looping through

ActiveRecord::Base.connection_handler.connection_pools.values.map {|pool| pool.connection}

I’ve filed a bug at lighthouseapp.