capistrano 1.4.2 → 2.0.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 (113) hide show
  1. data/CHANGELOG +140 -4
  2. data/MIT-LICENSE +1 -1
  3. data/README +22 -14
  4. data/bin/cap +1 -8
  5. data/bin/capify +77 -0
  6. data/examples/sample.rb +10 -109
  7. data/lib/capistrano.rb +1 -0
  8. data/lib/capistrano/callback.rb +41 -0
  9. data/lib/capistrano/cli.rb +17 -317
  10. data/lib/capistrano/cli/execute.rb +82 -0
  11. data/lib/capistrano/cli/help.rb +102 -0
  12. data/lib/capistrano/cli/help.txt +53 -0
  13. data/lib/capistrano/cli/options.rb +183 -0
  14. data/lib/capistrano/cli/ui.rb +28 -0
  15. data/lib/capistrano/command.rb +62 -29
  16. data/lib/capistrano/configuration.rb +25 -226
  17. data/lib/capistrano/configuration/actions/file_transfer.rb +35 -0
  18. data/lib/capistrano/configuration/actions/inspect.rb +46 -0
  19. data/lib/capistrano/configuration/actions/invocation.rb +127 -0
  20. data/lib/capistrano/configuration/callbacks.rb +148 -0
  21. data/lib/capistrano/configuration/connections.rb +159 -0
  22. data/lib/capistrano/configuration/execution.rb +126 -0
  23. data/lib/capistrano/configuration/loading.rb +112 -0
  24. data/lib/capistrano/configuration/namespaces.rb +190 -0
  25. data/lib/capistrano/configuration/roles.rb +51 -0
  26. data/lib/capistrano/configuration/servers.rb +75 -0
  27. data/lib/capistrano/configuration/variables.rb +127 -0
  28. data/lib/capistrano/errors.rb +15 -0
  29. data/lib/capistrano/extensions.rb +27 -8
  30. data/lib/capistrano/gateway.rb +54 -29
  31. data/lib/capistrano/logger.rb +11 -11
  32. data/lib/capistrano/recipes/compat.rb +32 -0
  33. data/lib/capistrano/recipes/deploy.rb +483 -0
  34. data/lib/capistrano/recipes/deploy/dependencies.rb +44 -0
  35. data/lib/capistrano/recipes/deploy/local_dependency.rb +46 -0
  36. data/lib/capistrano/recipes/deploy/remote_dependency.rb +65 -0
  37. data/lib/capistrano/recipes/deploy/scm.rb +19 -0
  38. data/lib/capistrano/recipes/deploy/scm/base.rb +180 -0
  39. data/lib/capistrano/recipes/deploy/scm/bzr.rb +86 -0
  40. data/lib/capistrano/recipes/deploy/scm/cvs.rb +151 -0
  41. data/lib/capistrano/recipes/deploy/scm/darcs.rb +85 -0
  42. data/lib/capistrano/recipes/deploy/scm/mercurial.rb +129 -0
  43. data/lib/capistrano/recipes/deploy/scm/perforce.rb +126 -0
  44. data/lib/capistrano/recipes/deploy/scm/subversion.rb +103 -0
  45. data/lib/capistrano/recipes/deploy/strategy.rb +19 -0
  46. data/lib/capistrano/recipes/deploy/strategy/base.rb +64 -0
  47. data/lib/capistrano/recipes/deploy/strategy/checkout.rb +20 -0
  48. data/lib/capistrano/recipes/deploy/strategy/copy.rb +143 -0
  49. data/lib/capistrano/recipes/deploy/strategy/export.rb +20 -0
  50. data/lib/capistrano/recipes/deploy/strategy/remote.rb +52 -0
  51. data/lib/capistrano/recipes/deploy/strategy/remote_cache.rb +47 -0
  52. data/lib/capistrano/recipes/deploy/templates/maintenance.rhtml +53 -0
  53. data/lib/capistrano/recipes/standard.rb +26 -276
  54. data/lib/capistrano/recipes/templates/maintenance.rhtml +1 -1
  55. data/lib/capistrano/recipes/upgrade.rb +33 -0
  56. data/lib/capistrano/server_definition.rb +51 -0
  57. data/lib/capistrano/shell.rb +125 -81
  58. data/lib/capistrano/ssh.rb +80 -36
  59. data/lib/capistrano/task_definition.rb +69 -0
  60. data/lib/capistrano/upload.rb +146 -0
  61. data/lib/capistrano/version.rb +13 -17
  62. data/test/cli/execute_test.rb +132 -0
  63. data/test/cli/help_test.rb +139 -0
  64. data/test/cli/options_test.rb +226 -0
  65. data/test/cli/ui_test.rb +28 -0
  66. data/test/cli_test.rb +17 -0
  67. data/test/command_test.rb +284 -25
  68. data/test/configuration/actions/file_transfer_test.rb +40 -0
  69. data/test/configuration/actions/inspect_test.rb +62 -0
  70. data/test/configuration/actions/invocation_test.rb +195 -0
  71. data/test/configuration/callbacks_test.rb +206 -0
  72. data/test/configuration/connections_test.rb +288 -0
  73. data/test/configuration/execution_test.rb +159 -0
  74. data/test/configuration/loading_test.rb +119 -0
  75. data/test/configuration/namespace_dsl_test.rb +283 -0
  76. data/test/configuration/roles_test.rb +47 -0
  77. data/test/configuration/servers_test.rb +90 -0
  78. data/test/configuration/variables_test.rb +180 -0
  79. data/test/configuration_test.rb +60 -212
  80. data/test/deploy/scm/base_test.rb +55 -0
  81. data/test/deploy/strategy/copy_test.rb +146 -0
  82. data/test/extensions_test.rb +69 -0
  83. data/test/fixtures/cli_integration.rb +5 -0
  84. data/test/fixtures/custom.rb +2 -2
  85. data/test/gateway_test.rb +167 -0
  86. data/test/logger_test.rb +123 -0
  87. data/test/server_definition_test.rb +108 -0
  88. data/test/shell_test.rb +64 -0
  89. data/test/ssh_test.rb +67 -154
  90. data/test/task_definition_test.rb +101 -0
  91. data/test/upload_test.rb +131 -0
  92. data/test/utils.rb +31 -39
  93. data/test/version_test.rb +24 -0
  94. metadata +145 -98
  95. data/THANKS +0 -4
  96. data/lib/capistrano/actor.rb +0 -567
  97. data/lib/capistrano/generators/rails/deployment/deployment_generator.rb +0 -25
  98. data/lib/capistrano/generators/rails/deployment/templates/capistrano.rake +0 -49
  99. data/lib/capistrano/generators/rails/deployment/templates/deploy.rb +0 -122
  100. data/lib/capistrano/generators/rails/loader.rb +0 -20
  101. data/lib/capistrano/scm/base.rb +0 -61
  102. data/lib/capistrano/scm/baz.rb +0 -118
  103. data/lib/capistrano/scm/bzr.rb +0 -70
  104. data/lib/capistrano/scm/cvs.rb +0 -129
  105. data/lib/capistrano/scm/darcs.rb +0 -27
  106. data/lib/capistrano/scm/mercurial.rb +0 -83
  107. data/lib/capistrano/scm/perforce.rb +0 -139
  108. data/lib/capistrano/scm/subversion.rb +0 -128
  109. data/lib/capistrano/transfer.rb +0 -97
  110. data/lib/capistrano/utils.rb +0 -26
  111. data/test/actor_test.rb +0 -402
  112. data/test/scm/cvs_test.rb +0 -196
  113. data/test/scm/subversion_test.rb +0 -145
