capistrano 2.4.3 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. data/CHANGELOG.rdoc +39 -0
  2. data/capistrano.gemspec +5 -5
  3. data/lib/capistrano/cli/execute.rb +1 -0
  4. data/lib/capistrano/cli/help.txt +6 -0
  5. data/lib/capistrano/cli/options.rb +26 -0
  6. data/lib/capistrano/cli/ui.rb +0 -1
  7. data/lib/capistrano/command.rb +175 -47
  8. data/lib/capistrano/configuration.rb +2 -1
  9. data/lib/capistrano/configuration/actions/invocation.rb +38 -7
  10. data/lib/capistrano/configuration/connections.rb +12 -6
  11. data/lib/capistrano/configuration/execution.rb +2 -1
  12. data/lib/capistrano/configuration/servers.rb +5 -4
  13. data/lib/capistrano/recipes/deploy.rb +45 -22
  14. data/lib/capistrano/recipes/deploy/local_dependency.rb +7 -3
  15. data/lib/capistrano/recipes/deploy/scm/cvs.rb +2 -1
  16. data/lib/capistrano/recipes/deploy/scm/none.rb +1 -1
  17. data/lib/capistrano/recipes/deploy/scm/subversion.rb +1 -1
  18. data/lib/capistrano/recipes/deploy/strategy/copy.rb +1 -1
  19. data/lib/capistrano/recipes/deploy/strategy/remote_cache.rb +10 -1
  20. data/lib/capistrano/role.rb +4 -0
  21. data/lib/capistrano/version.rb +2 -2
  22. data/test/cli/execute_test.rb +1 -1
  23. data/test/cli/options_test.rb +84 -0
  24. data/test/command_test.rb +38 -41
  25. data/test/configuration/actions/invocation_test.rb +12 -16
  26. data/test/configuration/connections_test.rb +30 -9
  27. data/test/configuration/execution_test.rb +16 -0
  28. data/test/configuration/servers_test.rb +15 -0
  29. data/test/configuration_test.rb +8 -1
  30. data/test/deploy/local_dependency_test.rb +15 -12
  31. data/test/deploy/scm/none_test.rb +35 -0
  32. data/test/deploy/strategy/copy_test.rb +13 -0
  33. metadata +3 -2
@@ -23,21 +23,27 @@ module Capistrano
23
23
 
24
24
  class GatewayConnectionFactory #:nodoc:
25
25
  def initialize(gateway, options)
26
- Thread.abort_on_exception = true
27
- server = ServerDefinition.new(gateway)
28
-
29
26
  @options = options
30
- @gateway = SSH.connection_strategy(server, options) do |host, user, connect_options|
27
+ @options[:logger].debug "Creating gateway using #{[*gateway].join(', ')}" if @options[:logger]
28
+ Thread.abort_on_exception = true
29
+ @gateways = [*gateway].collect { |g| ServerDefinition.new(g) }
30
+ tunnel = SSH.connection_strategy(@gateways[0], @options) do |host, user, connect_options|
31
31
  Net::SSH::Gateway.new(host, user, connect_options)
32
32
  end
33
+ @gateway = (@gateways[1..-1]).inject(tunnel) do |tunnel, destination|
34
+ @options[:logger].debug "Creating tunnel to #{destination}" if @options[:logger]
35
+ local_host = ServerDefinition.new("127.0.0.1", :user => destination.user, :port => tunnel.open(destination.host, (destination.port || 22)))
36
+ SSH.connection_strategy(local_host, @options) do |host, user, connect_options|
37
+ Net::SSH::Gateway.new(host, user, connect_options)
38
+ end
39
+ end
33
40
  end
34
-
41
+
35
42
  def connect_to(server)
36
43
  @options[:logger].debug "establishing connection to `#{server}' via gateway" if @options[:logger]
37
44
  local_host = ServerDefinition.new("127.0.0.1", :user => server.user, :port => @gateway.open(server.host, server.port || 22))
