Skip to content
Browse files

When executing multiline commands, escape newlines with a backslash

git-svn-id: http://svn.rubyonrails.org/rails/trunk/switchtower@1975 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
  • Loading branch information...
1 parent 936c35f commit 71e6cc2cb89d789873c4d453708a0ef0b0834a23 @jamis jamis committed Aug 6, 2005
Showing with 96 additions and 37 deletions.
  1. +3 −0 CHANGELOG
  2. +23 −15 lib/switchtower/actor.rb
  3. +1 −1 lib/switchtower/command.rb
  4. +26 −21 test/actor_test.rb
  5. +43 −0 test/command_test.rb
View
3 CHANGELOG
@@ -0,0 +1,3 @@
+*SVN*
+
+* When executing multiline commands, use a backslash to escape the newline
View
38 lib/switchtower/actor.rb
@@ -12,6 +12,27 @@ module SwitchTower
# new actor via Configuration#actor.
class Actor
+ # An adaptor for making the Net::SSH interface look and act like that of the
+ # Gateway class.
+ class DefaultConnectionFactory #:nodoc:
+ def initialize(config)
+ @config= config
+ end
+
+ def connect_to(server)
+ Net::SSH.start(server, :username => @config.user,
+ :password => @config.password)
+ end
+ end
+
+ class <<self
+ attr_accessor :connection_factory
+ attr_accessor :command_factory
+ end
+
+ self.connection_factory = DefaultConnectionFactory
+ self.command_factory = Command
+
# The configuration instance associated with this actor.
attr_reader :configuration
@@ -37,19 +58,6 @@ class Actor
# A struct for representing a single instance of an invoked task.
TaskCallFrame = Struct.new(:name, :rollback)
- # An adaptor for making the Net::SSH interface look and act like that of the
- # Gateway class.
- class DefaultConnectionFactory #:nodoc:
- def initialize(config)
- @config= config
- end
-
- def connect_to(server)
- Net::SSH.start(server, :username => @config.user,
- :password => @config.password)
- end
- end
-
# Represents the definition of a single task.
class Task #:nodoc:
attr_reader :name, :options
@@ -88,7 +96,7 @@ def initialize(config) #:nodoc:
@tasks = {}
@task_call_frames = []
@sessions = {}
- @factory = DefaultConnectionFactory.new(configuration)
+ @factory = self.class.connection_factory.new(configuration)
end
# Define a new task for this actor. The block will be invoked when this
@@ -134,7 +142,7 @@ def run(cmd, options={}, &block)
establish_connections(servers)
# execute the command on each server in parallel
- command = Command.new(servers, cmd, block, options, self)
+ command = self.class.command_factory.new(servers, cmd, block, options, self)
command.process! # raises an exception if command fails on any server
end
end
View
2 lib/switchtower/command.rb
@@ -7,7 +7,7 @@ class Command
def initialize(servers, command, callback, options, actor) #:nodoc:
@servers = servers
- @command = command
+ @command = command.gsub(/\r?\n/, "\\\n")
@callback = callback
@options = options
@actor = actor
View
47 test/actor_test.rb
@@ -5,28 +5,24 @@
require 'switchtower/actor'
require 'switchtower/logger'
-module SwitchTower
- class Actor
- attr_reader :factory
+class ActorTest < Test::Unit::TestCase
- class DefaultConnectionFactory
- def connect_to(server)
- server
- end
+ class TestingConnectionFactory
+ def initialize(config)
end
- class GatewayConnectionFactory
- def connect_to(server)
- server
- end
+ def connect_to(server)
+ server
end
+ end
- def establish_gateway
- GatewayConnectionFactory.new
+ class GatewayConnectionFactory
+ def connect_to(server)
+ server
end
end
- class Command
+ class TestingCommand
def self.invoked!
@invoked = true
end
@@ -46,9 +42,18 @@ def process!
self.class.invoked!
end
end
-end
-class ActorTest < Test::Unit::TestCase
+ 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)
@@ -79,8 +84,8 @@ def logger
end
def setup
- SwitchTower::Command.reset!
- @actor = SwitchTower::Actor.new(MockConfiguration.new)
+ TestingCommand.reset!
+ @actor = TestActor.new(MockConfiguration.new)
end
def test_define_task_creates_method
@@ -203,7 +208,7 @@ def test_establish_connection_uses_gateway_if_specified
end
@actor.foo
- assert_instance_of SwitchTower::Actor::GatewayConnectionFactory, @actor.factory
+ assert_instance_of GatewayConnectionFactory, @actor.factory
end
def test_run_when_not_pretend
@@ -213,7 +218,7 @@ def test_run_when_not_pretend
@actor.configuration.pretend = false
@actor.foo
- assert SwitchTower::Command.invoked?
+ assert TestingCommand.invoked?
end
def test_run_when_pretend
@@ -223,7 +228,7 @@ def test_run_when_pretend
@actor.configuration.pretend = true
@actor.foo
- assert !SwitchTower::Command.invoked?
+ assert !TestingCommand.invoked?
end
def test_task_before_hook
View
43 test/command_test.rb
@@ -0,0 +1,43 @@
+$:.unshift File.dirname(__FILE__) + "/../lib"
+
+require 'stringio'
+require 'test/unit'
+require 'switchtower/command'
+
+class CommandTest < Test::Unit::TestCase
+ class MockSession
+ def open_channel
+ { :closed => true, :status => 0 }
+ end
+ end
+
+ class MockActor
+ attr_reader :sessions
+
+ def initialize
+ @sessions = Hash.new { |h,k| h[k] = MockSession.new }
+ end
+ end
+
+ def setup
+ @actor = MockActor.new
+ end
+
+ def test_command_executes_on_all_servers
+ command = SwitchTower::Command.new(%w(server1 server2 server3),
+ "hello", nil, {}, @actor)
+ assert_equal %w(server1 server2 server3), @actor.sessions.keys.sort
+ end
+
+ def test_command_with_newlines
+ command = SwitchTower::Command.new(%w(server1), "hello\nworld", nil, {},
+ @actor)
+ assert_equal "hello\\\nworld", command.command
+ end
+
+ def test_command_with_windows_newlines
+ command = SwitchTower::Command.new(%w(server1), "hello\r\nworld", nil, {},
+ @actor)
+ assert_equal "hello\\\nworld", command.command
+ end
+end

0 comments on commit 71e6cc2

Please sign in to comment.
Something went wrong with that request. Please try again.