Back to Repositories

Validating Plugin Hook Implementation in Resque

This test suite validates the plugin hook functionality and linting mechanisms in Resque, focusing on proper hook method naming and execution order. It ensures plugins correctly implement lifecycle hooks like before_perform, after_perform, around_perform, and on_failure with appropriate namespacing.

Test Coverage Overview

The test suite provides comprehensive coverage of Resque’s plugin system, particularly focusing on hook method discovery and validation.

Key areas tested include:
  • Hook method discovery and sorting
  • Custom hook method filtering
  • Plugin naming convention enforcement
  • Namespace validation for plugin hooks

Implementation Analysis

The testing approach uses RSpec to verify two main aspects of plugin functionality: hook finding and plugin linting. It employs mock modules to simulate both valid and invalid plugin implementations, systematically testing the framework’s ability to handle different scenarios.

Technical patterns include:
  • Module-based test fixtures
  • Exception handling verification
  • Method name validation
  • Hook method ordering checks

Technical Details

Testing infrastructure includes:
  • RSpec test framework
  • Mock module definitions
  • Resque::Plugin test helpers
  • Custom assertion methods
  • Error handling verification

Best Practices Demonstrated

The test suite exemplifies several testing best practices in Ruby.

Notable practices include:
  • Isolation of test cases
  • Comprehensive error scenario coverage
  • Clear test case organization
  • Consistent naming conventions
  • Thorough validation of both positive and negative cases

resque/resque

test/plugin_test.rb

            
require 'test_helper'

describe "Resque::Plugin finding hooks" do
  module SimplePlugin
    extend self
    def before_perform1; end
    def before_perform; end
    def before_perform2; end
    def after_perform1; end
    def after_perform; end
    def after_perform2; end
    def perform; end
    def around_perform1; end
    def around_perform; end
    def around_perform2; end
    def on_failure1; end
    def on_failure; end
    def on_failure2; end
  end

  module HookBlacklistJob
    extend self
    def around_perform_blacklisted; end
    def around_perform_ok; end

    def hooks
      @hooks ||= Resque::Plugin.job_methods(self) - ['around_perform_blacklisted']
    end
  end

  it "before_perform hooks are found and sorted" do
    assert_equal ["before_perform", "before_perform1", "before_perform2"], Resque::Plugin.before_hooks(SimplePlugin).map {|m| m.to_s}
  end

  it "after_perform hooks are found and sorted" do
    assert_equal ["after_perform", "after_perform1", "after_perform2"], Resque::Plugin.after_hooks(SimplePlugin).map {|m| m.to_s}
  end

  it "around_perform hooks are found and sorted" do
    assert_equal ["around_perform", "around_perform1", "around_perform2"], Resque::Plugin.around_hooks(SimplePlugin).map {|m| m.to_s}
  end

  it "on_failure hooks are found and sorted" do
    assert_equal ["on_failure", "on_failure1", "on_failure2"], Resque::Plugin.failure_hooks(SimplePlugin).map {|m| m.to_s}
  end

  it 'uses job.hooks if available get hook methods' do
    assert_equal ['around_perform_ok'], Resque::Plugin.around_hooks(HookBlacklistJob)
  end
end

describe "Resque::Plugin linting" do
  module ::BadBefore
    def self.before_perform; end
  end
  module ::BadAfter
    def self.after_perform; end
  end
  module ::BadAround
    def self.around_perform; end
  end
  module ::BadFailure
    def self.on_failure; end
  end

  it "before_perform must be namespaced" do
    begin
      Resque::Plugin.lint(BadBefore)
      assert false, "should have failed"
    rescue Resque::Plugin::LintError => e
      assert_equal "BadBefore.before_perform is not namespaced", e.message
    end
  end

  it "after_perform must be namespaced" do
    begin
      Resque::Plugin.lint(BadAfter)
      assert false, "should have failed"
    rescue Resque::Plugin::LintError => e
      assert_equal "BadAfter.after_perform is not namespaced", e.message
    end
  end

  it "around_perform must be namespaced" do
    begin
      Resque::Plugin.lint(BadAround)
      assert false, "should have failed"
    rescue Resque::Plugin::LintError => e
      assert_equal "BadAround.around_perform is not namespaced", e.message
    end
  end

  it "on_failure must be namespaced" do
    begin
      Resque::Plugin.lint(BadFailure)
      assert false, "should have failed"
    rescue Resque::Plugin::LintError => e
      assert_equal "BadFailure.on_failure is not namespaced", e.message
    end
  end

  module GoodBefore
    def self.before_perform1; end
  end
  module GoodAfter
    def self.after_perform1; end
  end
  module GoodAround
    def self.around_perform1; end
  end
  module GoodFailure
    def self.on_failure1; end
  end

  it "before_perform1 is an ok name" do
    Resque::Plugin.lint(GoodBefore)
  end

  it "after_perform1 is an ok name" do
    Resque::Plugin.lint(GoodAfter)
  end

  it "around_perform1 is an ok name" do
    Resque::Plugin.lint(GoodAround)
  end

  it "on_failure1 is an ok name" do
    Resque::Plugin.lint(GoodFailure)
  end
end