The virtues of having a fast build have been well extolled. While there are strategies for speeding up an existing slow build, let’s look at a tool that can help us keep us from getting in that position. We will assume you are using a current version of RSpec to test Ruby code.
Before we look at the code, let’s outline the approach. First, we will add a setting to RSpec’s configuration that specifies how long of a build you want to tolerate. Next, we’ll adds hooks that make sure the build will fail if it takes longer than the time you specify.
spec/support/build_bomb.rb
class BuildBomb
include Singleton
attr_accessor :start_time, :fail_after
def self.setup(rspec_config)
raise 'Your version of RSpec does not allow settings to be added' unless rspec_config.respond_to?(:add_setting)
self.add_bomb_settings(rspec_config)
self.add_bomb_hooks(rspec_config)
end
def build_started(fail_after)
self.start_time = Time.now
self.fail_after = fail_after
end
def build_ended(end_time)
if build_was_too_slow?(start_time, end_time, fail_after)
raise BuildBomb::BuildTooSlowException.new('Build was too slow!!!')
end
end
private
def self.add_bomb_settings(config)
config.add_setting :fail_after
end
def self.add_bomb_hooks(config)
config.before(:suite) do
BuildBomb.instance.build_started(config.fail_after)
end
config.after(:suite) do
BuildBomb.instance.build_ended(Time.now)
end
end
def build_was_too_slow?(start_time, end_time, max_time)
(end_time - start_time) > max_time
end
class BuildTooSlowException < RuntimeError;
end
end
BuildBomb.setup(RSpec.configuration)
Then configure the fail_after setting in your spec helper.
spec/spec_helper.rb
...
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
RSpec.configure do |config|
...
config.fail_after = 60 # seconds to fail you build after
...
end
That’s it. With this setting, the build bomb will go off if your build takes longer than 60 seconds.
Hunters-MacBook-Pro:bomber-rails huntergillane$ rspec spec
.
Finished in 60.06 seconds
1 example, 0 failures
Randomized with seed 6736
/Users/huntergillane/workspace/gems/bomber-rails/spec/support/build_bomb.rb:21:in `build_ended': Build was too slow!!! (BuildBomb::BuildTooSlowException)
from /Users/huntergillane/workspace/gems/bomber-rails/spec/support/build_bomb.rb:37:in `block in add_bomb_hooks'
from /Users/huntergillane/.rbenv/versions/1.9.3-p327/lib/ruby/gems/1.9.1/gems/rspec-core-2.13.1/lib/rspec/core/example_group.rb:470:in `instance_eval'
from /Users/huntergillane/.rbenv/versions/1.9.3-p327/lib/ruby/gems/1.9.1/gems/rspec-core-2.13.1/lib/rspec/core/example_group.rb:470:in `instance_eval_with_rescue'
...
Mike Barinek first introduced this on a project I was working on last year and it has since proven to be a useful tool to have. Even if you have an existing slow build, you could use something like this to keep it from getting slower.