38
45
  session = SSH.connect(local_host, @options)
39
46
  session.xserver = server
40
- @options[:logger].trace "connected: `#{server}' (via gateway)" if @options[:logger]
41
47
  session
42
48
  end
43
49
  end
@@ -60,8 +60,9 @@ module Capistrano
60
60
  # hook will be executed.
61
61
  def on_rollback(&block)
62
62
  if transaction?
63
+ # don't note a new rollback request if one has already been set
64
+ rollback_requests << task_call_frames.last unless task_call_frames.last.rollback
63
65
  task_call_frames.last.rollback = block
64
- rollback_requests << task_call_frames.last
65
66
  end
66
67
  end
67
68
 
@@ -35,13 +35,14 @@ module Capistrano
35
35
  # servers = find_servers :hosts => "jamis@example.host.com"
36
36
  def find_servers(options={})
37
37
  hosts = server_list_from(ENV['HOSTS'] || options[:hosts])
38
- roles = role_list_from(ENV['ROLES'] || options[:roles] || self.roles.keys)
39
- only = options[:only] || {}
40
- except = options[:except] || {}
41
-
38
+
42
39
  if hosts.any?
43
40
  hosts.uniq
44
41
  else
42
+ roles = role_list_from(ENV['ROLES'] || options[:roles] || self.roles.keys)
43
+ only = options[:only] || {}
44
+ except = options[:except] || {}
45
+
45
46
  servers = roles.inject([]) { |list, role| list.concat(self.roles[role]) }
46
47
  servers = servers.select { |server| only.all? { |key,value| server.options[key] == value } }
47
48
  servers = servers.reject { |server| except.any? { |key,value| server.options[key] == value } }
