Time Warp
 
Photo by The Rocketeer

Update: This has been turned into a gem for plug-and-play reuse.

In my freelance time I find myself working with an internationalized site used in over 50 countries. Of course, users of the site wanted to deal with things in a localized time zone. Adding time zone awareness brings a special angle to testing and it saddled me with some errors I had not seen before.

To start, I made use of some excellent time warp code for the unit tests I had written up. It worked beautifully. That is, it worked beautifully until I ran rake or, more specifically, rake test:functionals.

My functional tests were dying hard with these new, handy additions to test_helper.rb. From the execution of the first test, I was seeing “stack trace too deep” errors.

./test/functional/../test_helper.rb:13:in `real_now': stack level too deep (SystemStackError)
        from ./test/functional/../test_helper.rb:13:in `real_now'
        from ./test/functional/cms/../../test_helper.rb:13:in `now'
        from /usr/local/lib/ruby/1.8/logger.rb:327:in `add'
        from /usr/local/lib/ruby/1.8/logger.rb:348:in `debug'
        from /Users/bjhess/Sites/iridesco/afs/trunk/config/../vendor/rails/actionpack/lib/action_controller/helpers.rb:114:in `default_helper_module!'
        from /Users/bjhess/Sites/iridesco/afs/trunk/config/../vendor/rails/actionpack/lib/action_controller/helpers.rb:124:in `send'
        from /Users/bjhess/Sites/iridesco/afs/trunk/config/../vendor/rails/actionpack/lib/action_controller/helpers.rb:124:in `inherited'
        from /Users/bjhess/Sites/iridesco/afs/trunk/config/../app/controllers/cms/email_controller.rb:1
         ... 9 levels...
        from /Users/bjhess/Sites/iridesco/afs/trunk/config/../vendor/rails/activerecord/lib/../../activesupport/lib/active_support/dependencies.rb:489:in `load'
        from /usr/local/lib/ruby/gems/1.8/gems/rake-0.7.3/lib/rake/rake_test_loader.rb:5
        from /usr/local/lib/ruby/gems/1.8/gems/rake-0.7.3/lib/rake/rake_test_loader.rb:5:in `each'
        from /usr/local/lib/ruby/gems/1.8/gems/rake-0.7.3/lib/rake/rake_test_loader.rb:5
rake aborted!
Command failed with status (1): [/usr/local/bin/ruby -Ilib:test "/usr/local...]

The specific bit of code appeared to be the real_now call on the line real_now - testing_offset:

alias_method :real_now, :now
def now
  real_now - testing_offset
end
alias_method :new, :now

My workaround was to move all of the time warp code into its own time_helper.rb file.

ENV["RAILS_ENV"] = "test"
require File.expand_path(File.dirname(__FILE__) + "/../config/environment")

class Time #:nodoc:
  class <<self
    attr_accessor :testing_offset
    alias_method :real_now, :now
    def now
      real_now - testing_offset
    end
    alias_method :new, :now
  end
end
Time.testing_offset = 0

class Test::Unit::TestCase

  def pretend_now_is(time)
    begin
      Time.testing_offset = Time.now - time
      yield
    ensure
      Time.testing_offset = 0
    end
  end
end

Then I simply included the time_helper file along with test_helper in any test that required time warping:

require File.dirname(__FILE__) + '/../test_helper'
require File.dirname(__FILE__) + '/../time_helper'

class EventTest < Test::Unit::TestCase
  . . .
end

This worked beautifully. Unfortunately I’m at a loss as to why the initial setup had problems and I really wish I did know why. I don’t like being in the dark on problems.

Aug 12, 2007 · Subscribe · Archive · Projects · Twitter · GitHub · Flickr