@@ -0,0 +1,64 @@
1
+ require "#{File.dirname(__FILE__)}/utils"
2
+ require 'capistrano/configuration'
3
+ require 'capistrano/shell'
4
+
5
+ class ShellTest < Test::Unit::TestCase
6
+ def setup
7
+ @config = Capistrano::Configuration.new
8
+ @shell = Capistrano::Shell.new(@config)
9
+ @shell.stubs(:puts)
10
+ end
11
+
12
+ def test_readline_fallback_prompt_should_write_to_stdout_and_read_from_stdin
13
+ STDOUT.expects(:print).with("prompt> ")
14
+ STDOUT.expects(:flush)
15
+ STDIN.expects(:gets).returns("hi\n")
16
+ assert_equal "hi\n", Capistrano::Shell::ReadlineFallback.readline("prompt> ")
17
+ end
18
+
19
+ def test_question_mark_as_input_should_trigger_help
20
+ @shell.expects(:read_line).returns("?")
21
+ @shell.expects(:help)
22
+ assert @shell.read_and_execute
23
+ end
24
+
25
+ def test_help_as_input_should_trigger_help
26
+ @shell.expects(:read_line).returns("help")
27
+ @shell.expects(:help)
28
+ assert @shell.read_and_execute
29
+ end
30
+
31
+ def test_quit_as_input_should_cause_read_and_execute_to_return_false
32
+ @shell.expects(:read_line).returns("quit")
33
+ assert !@shell.read_and_execute
34
+ end
35
+
36
+ def test_exit_as_input_should_cause_read_and_execute_to_return_false
37
+ @shell.expects(:read_line).returns("exit")
38
+ assert !@shell.read_and_execute
39
+ end
40
+
41
+ def test_set_should_parse_flag_and_value_and_call_set_option
42
+ @shell.expects(:read_line).returns("set -v 5")
43
+ @shell.expects(:set_option).with("v", "5")
44
+ assert @shell.read_and_execute
45
+ end
46
+
47
+ def test_text_without_with_or_on_gets_processed_verbatim
48
+ @shell.expects(:read_line).returns("hello world")
49
+ @shell.expects(:process_command).with(nil, nil, "hello world")
50
+ assert @shell.read_and_execute
51
+ end
52
+
53
+ def test_text_with_with_gets_processed_with_with # lol
54
+ @shell.expects(:read_line).returns("with app,db hello world")
55
+ @shell.expects(:process_command).with("with", "app,db", "hello world")
56
+ assert @shell.read_and_execute
57
+ end
58
+
59
+ def test_text_with_on_gets_processed_with_on
60
+ @shell.expects(:read_line).returns("on app,db hello world")
61
+ @shell.expects(:process_command).with("on", "app,db", "hello world")
62
+ assert @shell.read_and_execute
63
+ end
64
+ end
@@ -1,184 +1,97 @@
1
- $:.unshift File.dirname(__FILE__) + "/../lib"
2
-
3
- require File.dirname(__FILE__) + "/utils"
4
- require 'test/unit'
1
+ require "#{File.dirname(__FILE__)}/utils"
5
2
  require 'capistrano/ssh'
