aboutsummaryrefslogblamecommitdiffstats
path: root/switchtower/test/actor_test.rb
blob: ed657ee26e5b3d8e3af67c77248ec10db7e3525b (plain) (tree)
1
2
3
4
5
6
7
8
9






                                             
                                      
 

                                

       

                          
       
     
 


                                


       
                      


















                         
 










                                                      





























                                                                     

                                                 

























































































































                                                                                                                                                                                                    
                                                               








                                        
                                  








                                       
                                   





























                                            
$:.unshift File.dirname(__FILE__) + "/../lib"

require 'stringio'
require 'test/unit'
require 'switchtower/actor'
require 'switchtower/logger'

class ActorTest < Test::Unit::TestCase

  class TestingConnectionFactory
    def initialize(config)
    end

    def connect_to(server)
      server
    end
  end

  class GatewayConnectionFactory
    def connect_to(server)
      server
    end
  end

  class TestingCommand
    def self.invoked!
      @invoked = true
    end

    def self.invoked?
      @invoked
    end

    def self.reset!
      @invoked = nil
    end

    def initialize(*args)
    end

    def process!
      self.class.invoked!
    end
  end

  class TestActor < SwitchTower::Actor
    attr_reader :factory

    self.connection_factory = TestingConnectionFactory
    self.command_factory = TestingCommand

    def establish_gateway
      GatewayConnectionFactory.new
    end
  end

  class MockConfiguration
    Role = Struct.new(:host, :options)

    attr_accessor :gateway, :pretend

    def delegated_method
      "result of method"
    end

    ROLES = { :db  => [ Role.new("01.example.com", :primary => true),
                        Role.new("02.example.com", {}),
                        Role.new("all.example.com", {})],
              :web => [ Role.new("03.example.com", {}),
                        Role.new("04.example.com", {}),
                        Role.new("all.example.com", {})],
              :app => [ Role.new("05.example.com", {}),
                        Role.new("06.example.com", {}),
                        Role.new("07.example.com", {}),
                        Role.new("all.example.com", {})] }

    def roles
      ROLES
    end

    def logger
      @logger ||= SwitchTower::Logger.new(:output => StringIO.new)
    end
  end

  def setup
    TestingCommand.reset!
    @actor = TestActor.new(MockConfiguration.new)
  end

  def test_define_task_creates_method
    @actor.define_task :hello do
      "result"
    end
    assert @actor.respond_to?(:hello)
    assert_equal "result", @actor.hello
  end

  def test_define_task_with_successful_transaction
    class << @actor
      attr_reader :rolled_back
      attr_reader :history
    end

    @actor.define_task :hello do
      (@history ||= []) << :hello
      on_rollback { @rolled_back = true }
      "hello"
    end

    @actor.define_task :goodbye do
      (@history ||= []) << :goodbye
      transaction do
        hello
      end
      "goodbye"
    end

    assert_nothing_raised { @actor.goodbye }
    assert !@actor.rolled_back
    assert_equal [:goodbye, :hello], @actor.history
  end

  def test_define_task_with_failed_transaction
    class << @actor
      attr_reader :rolled_back
      attr_reader :history
    end

    @actor.define_task :hello do
      (@history ||= []) << :hello
      on_rollback { @rolled_back = true }
      "hello"
    end

    @actor.define_task :goodbye do
      (@history ||= []) << :goodbye
      transaction do
        hello
        raise "ouch"
      end
      "goodbye"
    end

    assert_raise(RuntimeError) do
      @actor.goodbye
    end

    assert @actor.rolled_back
    assert_equal [:goodbye, :hello], @actor.history
  end

  def test_delegates_to_configuration
    @actor.define_task :hello do
      delegated_method
    end
    assert_equal "result of method", @actor.hello
  end

  def test_task_servers_with_duplicates
    @actor.define_task :foo do
      run "do this"
    end

    assert_equal %w(01.example.com 02.example.com 03.example.com 04.example.com 05.example.com 06.example.com 07.example.com all.example.com), @actor.tasks[:foo].servers(@actor.configuration).sort
  end

  def test_run_in_task_without_explicit_roles_selects_all_roles
    @actor.define_task :foo do
      run "do this"
    end

    @actor.foo
    assert_equal %w(01.example.com 02.example.com 03.example.com 04.example.com 05.example.com 06.example.com 07.example.com all.example.com), @actor.sessions.keys.sort
  end

  def test_run_in_task_with_single_role_selects_that_role
    @actor.define_task :foo, :roles => :db do
      run "do this"
    end

    @actor.foo
    assert_equal %w(01.example.com 02.example.com all.example.com), @actor.sessions.keys.sort
  end

  def test_run_in_task_with_multiple_roles_selects_those_roles
    @actor.define_task :foo, :roles => [:db, :web] do
      run "do this"
    end

    @actor.foo
    assert_equal %w(01.example.com 02.example.com 03.example.com 04.example.com all.example.com), @actor.sessions.keys.sort
  end

  def test_run_in_task_with_only_restricts_selected_roles
    @actor.define_task :foo, :roles => :db, :only => { :primary => true } do
      run "do this"
    end

    @actor.foo
    assert_equal %w(01.example.com), @actor.sessions.keys.sort
  end

  def test_establish_connection_uses_gateway_if_specified
    @actor.configuration.gateway = "10.example.com"
    @actor.define_task :foo, :roles => :db do
      run "do this"
    end

    @actor.foo
    assert_instance_of GatewayConnectionFactory, @actor.factory
  end

  def test_run_when_not_pretend
    @actor.define_task :foo do
      run "do this"
    end

    @actor.configuration.pretend = false
    @actor.foo
    assert TestingCommand.invoked?
  end

  def test_run_when_pretend
    @actor.define_task :foo do
      run "do this"
    end

    @actor.configuration.pretend = true
    @actor.foo
    assert !TestingCommand.invoked?
  end

  def test_task_before_hook
    history = []
    @actor.define_task :foo do
      history << "foo"
    end

    @actor.define_task :before_foo do
      history << "before_foo"
    end

    @actor.foo
    assert_equal %w(before_foo foo), history
  end

  def test_task_after_hook
    history = []
    @actor.define_task :foo do
      history << "foo"
    end

    @actor.define_task :after_foo do
      history << "after_foo"
    end

    @actor.foo
    assert_equal %w(foo after_foo), history
  end
end