@@ -42,6 +42,7 @@ _cset(:release_name) { set :deploy_timestamped, true; Time.now.utc.strftime
42
42
 
43
43
  _cset :version_dir, "releases"
44
44
  _cset :shared_dir, "shared"
45
+ _cset :shared_children, %w(system log pids)
45
46
  _cset :current_dir, "current"
46
47
 
47
48
  _cset(:releases_path) { File.join(deploy_to, version_dir) }
@@ -49,7 +50,7 @@ _cset(:shared_path) { File.join(deploy_to, shared_dir) }
49
50
  _cset(:current_path) { File.join(deploy_to, current_dir) }
50
51
  _cset(:release_path) { File.join(releases_path, release_name) }
51
52
 
52
- _cset(:releases) { capture("ls -x #{releases_path}").split.sort }
53
+ _cset(:releases) { capture("ls -xt #{releases_path}").split.reverse }
53
54
  _cset(:current_release) { File.join(releases_path, releases.last) }
54
55
  _cset(:previous_release) { File.join(releases_path, releases[-2]) }
55
56
 
@@ -160,7 +161,7 @@ namespace :deploy do
160
161
  DESC
161
162
  task :setup, :except => { :no_release => true } do
162
163
  dirs = [deploy_to, releases_path, shared_path]
163
- dirs += %w(system log pids).map { |d| File.join(shared_path, d) }
164
+ dirs += shared_children.map { |d| File.join(shared_path, d) }
164
165
  run "#{try_sudo} mkdir -p #{dirs.join(' ')} && #{try_sudo} chmod g+w #{dirs.join(' ')}"
165
166
  end
166
167
 
@@ -287,28 +288,50 @@ namespace :deploy do
287
288
  try_runner "#{current_path}/script/process/reaper"
288
289
  end
289
290
 
290
- desc <<-DESC
291
- Rolls back to the previously deployed version. The `current' symlink will \
292
- be updated to point at the previously deployed version, and then the \
293
- current release will be removed from the servers. You'll generally want \
294
- to call `rollback' instead, as it performs a `restart' as well.
295
- DESC
296
- task :rollback_code, :except => { :no_release => true } do
297
- if releases.length < 2
298
- abort "could not rollback the code because there is no prior release"
299
- else
300
- run "rm #{current_path}; ln -s #{previous_release} #{current_path} && rm -rf #{current_release}"
291
+ namespace :rollback do
292
+ desc <<-DESC
293
+ [internal] Points the current symlink at the previous revision.
294
+ This is called by the rollback sequence, and should rarely (if
295
+ ever) need to be called directly.
296
+ DESC
297
+ task :revision, :except => { :no_release => true } do
298
+ if releases.length < 2
299
+ abort "could not rollback the code because there is no prior release"
300
+ else
301
+ run "rm #{current_path}; ln -s #{previous_release} #{current_path}"
302
+ end
301
303
  end
302
- end
303
304
 
304
- desc <<-DESC
305
- Rolls back to a previous version and restarts. This is handy if you ever \
306
- discover that you've deployed a lemon; `cap rollback' and you're right \
307
- back where you were, on the previously deployed version.
308
- DESC
309
- task :rollback do
310
- rollback_code
311
- restart
305
+ desc <<-DESC
306
+ [internal] Removes the most recently deployed release.
307
+ This is called by the rollback sequence, and should rarely
308
+ (if ever) need to be called directly.
309
+ DESC
310
+ task :cleanup, :except => { :no_release => true } do
311
+ run "if [ `readlink #{current_path}` != #{current_release} ]; then rm -rf #{current_release}; fi"
312
+ end
313
+
314
+ desc <<-DESC
315
+ Rolls back to the previously deployed version. The `current' symlink will \
316
+ be updated to point at the previously deployed version, and then the \
317
+ current release will be removed from the servers. You'll generally want \
318
+ to call `rollback' instead, as it performs a `restart' as well.
319
+ DESC
320
+ task :code, :except => { :no_release => true } do
321
+ revision
322
+ cleanup
323
+ end
324
+
325
+ desc <<-DESC
326
+ Rolls back to a previous version and restarts. This is handy if you ever \
327
+ discover that you've deployed a lemon; `cap rollback' and you're right \
328
+ back where you were, on the previously deployed version.
329
+ DESC
330
+ task :default do
331
+ revision
332
+ restart
333
+ cleanup
334
+ end
312
335
  end
313
336
 
314
337
  desc <<-DESC
@@ -30,7 +30,7 @@ module Capistrano
30
30
  # file is found that matches the parameter, this returns true.
31
31
  def find_in_path(utility)
32
32
  path = (ENV['PATH'] || "").split(File::PATH_SEPARATOR)
33
- suffixes = self.class.on_windows? ? %w(.bat .exe .com .cmd) : [""]
33
+ suffixes = self.class.on_windows? ? self.class.windows_executable_extensions : [""]
34
34
 
35
35
  path.each do |dir|
36
36
  suffixes.each do |sfx|
@@ -41,9 +41,13 @@ module Capistrano
41
41
 
42
42
  false
43
43
  end
44
-
44
+
45
45
  def self.on_windows?
46
- RUBY_PLATFORM =~ /mswin/
46
+ RUBY_PLATFORM =~ /mswin|mingw/
47
+ end
48
+
49
+ def self.windows_executable_extensions
50
+ %w(.exe .bat .com .cmd)
47
51
  end
48
52
  end
49
53
  end
@@ -71,7 +71,7 @@ module Capistrano
71
71
  revision = yield(scm(cvs_root, :log, "-r#{revision}")).
72
72
  grep(/^date:/).
73
73
  map { |line| line[/^date: (.*?);/, 1] }.
74
- sort.last
74
+ sort.last + " UTC"
75
75
  return revision
76
76
  end
77
77
 
@@ -111,6 +111,7 @@ module Capistrano
111
111
 
112
112
  # attempts to guess what type of revision we're working with
113
113
  def revision_type(rev)
114
+ return :date if rev =~ /^\d{4}\/\d{2}\/\d{2} \d{2}:\d{2}:\d{2} UTC$/ # i.e 2007-05-15 08:13:25 UTC
114
115
  return :date if rev =~ /^\d{4}\/\d{2}\/\d{2} \d{2}:\d{2}:\d{2}$/ # i.e 2007-05-15 08:13:25
115
116
  return :revision if rev =~ /^\d/ # i.e. 1.2.1
116
117
  return :tag # i.e. RELEASE_1_2
@@ -27,7 +27,7 @@ module Capistrano
27
27
  # Simply does a copy from the :repository directory to the
28
28
  # :destination directory.
29
29
  def checkout(revision, destination)
30
- "cp -R #{repository} #{destination}"
30
+ !Capistrano::Deploy::LocalDependency.on_windows? ? "cp -R #{repository} #{destination}" : "xcopy #{repository} \"#{destination}\" /S/I/Y/Q/E"
31
31
  end
32
32
 
33
33
  alias_method :export, :checkout
@@ -98,7 +98,7 @@ module Capistrano
98
98
  username = variable(:scm_username)
99
99
  return "" unless username
100
100
  result = "--username #{variable(:scm_username)} "
101
- result << "--password #{variable(:scm_password)} " unless variable(:scm_prefer_prompt)
101
+ result << "--password #{variable(:scm_password)} " unless variable(:scm_auth_cache) || variable(:scm_prefer_prompt)
102
102
  result << "--no-auth-cache " unless variable(:scm_auth_cache)
103
103
  result
104
104
  end
@@ -80,7 +80,7 @@ module Capistrano
80
80
 
81
81
  if copy_exclude.any?
82
82
  logger.debug "processing exclusions..."
83
- copy_exclude.each { |pattern| FileUtils.rm_rf(File.join(destination, pattern)) }
83
+ copy_exclude.each { |pattern| FileUtils.rm_rf(Dir.glob(File.join(destination, pattern), File::FNM_DOTMATCH)) }
84
84
  end
85
85
  end
86
86
 
@@ -38,7 +38,16 @@ module Capistrano
38
38
 
39
39
  def copy_repository_cache
40
40
  logger.trace "copying the cached version to #{configuration[:release_path]}"
41
- run "cp -RPp #{repository_cache} #{configuration[:release_path]} && #{mark}"
41
+ if copy_exclude.empty?
42
+ run "cp -RPp #{repository_cache} #{configuration[:release_path]} && #{mark}"
43
+ else
44
+ exclusions = copy_exclude.map { |e| "--exclude=\"#{e}\"" }.join(' ')
45
+ run "rsync -rp #{exclusions} #{repository_cache}/* #{configuration[:release_path]} && #{mark}"
46
+ end
47
+ end
48
+
49
+ def copy_exclude
50
+ @copy_exclude ||= Array(configuration.fetch(:copy_exclude, []))
42
51
  end
43
52
  end
44
53
 
@@ -38,6 +38,10 @@ module Capistrano
38
38
  @static_servers.clear
39
39
  end
40
40
 
41
+ def include?(server)
42
+ servers.include?(server)
43
+ end
44
+
41
45
  protected
42
46
 
43
47
  # This is the combination of a block, a hash of options, and a cached value.
@@ -5,8 +5,8 @@ module Capistrano
5
5
  # Describes the current version of Capistrano.
6
6
  class Version < Net::SSH::Version
7
7
  MAJOR = 2
8
- MINOR = 4
9
- TINY = 3
8
+ MINOR = 5
9
+ TINY = 0
10
10
 
11
11
  # The current version, as a Version instance
12
12
  CURRENT = new(MAJOR, MINOR, TINY)
@@ -15,7 +15,7 @@ class CLIExecuteTest < Test::Unit::TestCase
15
15
  def setup
16
16
  @cli = MockCLI.new
17
17
  @logger = stub_everything
18
- @config = stub(:logger => @logger, :debug= => nil)
18
+ @config = stub(:logger => @logger, :debug= => nil, :dry_run= => nil)
19
19
  @config.stubs(:set)
20
20
  @config.stubs(:load)
21
21
  @config.stubs(:trigger)
@@ -30,6 +30,18 @@ class CLIOptionsTest < Test::Unit::TestCase
30
30
  assert @cli.options[:debug]
31
31
  end
32
32
 
33
+ def test_parse_options_with_n_should_set_dry_run_option
34
+ @cli.args << "-n"
35
+ @cli.parse_options!
36
+ assert @cli.options[:dry_run]
37
+ end
38
+
39
+ def test_parse_options_with_dry_run_should_set_dry_run_option
40
+ @cli.args << "--dry-run"
41
+ @cli.parse_options!
42
+ assert @cli.options[:dry_run]
43
+ end
44
+
33
45
  def test_parse_options_with_e_should_set_explain_option
34
46
  @cli.args << "-e" << "sample"
35
47
  @cli.parse_options!
@@ -87,12 +99,84 @@ class CLIOptionsTest < Test::Unit::TestCase
87
99
  assert_equal "bar", @cli.options[:pre_vars][:foo]
88
100
  end
89
101
 
102
+ def test_S_should_coerce_digits_to_integers
103
+ @cli.args << "-S" << "foo=1234"
104
+ @cli.parse_options!
105
+ assert_equal 1234, @cli.options[:pre_vars][:foo]
106
+ end
107
+
108
+ def test_S_should_treat_quoted_integers_as_string
109
+ @cli.args << "-S" << "foo=\"1234\""
110
+ @cli.parse_options!
111
+ assert_equal "1234", @cli.options[:pre_vars][:foo]
112
+ end
113
+
114
+ def test_S_should_treat_digits_with_dot_as_floating_point
115
+ @cli.args << "-S" << "foo=3.1415"
116
+ @cli.parse_options!
117
+ assert_equal 3.1415, @cli.options[:pre_vars][:foo]
118
+ end
119
+
120
+ def test_S_should_treat_true_as_boolean_true
121
+ @cli.args << "-S" << "foo=true"
122
+ @cli.parse_options!
123
+ assert_equal true, @cli.options[:pre_vars][:foo]
124
+ end
125
+
126
+ def test_S_should_treat_false_as_boolean_false
127
+ @cli.args << "-S" << "foo=false"
128
+ @cli.parse_options!
129
+ assert_equal false, @cli.options[:pre_vars][:foo]
130
+ end
131
+
132
+ def test_S_should_treat_nil_as_nil
133
+ @cli.args << "-S" << "foo=nil"
134
+ @cli.parse_options!
135
+ assert_equal nil, @cli.options[:pre_vars][:foo]
136
+ end
137
+
90
138
  def test_parse_options_with_s_should_set_vars
91
139
  @cli.args << "-s" << "foo=bar"
92
140
  @cli.parse_options!
93
141
  assert_equal "bar", @cli.options[:vars][:foo]
94
142
  end
95
143
 
144
+ def test_s_should_coerce_digits_to_integers
145
+ @cli.args << "-s" << "foo=1234"
146
+ @cli.parse_options!
147
+ assert_equal 1234, @cli.options[:vars][:foo]
148
+ end
149
+
150
+ def test_s_should_treat_quoted_integers_as_string
151
+ @cli.args << "-s" << "foo=\"1234\""
152
+ @cli.parse_options!
153
+ assert_equal "1234", @cli.options[:vars][:foo]
154
+ end
155
+
156
+ def test_s_should_treat_digits_with_dot_as_floating_point
157
+ @cli.args << "-s" << "foo=3.1415"
158
+ @cli.parse_options!
159
+ assert_equal 3.1415, @cli.options[:vars][:foo]
160
+ end
161
+
162
+ def test_s_should_treat_true_as_boolean_true
163
+ @cli.args << "-s" << "foo=true"
164
+ @cli.parse_options!
165
+ assert_equal true, @cli.options[:vars][:foo]
166
+ end
167
+
168
+ def test_s_should_treat_false_as_boolean_false
169
+ @cli.args << "-s" << "foo=false"
170
+ @cli.parse_options!
171
+ assert_equal false, @cli.options[:vars][:foo]
172
+ end
173
+
174
+ def test_s_should_treat_nil_as_nil
175
+ @cli.args << "-s" << "foo=nil"
176
+ @cli.parse_options!
177
+ assert_equal nil, @cli.options[:vars][:foo]
178
+ end
179
+
96
180
  def test_parse_options_with_T_should_set_tasks_option_and_set_verbose_off
97
181
  @cli.args << "-T"
98
182
  @cli.parse_options!
@@ -1,22 +1,21 @@
1
1
  require "utils"
2
2
  require 'capistrano/command'
3
+ require 'capistrano/configuration'
3
4
 
4
5
  class CommandTest < Test::Unit::TestCase
5
6
  def test_command_should_open_channels_on_all_sessions
6
- s1 = mock(:open_channel => nil)
7
- s2 = mock(:open_channel => nil)
8
- s3 = mock(:open_channel => nil)
9
- assert_equal "ls", Capistrano::Command.new("ls", [s1, s2, s3]).command
7
+ s1, s2, s3 = mock_session, mock_session, mock_session
8
+ assert_equal "ls", Capistrano::Command.new("ls", [s1, s2, s3]).tree.fallback.command
10
9
  end
11
10
 
12
11
  def test_command_with_newlines_should_be_properly_escaped
13
- cmd = Capistrano::Command.new("ls\necho", [mock(:open_channel => nil)])
14
- assert_equal "ls\\\necho", cmd.command
12
+ cmd = Capistrano::Command.new("ls\necho", [mock_session])
13
+ assert_equal "ls\\\necho", cmd.tree.fallback.command
15
14
  end
16
15
 
17
16
  def test_command_with_windows_newlines_should_be_properly_escaped
18
- cmd = Capistrano::Command.new("ls\r\necho", [mock(:open_channel => nil)])
19
- assert_equal "ls\\\necho", cmd.command
17
+ cmd = Capistrano::Command.new("ls\r\necho", [mock_session])
18
+ assert_equal "ls\\\necho", cmd.tree.fallback.command
20
19
  end
21
20
 
22
21
  def test_command_with_pty_should_request_pty_and_register_success_callback
@@ -76,25 +75,17 @@ class CommandTest < Test::Unit::TestCase
76
75
  end
77
76
 
78
77
  def test_open_channel_should_set_host_key_on_channel
79
- session = mock(:xserver => server("capistrano"))
80
- channel = stub_everything
81
-
82
- session.expects(:open_channel).yields(channel)
83
- channel.expects(:[]=).with(:host, "capistrano")
84
- channel.stubs(:[]).with(:host).returns("capistrano")
85
-
78
+ channel = nil
79
+ session = setup_for_extracting_channel_action { |ch| channel = ch }
86
80
  Capistrano::Command.new("ls", [session])
81
+ assert_equal "capistrano", channel[:host]
87
82
  end
88
83
 
89
84
  def test_open_channel_should_set_options_key_on_channel
90
- session = mock(:xserver => server("capistrano"))
91
- channel = stub_everything
92
-
93
- session.expects(:open_channel).yields(channel)
94
- channel.expects(:[]=).with(:options, {:data => "here we go"})
95
- channel.stubs(:[]).with(:host).returns("capistrano")
96
-
85
+ channel = nil
86
+ session = setup_for_extracting_channel_action { |ch| channel = ch }
97
87
  Capistrano::Command.new("ls", [session], :data => "here we go")
88
+ assert_equal({ :data => 'here we go' }, channel[:options])
98
89
  end
99
90
 
100
91
  def test_successful_channel_should_send_command
@@ -157,17 +148,17 @@ class CommandTest < Test::Unit::TestCase
157
148
 
158
149
  def test_on_request_should_record_exit_status
159
150
  data = mock(:read_long => 5)
160
- session = setup_for_extracting_channel_action([:on_request, "exit-status"], data) do |ch|
161
- ch.expects(:[]=).with(:status, 5)
162
- end
151
+ channel = nil
152
+ session = setup_for_extracting_channel_action([:on_request, "exit-status"], data) { |ch| channel = ch }
163
153
  Capistrano::Command.new("ls", [session])
154
+ assert_equal 5, channel[:status]
164
155
  end
165
156
 
166
157
  def test_on_close_should_set_channel_closed
167
- session = setup_for_extracting_channel_action(:on_close) do |ch|
168
- ch.expects(:[]=).with(:closed, true)
169
- end
158
+ channel = nil
159
+ session = setup_for_extracting_channel_action(:on_close) { |ch| channel = ch }
170
160
  Capistrano::Command.new("ls", [session])
161
+ assert channel[:closed]
171
162
  end
172
163
 
173
164
  def test_stop_should_close_all_open_channels
@@ -228,10 +219,8 @@ class CommandTest < Test::Unit::TestCase
228
219
 
229
220
  def test_process_should_instantiate_command_and_process!
230
221
  cmd = mock("command", :process! => nil)
231
- Capistrano::Command.expects(:new).with("ls -l", %w(a b c), {:foo => "bar"}).yields(:command).returns(cmd)
232
- parameter = nil
233
- Capistrano::Command.process("ls -l", %w(a b c), :foo => "bar") { |cmd| parameter = cmd }
234
- assert_equal :command, parameter
222
+ Capistrano::Command.expects(:new).with("ls -l", %w(a b c), {:foo => "bar"}).returns(cmd)
223
+ Capistrano::Command.process("ls -l", %w(a b c), :foo => "bar")
235
224
  end
236
225
 
237
226
  def test_process_with_host_placeholder_should_substitute_placeholder_with_each_host
@@ -254,16 +243,20 @@ class CommandTest < Test::Unit::TestCase
254
243
  stub('session', :open_channel => channel,
255
244
  :preprocess => true,
256
245
  :postprocess => true,
257
- :listeners => {})
246
+ :listeners => {},
247
+ :xserver => server("capistrano"))
248
+ end
249
+
250
+ class MockChannel < Hash
251
+ def close
252
+ end
258
253
  end