6
3
 
7
4
  class SSHTest < Test::Unit::TestCase
8
- class MockSSH
9
- AuthenticationFailed = Net::SSH::AuthenticationFailed
10
-
11
- class <<self
12
- attr_accessor :story
13
- attr_accessor :invocations
14
- end
5
+ def setup
6
+ @options = { :username => nil,
7
+ :password => nil,
8
+ :port => 22,
9
+ :auth_methods => %w(publickey hostbased) }
10
+ @server = server("capistrano")
11
+ end
15
12
 
16
- def self.start(server, opts, &block)
17
- @invocations << [server, opts, block]
18
- err = story.shift
19
- raise err if err
20
- end
13
+ def test_connect_with_bare_server_without_options_or_config_with_public_key_succeeding_should_only_loop_once
14
+ Net::SSH.expects(:start).with(@server.host, @options).returns(success = Object.new)
15
+ assert_equal success, Capistrano::SSH.connect(@server)
21
16
  end
22
17
 
23
- def setup
24
- @config = MockConfiguration.new
25
- @config[:user] = 'demo'
26
- @config[:password] = 'c0c0nutfr0st1ng'
27
- MockSSH.story = []
28
- MockSSH.invocations = []
18
+ def test_connect_with_bare_server_without_options_with_public_key_failing_should_try_password
19
+ Net::SSH.expects(:start).with(@server.host, @options).raises(Net::SSH::AuthenticationFailed)
20
+ Net::SSH.expects(:start).with(@server.host, @options.merge(:password => "f4b13n", :auth_methods => %w(password keyboard-interactive))).returns(success = Object.new)
21
+ assert_equal success, Capistrano::SSH.connect(@server, :password => "f4b13n")
29
22
  end
30
23
 
31
- def test_publickey_auth_succeeds_default_port_no_block
32
- Net.const_during(:SSH, MockSSH) do
33
- Capistrano::SSH.connect('demo.server.i', @config)
24
+ def test_connect_with_bare_server_without_options_public_key_and_password_failing_should_raise_error
25
+ Net::SSH.expects(:start).with(@server.host, @options).raises(Net::SSH::AuthenticationFailed)
26
+ Net::SSH.expects(:start).with(@server.host, @options.merge(:password => "f4b13n", :auth_methods => %w(password keyboard-interactive))).raises(Net::SSH::AuthenticationFailed)
27
+ assert_raises(Net::SSH::AuthenticationFailed) do
28
+ Capistrano::SSH.connect(@server, :password => "f4b13n")
34
29
  end
