Glad You're Ready. Let's Get Started!

Let us know how we can contact you.

Thank you!

We'll respond shortly.

Testing Desert Plugins in Isolation

At Pivotal, some of our client projects use plugins from our home-grown social networking platform and rely on Desert to tie them all together. To test this package of plugins we created a project that contains all of our Desert plugins and wrote some rake tasks that run all of their tests. Great, right?

Mostly. We want to ensure that our plugins have the absolute minimum dependencies to function. Let’s pretend we have an UserAuth plugin and a SocialPivots plugin, where UserAuth has no dependencies, but SocialPivots depends on UserAuth. We would like to test these the to plugins in isolation. But, with Desert doing it’s job so well, our UserAuth plugin could have a dependency on the SocialPivots plugins’ models or tables and we would never know it. Everything from SocialPivots is mixed-in and loaded into memory, and all of its migrations have executed, at the time we are running UserAuth’s tests.

What we need is a way to tell Desert to load only the plugin under test, plus its dependencies listed in init.rb. Hacking Desert and Rails to allow us to specify which plugins to load turned out to be pretty easy. Check it out (full gist here):

Here, we override plugin loading:

# lib/plugin_dependency_limiter.rb
class Rails::Initializer
  def load_plugins
    # Only load the plugin under test"vendor/plugins/#{ENV['PLUGIN']}").load(self)

  def add_plugin_load_paths
    # Do nothing.  We'll handle plugin loading ourselves.

We might have many plugins in vendor/plugins but we only want to test our Desert plugins. We list them in config/plugins/plugins_to_test.yml and keep track of them here:

# also in lib/plugin_dependency_limiter.rb
class Rails::Plugin
  def self.plugins_of_interest
    # Keep track of the Desert plugins we care about
    @of_interest ||= YAML.load_file(RAILS_ROOT + "/config/plugins/plugins_to_test.yml").collect

  def self.tracked_plugins
    @tracked_plugins ||= []

  def require_plugin_with_plugin_tracking(plugin_name)
    self.class.tracked_plugins << plugin_name if self.class.plugins_of_interest.include?(plugin_name)
  alias_method_chain :require_plugin, :plugin_tracking

Once you can control which plugins are loaded you can expand this to dictate which routes and migrations should be run:


# config/routes.rb
ActionController::Routing::Routes.draw do |map|
  if ENV['PLUGIN']
    Rails::Plugin.tracked_plugins.each do |plugin|


# db/migration/001_migrate_desert_plugins.rb
class MigrateDesertPlugins < ActiveRecord::Migration
  def self.up
    Rails::Plugin.tracked_plugins.each do |plugin|
      migrate_plugin(plugin, nil)
    migrate_plugin(ENV['PLUGIN'], nil)

  def self.down
    raise ActiveRecord::IrreversibleMigration

Let’s run some tests! Though we don’t provide the rake task here, it runs db:drop db:create db:migrate db:test:prepare before running the plugin tests.

First, the UserAuth plugin that has no dependencies:

$ rake testspec:plugins PLUGIN=user_auth
(in /Users/pivotal/workspace/desert_plugins)
==  MigrateDesertPlugins: migrating ===========================================
==  CreateUserAuthStuff: migrating ====================================================
-- create_table(:user_auth_stuff)
   -> 0.0023s
==  CreateUserAuthStuff: migrated (0.0026s) ===========================================

==  MigrateDesertPlugins: migrated (0.0076s) ==================================

/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby -I"lib:test" "/Library/Ruby/Gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb"

Finished in 0.494227 seconds

36 examples, 0 failures

Now the SocialPivots Plugin, which relies on UserAuth:

$ rake testspec:plugins PLUGIN=social_pivots
(in /Users/pivotal/workspace/desert_plugins)
==  MigrateDesertPlugins: migrating ===========================================
# Look, the migrations from UserAuth!
# Look, the migrations from UserAuth!
# Look, the migrations from UserAuth!
==  CreateUserAuthStuff: migrating ====================================================
-- create_table(:user_auth_stuff)
   -> 0.0201s
==  CreateUserAuthStuff: migrated (0.0204s) ===========================================

==  CreateSocialPivotStuff: migrating ==============================================
-- create_table(:social_pivot_stuff)
   -> 0.0034s
==  CreateSocialPivotStuff: migrated (0.0036s) =====================================

==  MigrateDesertPlugins: migrated (0.0332s) ==================================

/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby -I"lib:test" "/Library/Ruby/Gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb"

Finished in 1.381141 seconds

72 examples, 0 failures

I hope this code makes testing Desert plugins easier. Thanks to Pivots Adam and Edward for pairing with me through these solutions.

Post a Comment

Your Information (Name required. Email address will not be displayed with comment.)

* Copy This Password *

* Type Or Paste Password Here *