259
254
 
260
255
  def new_channel(closed, status=nil)
261
- ch = mock("channel")
262
- ch.expects(:[]).with(:closed).returns(closed)
263
- ch.expects(:[]).with(:status).returns(status) if status
256
+ ch = MockChannel.new
257
+ ch.update({ :closed => closed, :host => "capistrano", :server => server("capistrano") })
258
+ ch[:status] = status if status
264
259
  ch.expects(:close) unless closed
265
- ch.stubs(:[]).with(:host).returns("capistrano")
266
- ch.stubs(:[]).with(:server).returns(server("capistrano"))
267
260
  ch
268
261
  end
269
262
 
@@ -271,11 +264,15 @@ class CommandTest < Test::Unit::TestCase
271
264
  s = server("capistrano")
272
265
  session = mock("session", :xserver => s)
273
266
 
274
- channel = stub_everything
267
+ channel = {}
275
268
  session.expects(:open_channel).yields(channel)
276
269
 
277
- channel.stubs(:[]).with(:server).returns(s)
278
- channel.stubs(:[]).with(:host).returns(s.host)
270
+ channel.stubs(:on_data)
271
+ channel.stubs(:on_extended_data)
272
+ channel.stubs(:on_request)
273
+ channel.stubs(:on_close)
274
+ channel.stubs(:exec)
275
+ channel.stubs(:send_data)
279
276
 
280
277
  if action
281
278
  action = Array(action)