35
-
36
- assert_equal 1, MockSSH.invocations.length
37
- assert_equal 'demo.server.i', MockSSH.invocations.first[0]
38
- assert_equal 22, MockSSH.invocations.first[1][:port]
39
- assert_equal 'demo', MockSSH.invocations.first[1][:username]
40
- assert_nil MockSSH.invocations.first[1][:password]
41
- assert_equal %w(publickey hostbased),
42
- MockSSH.invocations.first[1][:auth_methods]
43
- assert_nil MockSSH.invocations.first[2]
44
30
  end
45
-
46
- def test_explicit_ssh_ports_in_server_string_no_block
47
- Net.const_during(:SSH, MockSSH) do
48
- Capistrano::SSH.connect('demo.server.i:8088', @config)
49
- end
50
31
 
51
- assert_equal 1, MockSSH.invocations.length
52
- assert_equal 'demo.server.i', MockSSH.invocations.first[0]
53
- assert_equal '8088', MockSSH.invocations.first[1][:port]
54
- assert_equal 'demo', MockSSH.invocations.first[1][:username]
32
+ def test_connect_with_bare_server_and_user_via_public_key_should_pass_user_to_net_ssh
33
+ Net::SSH.expects(:start).with(@server.host, @options.merge(:username => "jamis")).returns(success = Object.new)
34
+ assert_equal success, Capistrano::SSH.connect(@server, :user => "jamis")
55
35
  end
56
-
57
- def test_explicit_ssh_username_in_server_string_no_block
58
- Net.const_during(:SSH, MockSSH) do
59
- Capistrano::SSH.connect('bob@demo.server.i', @config)
60
- end
61
36
 
62
- assert_equal 1, MockSSH.invocations.length
63
- assert_equal 'demo.server.i', MockSSH.invocations.first[0]
64
- assert_equal 22, MockSSH.invocations.first[1][:port]
65
- assert_equal 'bob', MockSSH.invocations.first[1][:username]
37
+ def test_connect_with_bare_server_and_user_via_password_should_pass_user_to_net_ssh
38
+ Net::SSH.expects(:start).with(@server.host, @options.merge(:username => "jamis")).raises(Net::SSH::AuthenticationFailed)
39
+ Net::SSH.expects(:start).with(@server.host, @options.merge(:username => "jamis", :password => "f4b13n", :auth_methods => %w(password keyboard-interactive))).returns(success = Object.new)
40
+ assert_equal success, Capistrano::SSH.connect(@server, :user => "jamis", :password => "f4b13n")
66
41
  end
67
-
68
- def test_explicit_ssh_username_and_port_in_server_string_no_block
69
- Net.const_during(:SSH, MockSSH) do
70
- Capistrano::SSH.connect('bob@demo.server.i:8088', @config)
71
- end
72
42
 
73
- assert_equal 1, MockSSH.invocations.length
74
- assert_equal 'demo.server.i', MockSSH.invocations.first[0]
75
- assert_equal '8088', MockSSH.invocations.first[1][:port]
76
- assert_equal 'bob', MockSSH.invocations.first[1][:username]
43
+ def test_connect_with_bare_server_with_explicit_port_should_pass_port_to_net_ssh
44
+ Net::SSH.expects(:start).with(@server.host, @options.merge(:port => 1234)).returns(success = Object.new)
45
+ assert_equal success, Capistrano::SSH.connect(@server, :port => 1234)
77
46
  end
78
47
 
79
- def test_publickey_auth_succeeds_explicit_port_no_block
80
- Net.const_during(:SSH, MockSSH) do
81
- Capistrano::SSH.connect('demo.server.i', @config, 23)
82
- end
83
-
84
- assert_equal 1, MockSSH.invocations.length
85
- assert_equal 23, MockSSH.invocations.first[1][:port]
86
- assert_nil MockSSH.invocations.first[2]
48
+ def test_connect_with_server_with_user_should_pass_user_to_net_ssh
49
+ server = server("jamis@capistrano")
50
+ Net::SSH.expects(:start).with(server.host, @options.merge(:username => "jamis")).returns(success = Object.new)
51
+ assert_equal success, Capistrano::SSH.connect(server)
87
52
  end
88
53
 
89
-
90
- def test_explicit_ssh_ports_in_server_string_with_block
91
- Net.const_during(:SSH, MockSSH) do
92
- Capistrano::SSH.connect('demo.server.i:8088', @config) do |session|
93
- end
94
- end
95
- assert_equal 'demo.server.i', MockSSH.invocations.first[0]
96
- assert_equal '8088', MockSSH.invocations.first[1][:port]
97
- assert_equal 1, MockSSH.invocations.length
98
- assert_instance_of Proc, MockSSH.invocations.first[2]
99
- end
100
-
101
- def test_explicit_ssh_username_in_server_string_with_block
102
- Net.const_during(:SSH, MockSSH) do
103
- Capistrano::SSH.connect('bob@demo.server.i', @config) do |session|
104
- end
105
- end
106
- assert_equal 'demo.server.i', MockSSH.invocations.first[0]
107
- assert_equal 22, MockSSH.invocations.first[1][:port]
108
- assert_equal 1, MockSSH.invocations.length
109
- assert_equal 'bob', MockSSH.invocations.first[1][:username]
110
- assert_instance_of Proc, MockSSH.invocations.first[2]
111
- end
112
-
113
- def test_explicit_ssh_username_and_port_in_server_string_with_block
114
- Net.const_during(:SSH, MockSSH) do
115
- Capistrano::SSH.connect('bob@demo.server.i:8088', @config) do |session|
116
- end
117
- end
118
- assert_equal 'demo.server.i', MockSSH.invocations.first[0]
119
- assert_equal '8088', MockSSH.invocations.first[1][:port]
120
- assert_equal 1, MockSSH.invocations.length
121
- assert_equal 'bob', MockSSH.invocations.first[1][:username]
122
- assert_instance_of Proc, MockSSH.invocations.first[2]
54
+ def test_connect_with_server_with_port_should_pass_port_to_net_ssh
55
+ server = server("capistrano:1235")
56
+ Net::SSH.expects(:start).with(server.host, @options.merge(:port => 1235)).returns(success = Object.new)
57
+ assert_equal success, Capistrano::SSH.connect(server)
123
58
  end
124
59
 
125
- def test_parse_server
126
- assert_equal(['bob', 'demo.server.i', '8088'],
127
- Capistrano::SSH.parse_server("bob@demo.server.i:8088"))
128
- assert_equal([nil, 'demo.server.i', '8088'],
129
- Capistrano::SSH.parse_server("demo.server.i:8088"))
130
- assert_equal(['bob', 'demo.server.i', nil],
131
- Capistrano::SSH.parse_server("bob@demo.server.i"))
132
- assert_equal([nil, 'demo.server.i', nil],
133
- Capistrano::SSH.parse_server("demo.server.i"))
134
- end
135
-
136
- def test_publickey_auth_succeeds_with_block
137
- Net.const_during(:SSH, MockSSH) do
138
- Capistrano::SSH.connect('demo.server.i', @config) do |session|
139
- end
140
- end
141
-
142
- assert_equal 1, MockSSH.invocations.length
143
- assert_instance_of Proc, MockSSH.invocations.first[2]
60
+ def test_connect_with_server_with_user_and_port_should_pass_user_and_port_to_net_ssh
61
+ server = server("jamis@capistrano:1235")
62
+ Net::SSH.expects(:start).with(server.host, @options.merge(:username => "jamis", :port => 1235)).returns(success = Object.new)
63
+ assert_equal success, Capistrano::SSH.connect(server)
144
64
  end
145
65
 
146
- def test_publickey_auth_fails
147
- MockSSH.story << Net::SSH::AuthenticationFailed
148
-
149
- Net.const_during(:SSH, MockSSH) do
150
- Capistrano::SSH.connect('demo.server.i', @config)
151
- end
152
-
153
- assert_equal 2, MockSSH.invocations.length
154
-
155
- assert_nil MockSSH.invocations.first[1][:password]
156
- assert_equal %w(publickey hostbased),
157
- MockSSH.invocations.first[1][:auth_methods]
158
-
159
- assert_equal 'c0c0nutfr0st1ng', MockSSH.invocations.last[1][:password]
160
- assert_equal %w(password keyboard-interactive),
161
- MockSSH.invocations.last[1][:auth_methods]
66
+ def test_connect_with_ssh_options_should_use_ssh_options
67
+ ssh_options = { :username => "JamisMan", :port => 8125 }
68
+ Net::SSH.expects(:start).with(@server.host, @options.merge(:username => "JamisMan", :port => 8125)).returns(success = Object.new)
69
+ assert_equal success, Capistrano::SSH.connect(@server, {:ssh_options => ssh_options})
162
70
  end
163
71
 
164
- def test_password_auth_fails
165
- MockSSH.story << Net::SSH::AuthenticationFailed
166
- MockSSH.story << Net::SSH::AuthenticationFailed
167
-
168
- Net.const_during(:SSH, MockSSH) do
169
- assert_raises(Net::SSH::AuthenticationFailed) do
170
- Capistrano::SSH.connect('demo.server.i', @config)
171
- end
172
- end
72
+ def test_connect_with_options_and_ssh_options_should_see_options_override_ssh_options
73
+ ssh_options = { :username => "JamisMan", :port => 8125, :forward_agent => true }
74
+ Net::SSH.expects(:start).with(@server.host, @options.merge(:username => "jamis", :port => 1235, :forward_agent => true)).returns(success = Object.new)
75
+ assert_equal success, Capistrano::SSH.connect(@server, {:ssh_options => ssh_options, :user => "jamis", :port => 1235})
76
+ end
173
77
 
174
- assert_equal 2, MockSSH.invocations.length
78
+ def test_connect_with_ssh_options_should_see_server_options_override_ssh_options
79
+ ssh_options = { :username => "JamisMan", :port => 8125, :forward_agent => true }
80
+ server = server("jamis@capistrano:1235")
81
+ Net::SSH.expects(:start).with(server.host, @options.merge(:username => "jamis", :port => 1235, :forward_agent => true)).returns(success = Object.new)
82
+ assert_equal success, Capistrano::SSH.connect(server, {:ssh_options => ssh_options})
83
+ end
175
84
 
176
- assert_nil MockSSH.invocations.first[1][:password]
177
- assert_equal %w(publickey hostbased),
178
- MockSSH.invocations.first[1][:auth_methods]
85
+ def test_connect_should_add_xserver_accessor_to_connection
86
+ Net::SSH.expects(:start).with(@server.host, @options).returns(success = Object.new)
87
+ assert_equal success, Capistrano::SSH.connect(@server)
88
+ assert success.respond_to?(:xserver)
89
+ assert success.respond_to?(:xserver)
90
+ assert_equal success.xserver, @server
91
+ end
179
92
 
180
- assert_equal 'c0c0nutfr0st1ng', MockSSH.invocations.last[1][:password]
181
- assert_equal %w(password keyboard-interactive),
182
- MockSSH.invocations.last[1][:auth_methods]
93
+ def test_connect_should_not_retry_if_custom_auth_methods_are_given
94
+ Net::SSH.expects(:start).with(@server.host, @options.merge(:auth_methods => %w(publickey))).raises(Net::SSH::AuthenticationFailed)
95
+ assert_raises(Net::SSH::AuthenticationFailed) { Capistrano::SSH.connect(@server, :ssh_options => { :auth_methods => %w(publickey) }) }
183
96
  end
184
97
  end
@@ -0,0 +1,101 @@
1
+ require "#{File.dirname(__FILE__)}/utils"
2
+ require 'capistrano/task_definition'
3
+
4
+ class TaskDefinitionTest < Test::Unit::TestCase
5
+ def setup
6
+ @namespace = namespace
7
+ end
8
+
9
+ def test_fqn_at_top_level_should_be_task_name
10
+ task = new_task(:testing)
11
+ assert_equal "testing", task.fully_qualified_name
12
+ end
13
+
14
+ def test_fqn_in_namespace_should_include_namespace_fqn
15
+ ns = namespace("outer:inner")
16
+ task = new_task(:testing, ns)
17
+ assert_equal "outer:inner:testing", task.fully_qualified_name
18
+ end
19
+
20
+ def test_fqn_at_top_level_when_default_should_be_default
21
+ task = new_task(:default)
22
+ assert_equal "default", task.fully_qualified_name
23
+ end
24
+
25
+ def test_fqn_in_namespace_when_default_should_be_namespace_fqn
26
+ ns = namespace("outer:inner")
27
+ task = new_task(:default, ns)
28
+ ns.stubs(:default_task => task)
29
+ assert_equal "outer:inner", task.fully_qualified_name
30
+ end
31
+
32
+ def test_task_should_require_block
33
+ assert_raises(ArgumentError) do
34
+ Capistrano::TaskDefinition.new(:testing, @namespace)
35
+ end
36
+ end
37
+
38
+ def test_description_should_return_empty_string_if_not_given
39
+ assert_equal "", new_task(:testing).description
40
+ end
41
+
42
+ def test_description_should_return_desc_attribute
43
+ assert_equal "something", new_task(:testing, @namespace, :desc => "something").description
44
+ end
45
+
46
+ def test_description_should_strip_leading_and_trailing_whitespace
47
+ assert_equal "something", new_task(:testing, @namespace, :desc => " something ").description
48
+ end
49
+
50
+ def test_description_should_normalize_newlines
51
+ assert_equal "a\nb\nc", new_task(:testing, @namespace, :desc => "a\nb\r\nc").description
52
+ end
53
+
54
+ def test_description_should_detect_and_remove_indentation
55
+ desc = <<-DESC
56
+ Here is some indented text \
57
+ and I want all of this to \
58
+ run together on a single line, \
59
+ without any extraneous spaces.
60
+
61
+ additional indentation will
62
+ be preserved.
63
+ DESC
64
+
65
+ task = new_task(:testing, @namespace, :desc => desc)
66
+ assert_equal "Here is some indented text and I want all of this to run together on a single line, without any extraneous spaces.\n\n additional indentation will\n be preserved.", task.description
67
+ end
68
+
69
+ def test_description_munging_should_be_sensitive_to_code_blocks
70
+ desc = <<-DESC
71
+ Here is a line \
72
+ wrapped with spacing in it.
73
+
74
+ foo bar
75
+ baz bang
76
+ DESC
77
+
78
+ task = new_task(:testing, @namespace, :desc => desc)
79
+ assert_equal "Here is a line wrapped with spacing in it.\n\n foo bar\n baz bang", task.description
80
+ end
81
+
82
+ def test_brief_description_should_return_first_sentence_in_description
83
+ desc = "This is the task. It does all kinds of things."
84
+ task = new_task(:testing, @namespace, :desc => desc)
85
+ assert_equal "This is the task.", task.brief_description
86
+ end
87
+
88
+ def test_brief_description_should_truncate_if_length_given
89
+ desc = "This is the task that does all kinds of things. And then some."
90
+ task = new_task(:testing, @namespace, :desc => desc)
91
+ assert_equal "This is the task ...", task.brief_description(20)
92
+ end
93
+
94
+ def test_brief_description_should_not_break_at_period_in_middle_of_sentence
95
+ task = new_task(:testing, @namespace, :desc => "Take file.txt and copy it.")
96
+ assert_equal "Take file.txt and copy it.", task.brief_description
97
+
98
+ task = new_task(:testing, @namespace, :desc => "Take file.txt and copy it. Then do something else.")
99
+ assert_equal "Take file.txt and copy it.", task.brief_description
100
+ end
101
+ end
@@ -0,0 +1,131 @@
1
+ require "#{File.dirname(__FILE__)}/utils"
2
+ require 'capistrano/upload'
3
+
4
+ class UploadTest < Test::Unit::TestCase
5
+ def setup
6
+ @mode = IO::WRONLY | IO::CREAT | IO::TRUNC
7
+ end
8
+
9
+ def test_initialize_should_raise_error_if_data_is_missing
10
+ assert_raises(ArgumentError) do
11
+ Capistrano::Upload.new([], "test.txt", :foo => "bar")
12
+ end
13
+ end
14
+
15
+ def test_initialize_should_get_sftp_for_each_session
16
+ new_sftp = Proc.new do |state|
17
+ sftp = mock("sftp", :state => state, :open => nil)
18
+ sftp.expects(:connect) unless state == :open
19
+ sftp.stubs(:channel).returns({})
20
+ sftp
21
+ end
22
+
23
+ sessions = [mock("session", :xserver => server("a"), :sftp => new_sftp[:closed]),
24
+ mock("session", :xserver => server("b"), :sftp => new_sftp[:closed]),
25
+ mock("session", :xserver => server("c"), :sftp => new_sftp[:open])]
26
+ Capistrano::Upload.new(sessions, "test.txt", :data => "data")
27
+ end
28
+
29
+ def test_self_process_should_instantiate_uploader_and_start_process
30
+ Capistrano::Upload.expects(:new).with([:s1, :s2], "test.txt", :data => "data").returns(mock(:process! => nil))
31
+ Capistrano::Upload.process([:s1, :s2], "test.txt", :data => "data")
32
+ end
33
+
34
+ def test_process_when_sftp_open_fails_should_raise_error
35
+ sftp = mock_sftp
36
+ sftp.expects(:open).with("test.txt", @mode, 0660).yields(mock("status", :code => "bad status", :message => "bad status"), :file_handle)
37
+ session = mock("session", :sftp => sftp, :xserver => server("capistrano"))
38
+ upload = Capistrano::Upload.new([session], "test.txt", :data => "data", :logger => stub_everything)
39
+ assert_raises(Capistrano::UploadError) { upload.process! }
40
+ assert_equal 1, upload.failed
41
+ assert_equal 1, upload.completed
42
+ end
43
+
44
+ def test_process_when_sftp_write_fails_should_raise_error
45
+ sftp = mock_sftp
46
+ sftp.expects(:open).with("test.txt", @mode, 0660).yields(mock("status1", :code => Net::SFTP::Session::FX_OK), :file_handle)
47
+ sftp.expects(:write).with(:file_handle, "data").yields(mock("status2", :code => "bad status", :message => "bad status"))
48
+ session = mock("session", :sftp => sftp, :xserver => server("capistrano"))
49
+ upload = Capistrano::Upload.new([session], "test.txt", :data => "data", :logger => stub_everything)
50
+ assert_raises(Capistrano::UploadError) { upload.process! }
51
+ assert_equal 1, upload.failed
52
+ assert_equal 1, upload.completed
53
+ end
54
+
55
+ def test_upload_error_should_include_accessor_with_host_array
56
+ sftp = mock_sftp
57
+ sftp.expects(:open).with("test.txt", @mode, 0660).yields(mock("status1", :code => Net::SFTP::Session::FX_OK), :file_handle)
58
+ sftp.expects(:write).with(:file_handle, "data").yields(mock("status2", :code => "bad status", :message => "bad status"))
59
+ session = mock("session", :sftp => sftp, :xserver => server("capistrano"))
60
+ upload = Capistrano::Upload.new([session], "test.txt", :data => "data", :logger => stub_everything)
61
+
62
+ begin
63
+ upload.process!
64
+ flunk "expected an exception to be raised"
65
+ rescue Capistrano::UploadError => e
66
+ assert e.respond_to?(:hosts)
67
+ assert_equal %w(capistrano), e.hosts.map { |h| h.to_s }
68
+ end
69
+ end
70
+
71
+ def test_process_when_sftp_succeeds_should_raise_nothing
72
+ sftp = mock_sftp
73
+ sftp.expects(:open).with("test.txt", @mode, 0660).yields(mock("status1", :code => Net::SFTP::Session::FX_OK), :file_handle)
74
+ sftp.expects(:write).with(:file_handle, "data").yields(mock("status2", :code => Net::SFTP::Session::FX_OK))
75
+ sftp.expects(:close_handle).with(:file_handle).yields
76
+ session = mock("session", :sftp => sftp, :xserver => server("capistrano"))
77
+ upload = Capistrano::Upload.new([session], "test.txt", :data => "data", :logger => stub_everything)
78
+ assert_nothing_raised { upload.process! }
79
+ assert_equal 0, upload.failed
80
+ assert_equal 1, upload.completed
81
+ end
82
+
83
+ def test_process_should_loop_while_running
84
+ con = mock("connection")
85
+ con.expects(:process).with(true).times(10)
86
+ channel = {}
87
+ channel.expects(:connection).returns(con).times(10)
88
+ sftp = mock("sftp", :state => :open, :open => nil)
89
+ sftp.stubs(:channel).returns(channel)
90
+ session = mock("session", :sftp => sftp, :xserver => server("capistrano"))
91
+ upload = Capistrano::Upload.new([session], "test.txt", :data => "data")
92
+ upload.expects(:running?).times(11).returns(*([true]*10 + [false]))
93
+ upload.process!
94
+ end
95
+
96
+ def test_process_should_loop_but_not_process_done_channels
97
+ new_sftp = Proc.new do |done|
98
+ channel = {}
99
+ channel[:needs_done] = done
100
+
101
+ if !done
102
+ con = mock("connection")
103
+ con.expects(:process).with(true).times(10)
104
+ channel.expects(:connection).returns(con).times(10)
105
+ end
106
+
107
+ sftp = mock("sftp", :state => :open, :open => nil)
108
+ sftp.stubs(:channel).returns(channel)
109
+ sftp
110
+ end
111
+
112
+ sessions = [stub("session", :sftp => new_sftp[true], :xserver => server("capistrano")),
113
+ stub("session", :sftp => new_sftp[false], :xserver => server("cap2"))]
114
+ upload = Capistrano::Upload.new(sessions, "test.txt", :data => "data")
115
+
116
+ # make sure the sftp channels we wanted to be done, start as done
117
+ # (Upload.new marks each channel as not-done, so we have to do it here)
118
+ sessions.each { |s| s.sftp.channel[:done] = true if s.sftp.channel[:needs_done] }
119
+ upload.expects(:running?).times(11).returns(*([true]*10 + [false]))
120
+ upload.process!
121
+ end
122
+
123
+ private
124
+
125
+ def mock_sftp
126
+ sftp = mock("sftp", :state => :open)
127
+ sftp.stubs(:channel).returns(Hash.new)
128
+ yield sftp if block_given?
129
+ sftp
130
+ end
131
+ end