sunshine 1.0.0.pre
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.
- data/History.txt +237 -0
- data/Manifest.txt +70 -0
- data/README.txt +277 -0
- data/Rakefile +46 -0
- data/bin/sunshine +5 -0
- data/examples/deploy.rb +61 -0
- data/examples/deploy_tasks.rake +112 -0
- data/examples/standalone_deploy.rb +31 -0
- data/lib/commands/add.rb +96 -0
- data/lib/commands/default.rb +169 -0
- data/lib/commands/list.rb +322 -0
- data/lib/commands/restart.rb +62 -0
- data/lib/commands/rm.rb +83 -0
- data/lib/commands/run.rb +151 -0
- data/lib/commands/start.rb +72 -0
- data/lib/commands/stop.rb +61 -0
- data/lib/sunshine/app.rb +876 -0
- data/lib/sunshine/binder.rb +70 -0
- data/lib/sunshine/crontab.rb +143 -0
- data/lib/sunshine/daemon.rb +380 -0
- data/lib/sunshine/daemons/ar_sendmail.rb +28 -0
- data/lib/sunshine/daemons/delayed_job.rb +30 -0
- data/lib/sunshine/daemons/nginx.rb +104 -0
- data/lib/sunshine/daemons/rainbows.rb +35 -0
- data/lib/sunshine/daemons/server.rb +66 -0
- data/lib/sunshine/daemons/unicorn.rb +26 -0
- data/lib/sunshine/dependencies.rb +103 -0
- data/lib/sunshine/dependency_lib.rb +200 -0
- data/lib/sunshine/exceptions.rb +54 -0
- data/lib/sunshine/healthcheck.rb +83 -0
- data/lib/sunshine/output.rb +131 -0
- data/lib/sunshine/package_managers/apt.rb +48 -0
- data/lib/sunshine/package_managers/dependency.rb +349 -0
- data/lib/sunshine/package_managers/gem.rb +54 -0
- data/lib/sunshine/package_managers/yum.rb +62 -0
- data/lib/sunshine/remote_shell.rb +241 -0
- data/lib/sunshine/repo.rb +128 -0
- data/lib/sunshine/repos/git_repo.rb +122 -0
- data/lib/sunshine/repos/rsync_repo.rb +29 -0
- data/lib/sunshine/repos/svn_repo.rb +78 -0
- data/lib/sunshine/server_app.rb +554 -0
- data/lib/sunshine/shell.rb +384 -0
- data/lib/sunshine.rb +391 -0
- data/templates/logrotate/logrotate.conf.erb +11 -0
- data/templates/nginx/nginx.conf.erb +109 -0
- data/templates/nginx/nginx_optimize.conf +23 -0
- data/templates/nginx/nginx_proxy.conf +13 -0
- data/templates/rainbows/rainbows.conf.erb +18 -0
- data/templates/tasks/sunshine.rake +114 -0
- data/templates/unicorn/unicorn.conf.erb +6 -0
- data/test/fixtures/app_configs/test_app.yml +11 -0
- data/test/fixtures/sunshine_test/test_upload +0 -0
- data/test/mocks/mock_object.rb +179 -0
- data/test/mocks/mock_open4.rb +117 -0
- data/test/test_helper.rb +188 -0
- data/test/unit/test_app.rb +489 -0
- data/test/unit/test_binder.rb +20 -0
- data/test/unit/test_crontab.rb +128 -0
- data/test/unit/test_git_repo.rb +26 -0
- data/test/unit/test_healthcheck.rb +70 -0
- data/test/unit/test_nginx.rb +107 -0
- data/test/unit/test_rainbows.rb +26 -0
- data/test/unit/test_remote_shell.rb +102 -0
- data/test/unit/test_repo.rb +42 -0
- data/test/unit/test_server.rb +324 -0
- data/test/unit/test_server_app.rb +425 -0
- data/test/unit/test_shell.rb +97 -0
- data/test/unit/test_sunshine.rb +157 -0
- data/test/unit/test_svn_repo.rb +55 -0
- data/test/unit/test_unicorn.rb +22 -0
- metadata +217 -0
@@ -0,0 +1,425 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class TestServerApp < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
mock_svn_response
|
7
|
+
|
8
|
+
@app = mock_app
|
9
|
+
@app.repo.extend MockObject
|
10
|
+
|
11
|
+
@sa = Sunshine::ServerApp.new @app, mock_remote_shell
|
12
|
+
@sa.extend MockObject
|
13
|
+
|
14
|
+
use_remote_shell @sa.shell
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
def test_init
|
19
|
+
default_info = {:ports => {}}
|
20
|
+
assert_equal default_info, @sa.info
|
21
|
+
|
22
|
+
assert_equal @app, @sa.app
|
23
|
+
assert_equal Hash.new, @sa.scripts
|
24
|
+
assert_equal [:all], @sa.roles
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
def test_init_roles
|
29
|
+
sa = Sunshine::ServerApp.new @app, "host", :roles => "role1 role2"
|
30
|
+
assert_equal [:role1, :role2], sa.roles
|
31
|
+
|
32
|
+
sa = Sunshine::ServerApp.new @app, "host", :roles => %w{role3 role4}
|
33
|
+
assert_equal [:role3, :role4], sa.roles
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
def test_add_shell_paths
|
38
|
+
@sa.add_shell_paths "test/path1", "test/path2"
|
39
|
+
assert_equal "test/path1:test/path2:$PATH", @sa.shell_env['PATH']
|
40
|
+
|
41
|
+
@sa.add_shell_paths "test/path3", "test/path4"
|
42
|
+
assert_equal "test/path3:test/path4:test/path1:test/path2:$PATH",
|
43
|
+
@sa.shell_env['PATH']
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
def test_app_attr
|
48
|
+
sa_root_path = "local/server_app/path"
|
49
|
+
sa_deploy_name = "local_deploy_name"
|
50
|
+
|
51
|
+
@sa = Sunshine::ServerApp.new "test", "host",
|
52
|
+
:root_path => sa_root_path, :deploy_name => sa_deploy_name
|
53
|
+
|
54
|
+
assert_equal sa_root_path, @sa.root_path
|
55
|
+
assert_equal sa_deploy_name, @sa.deploy_name
|
56
|
+
assert_equal "test", @sa.name
|
57
|
+
|
58
|
+
@sa.app = @app
|
59
|
+
|
60
|
+
assert_not_equal sa_root_path, @sa.root_path
|
61
|
+
assert_not_equal sa_deploy_name, @sa.deploy_name
|
62
|
+
assert_not_equal "test", @sa.name
|
63
|
+
|
64
|
+
assert_equal @app.root_path, @sa.root_path
|
65
|
+
assert_equal @app.deploy_name, @sa.deploy_name
|
66
|
+
assert_equal @app.name, @sa.name
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
def test_build_control_scripts
|
71
|
+
@sa.scripts[:start] << "start"
|
72
|
+
@sa.scripts[:stop] << "stop"
|
73
|
+
@sa.scripts[:custom] << "custom"
|
74
|
+
|
75
|
+
@sa.build_control_scripts
|
76
|
+
|
77
|
+
[:start, :stop, :custom].each do |script|
|
78
|
+
content = @sa.make_bash_script script, @sa.scripts[script]
|
79
|
+
assert @sa.method_called?(:write_script, :args => [script, content])
|
80
|
+
end
|
81
|
+
|
82
|
+
content = @sa.make_env_bash_script
|
83
|
+
assert @sa.method_called?(:write_script, :args => ["env", content])
|
84
|
+
|
85
|
+
content = @sa.make_bash_script :restart,
|
86
|
+
["#{@sa.app.root_path}/stop", "#{@sa.app.root_path}/start"]
|
87
|
+
assert @sa.method_called?(:write_script, :args => [:restart, content])
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
def test_build_deploy_info_file
|
92
|
+
args = ["#{@app.checkout_path}/info", @sa.get_deploy_info.to_yaml]
|
93
|
+
|
94
|
+
@sa.build_deploy_info_file
|
95
|
+
|
96
|
+
assert @sa.shell.method_called?(:make_file, :args => args)
|
97
|
+
|
98
|
+
args = ["#{@app.current_path}/info", "#{@app.root_path}/info"]
|
99
|
+
|
100
|
+
assert @sa.shell.method_called?(:symlink, :args => args)
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
def test_checkout_repo
|
105
|
+
@sa.checkout_repo @app.repo
|
106
|
+
repo = @sa.app.repo
|
107
|
+
args = [@app.checkout_path, @sa.shell]
|
108
|
+
|
109
|
+
assert repo.method_called?(:checkout_to, :args => args)
|
110
|
+
|
111
|
+
info = @app.repo.checkout_to @app.checkout_path, @sa.shell
|
112
|
+
assert_equal info, @sa.info[:scm]
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
def test_deploy_details
|
117
|
+
deploy_details = {:item => "thing"}
|
118
|
+
other_details = {:key => "value"}
|
119
|
+
|
120
|
+
@sa.shell.mock :call, :args => ["cat #{@sa.current_path}/info"],
|
121
|
+
:return => other_details.to_yaml
|
122
|
+
|
123
|
+
@sa.instance_variable_set "@deploy_details", deploy_details
|
124
|
+
|
125
|
+
assert_equal deploy_details, @sa.deploy_details
|
126
|
+
assert_equal other_details, @sa.deploy_details(true)
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
def test_not_deployed?
|
131
|
+
@sa.mock :deploy_details, :args => [true],
|
132
|
+
:return => nil
|
133
|
+
|
134
|
+
assert_equal false, @sa.deployed?
|
135
|
+
end
|
136
|
+
|
137
|
+
|
138
|
+
def test_server_checked_deployed?
|
139
|
+
@sa.mock :deploy_details, :args => [true],
|
140
|
+
:return => {:deploy_name => @sa.deploy_name}
|
141
|
+
|
142
|
+
assert_equal true, @sa.deployed?
|
143
|
+
end
|
144
|
+
|
145
|
+
|
146
|
+
def test_cached_details_deployed?
|
147
|
+
@sa.instance_variable_set "@deploy_details", :deploy_name => @sa.deploy_name
|
148
|
+
|
149
|
+
assert_equal true, @sa.deployed?
|
150
|
+
end
|
151
|
+
|
152
|
+
|
153
|
+
def test_get_deploy_info
|
154
|
+
test_info = {
|
155
|
+
:deployed_at => Time.now.to_s,
|
156
|
+
:deployed_as => @sa.shell.call("whoami"),
|
157
|
+
:deployed_by => Sunshine.shell.user,
|
158
|
+
:deploy_name => File.basename(@app.checkout_path),
|
159
|
+
:roles => @sa.roles,
|
160
|
+
:path => @app.root_path
|
161
|
+
}.merge @sa.info
|
162
|
+
|
163
|
+
deploy_info = @sa.get_deploy_info
|
164
|
+
|
165
|
+
deploy_info.each do |key, val|
|
166
|
+
next if key == :deployed_at
|
167
|
+
assert_equal test_info[key], val
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
|
172
|
+
def test_install_deps
|
173
|
+
nginx_dep = Sunshine.dependencies.get 'nginx', :prefer => @sa.pkg_manager
|
174
|
+
|
175
|
+
@sa.install_deps "ruby", nginx_dep
|
176
|
+
|
177
|
+
assert_dep_install 'ruby'
|
178
|
+
assert_dep_install 'nginx'
|
179
|
+
end
|
180
|
+
|
181
|
+
|
182
|
+
def test_install_deps_bad_type
|
183
|
+
nginx_dep = Sunshine.dependencies.get 'nginx'
|
184
|
+
|
185
|
+
@sa.install_deps nginx_dep, :type => Sunshine::Gem
|
186
|
+
raise "Didn't raise missing dependency when it should have."
|
187
|
+
|
188
|
+
rescue Sunshine::DependencyLib::MissingDependency => e
|
189
|
+
assert_equal "No dependency 'nginx' [Sunshine::Gem]", e.message
|
190
|
+
end
|
191
|
+
|
192
|
+
|
193
|
+
def test_make_app_directories
|
194
|
+
@sa.make_app_directories
|
195
|
+
|
196
|
+
assert_server_call "mkdir -p #{@sa.directories.join(" ")}"
|
197
|
+
end
|
198
|
+
|
199
|
+
|
200
|
+
def test_make_bash_script
|
201
|
+
app_script = @sa.make_bash_script "blah", [1,2,3,4]
|
202
|
+
|
203
|
+
assert_bash_script "blah", [1,2,3,4], app_script
|
204
|
+
end
|
205
|
+
|
206
|
+
|
207
|
+
def test_make_env_bash_script
|
208
|
+
@sa.shell.env = {"BLAH" => "blarg", "HOME" => "/home/blah"}
|
209
|
+
|
210
|
+
test_script = "#!/bin/bash\nenv BLAH=blarg HOME=/home/blah \"$@\""
|
211
|
+
|
212
|
+
assert_equal test_script, @sa.make_env_bash_script
|
213
|
+
end
|
214
|
+
|
215
|
+
|
216
|
+
def test_rake
|
217
|
+
@sa.rake "db:migrate"
|
218
|
+
|
219
|
+
assert_dep_install 'rake'
|
220
|
+
assert_server_call "cd #{@app.checkout_path} && rake db:migrate"
|
221
|
+
end
|
222
|
+
|
223
|
+
|
224
|
+
def test_register_as_deployed
|
225
|
+
Sunshine::AddCommand.extend MockObject unless
|
226
|
+
MockObject === Sunshine::AddCommand
|
227
|
+
|
228
|
+
@sa.register_as_deployed
|
229
|
+
|
230
|
+
args = [@app.root_path, {'servers' => [@sa.shell]}]
|
231
|
+
assert Sunshine::AddCommand.method_called?(:exec, :args => args)
|
232
|
+
end
|
233
|
+
|
234
|
+
|
235
|
+
def test_remove_old_deploys
|
236
|
+
Sunshine.setup 'max_deploy_versions' => 3
|
237
|
+
|
238
|
+
deploys = %w{ploy1 ploy2 ploy3 ploy4 ploy5}
|
239
|
+
|
240
|
+
@sa.shell.mock :call,
|
241
|
+
:args => ["ls -1 #{@app.deploys_path}"],
|
242
|
+
:return => "#{deploys.join("\n")}\n"
|
243
|
+
|
244
|
+
removed = deploys[0..1].map{|d| "#{@app.deploys_path}/#{d}"}
|
245
|
+
|
246
|
+
@sa.remove_old_deploys
|
247
|
+
|
248
|
+
assert_server_call "rm -rf #{removed.join(" ")}"
|
249
|
+
end
|
250
|
+
|
251
|
+
|
252
|
+
def test_remove_old_deploys_unnecessary
|
253
|
+
Sunshine.setup 'max_deploy_versions' => 5
|
254
|
+
|
255
|
+
deploys = %w{ploy1 ploy2 ploy3 ploy4 ploy5}
|
256
|
+
|
257
|
+
@sa.mock :call,
|
258
|
+
:args => ["ls -1 #{@app.deploys_path}"],
|
259
|
+
:return => "#{deploys.join("\n")}\n"
|
260
|
+
|
261
|
+
removed = deploys[0..1].map{|d| "#{@app.deploys_path}/#{d}"}
|
262
|
+
|
263
|
+
@sa.remove_old_deploys
|
264
|
+
|
265
|
+
assert_not_called "rm -rf #{removed.join(" ")}"
|
266
|
+
end
|
267
|
+
|
268
|
+
|
269
|
+
def test_revert!
|
270
|
+
deploys = %w{ploy1 ploy2 ploy3 ploy4 ploy5}
|
271
|
+
|
272
|
+
@sa.shell.mock :call,
|
273
|
+
:args => ["ls -rc1 #{@app.deploys_path}"],
|
274
|
+
:return => "#{deploys.join("\n")}\n"
|
275
|
+
|
276
|
+
@sa.revert!
|
277
|
+
|
278
|
+
assert_server_call "rm -rf #{@app.checkout_path}"
|
279
|
+
assert_server_call "ls -rc1 #{@app.deploys_path}"
|
280
|
+
|
281
|
+
last_deploy = "#{@app.deploys_path}/ploy5"
|
282
|
+
assert_server_call "ln -sfT #{last_deploy} #{@app.current_path}"
|
283
|
+
|
284
|
+
assert @sa.method_called?(:start, :args =>[:force => true])
|
285
|
+
end
|
286
|
+
|
287
|
+
|
288
|
+
def test_no_previous_revert!
|
289
|
+
@sa.shell.mock :call,
|
290
|
+
:args => ["ls -rc1 #{@app.deploys_path}"],
|
291
|
+
:return => "\n"
|
292
|
+
|
293
|
+
@sa.revert!
|
294
|
+
|
295
|
+
assert_server_call "rm -rf #{@app.checkout_path}"
|
296
|
+
assert_server_call "ls -rc1 #{@app.deploys_path}"
|
297
|
+
end
|
298
|
+
|
299
|
+
|
300
|
+
def test_run_bundler
|
301
|
+
@sa.run_bundler
|
302
|
+
|
303
|
+
assert_dep_install 'bundler'
|
304
|
+
assert_server_call "cd #{@app.checkout_path} && gem bundle"
|
305
|
+
end
|
306
|
+
|
307
|
+
|
308
|
+
def test_run_geminstaller
|
309
|
+
@sa.run_geminstaller
|
310
|
+
|
311
|
+
assert_dep_install 'geminstaller'
|
312
|
+
assert_server_call "cd #{@app.checkout_path} && geminstaller -e"
|
313
|
+
end
|
314
|
+
|
315
|
+
|
316
|
+
def test_sass
|
317
|
+
sass_files = %w{file1 file2 file3}
|
318
|
+
|
319
|
+
@sa.sass(*sass_files)
|
320
|
+
|
321
|
+
assert_dep_install 'haml'
|
322
|
+
|
323
|
+
sass_files.each do |file|
|
324
|
+
sass_file = "public/stylesheets/sass/#{file}.sass"
|
325
|
+
css_file = "public/stylesheets/#{file}.css"
|
326
|
+
|
327
|
+
assert_server_call \
|
328
|
+
"cd #{@app.checkout_path} && sass #{sass_file} #{css_file}"
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
|
333
|
+
def test_shell_env
|
334
|
+
assert_equal @sa.shell.env, @sa.shell_env
|
335
|
+
end
|
336
|
+
|
337
|
+
|
338
|
+
def test_symlink_current_dir
|
339
|
+
@sa.symlink_current_dir
|
340
|
+
|
341
|
+
assert_server_call "ln -sfT #{@app.checkout_path} #{@app.current_path}"
|
342
|
+
end
|
343
|
+
|
344
|
+
|
345
|
+
def test_upload_tasks
|
346
|
+
files = %w{task1 task2}
|
347
|
+
|
348
|
+
@sa.upload_tasks(*files)
|
349
|
+
|
350
|
+
assert_server_call "mkdir -p #{@app.checkout_path}/lib/tasks"
|
351
|
+
|
352
|
+
files.each do |f|
|
353
|
+
args = ["#{Sunshine::ROOT}/templates/tasks/#{f}.rake",
|
354
|
+
"#{@app.checkout_path}/lib/tasks/#{f}.rake"]
|
355
|
+
|
356
|
+
assert @sa.shell.method_called?(:upload, :args => args)
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
|
361
|
+
def test_upload_tasks_with_remote_path
|
362
|
+
files = %w{task1 task2}
|
363
|
+
path = "/path/to/remote/tasks"
|
364
|
+
|
365
|
+
@sa.upload_tasks files[0], files[1], :remote_path => path
|
366
|
+
|
367
|
+
assert_server_call "mkdir -p #{path}"
|
368
|
+
|
369
|
+
files.each do |f|
|
370
|
+
args = ["#{Sunshine::ROOT}/templates/tasks/#{f}.rake",
|
371
|
+
"#{path}/#{f}.rake"]
|
372
|
+
|
373
|
+
assert @sa.shell.method_called?(:upload, :args => args)
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
|
378
|
+
def test_upload_tasks_with_local_path
|
379
|
+
files = %w{task1 task2}
|
380
|
+
path = "/path/to/local/tasks"
|
381
|
+
args = files.dup << {:local_path => path}
|
382
|
+
|
383
|
+
@sa.upload_tasks(*args)
|
384
|
+
|
385
|
+
assert_server_call "mkdir -p #{@sa.checkout_path}/lib/tasks"
|
386
|
+
|
387
|
+
files.each do |f|
|
388
|
+
args = ["#{path}/#{f}.rake",
|
389
|
+
"#{@sa.checkout_path}/lib/tasks/#{f}.rake"]
|
390
|
+
|
391
|
+
assert @sa.shell.method_called?(:upload, :args => args)
|
392
|
+
end
|
393
|
+
end
|
394
|
+
|
395
|
+
|
396
|
+
def test_upload_tasks_all
|
397
|
+
files = Dir.glob("templates/tasks/*").map{|f| File.basename(f, ".rake")}
|
398
|
+
|
399
|
+
@sa.upload_tasks
|
400
|
+
|
401
|
+
assert_server_call "mkdir -p #{@app.checkout_path}/lib/tasks"
|
402
|
+
|
403
|
+
files.each do |f|
|
404
|
+
args = ["#{Sunshine::ROOT}/templates/tasks/#{f}.rake",
|
405
|
+
"#{@app.checkout_path}/lib/tasks/#{f}.rake"]
|
406
|
+
|
407
|
+
assert @sa.shell.method_called?(:upload, :args => args)
|
408
|
+
end
|
409
|
+
end
|
410
|
+
|
411
|
+
|
412
|
+
def test_write_script
|
413
|
+
@sa.write_script "script_name", "script contents"
|
414
|
+
|
415
|
+
args = ["#{@app.checkout_path}/script_name",
|
416
|
+
"script contents", {:flags => "--chmod=ugo=rwx"}]
|
417
|
+
|
418
|
+
assert @sa.shell.method_called?(:make_file, :args => args)
|
419
|
+
|
420
|
+
args = ["#{@app.current_path}/script_name",
|
421
|
+
"#{@app.root_path}/script_name"]
|
422
|
+
|
423
|
+
assert @sa.shell.method_called?(:symlink, :args => args)
|
424
|
+
end
|
425
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'test/test_helper'
|
2
|
+
|
3
|
+
class TestShell < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@output = StringIO.new
|
7
|
+
@output.extend MockObject
|
8
|
+
|
9
|
+
@shell = Sunshine::Shell.new @output
|
10
|
+
@shell.extend MockOpen4
|
11
|
+
|
12
|
+
@shell.input.extend MockObject
|
13
|
+
@shell.input.mock :ask, :return => "someinput"
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
def test_initialize
|
18
|
+
assert_equal @output, @shell.output
|
19
|
+
assert_equal HighLine, @shell.input.class
|
20
|
+
assert_equal `whoami`.chomp, @shell.user
|
21
|
+
assert_equal `hostname`.chomp, @shell.host
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
def test_ask
|
26
|
+
@shell.ask "input something!"
|
27
|
+
assert 1, @shell.input.method_call_count(:ask)
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
def test_close
|
32
|
+
@shell.close
|
33
|
+
assert 1, @shell.output.method_call_count(:close)
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
def test_write
|
38
|
+
@shell.write "blah"
|
39
|
+
assert @output.method_called?(:write, :args => "blah")
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
def test_prompt_for_password
|
44
|
+
@shell.prompt_for_password
|
45
|
+
|
46
|
+
args = "#{@shell.user}@#{@shell.host} Password:"
|
47
|
+
assert @shell.input.method_called?(:ask, :args => args)
|
48
|
+
assert_equal "someinput", @shell.password
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
def test_execute
|
53
|
+
@shell.set_mock_response 0, "say hi" => [:out, "hi\n"]
|
54
|
+
|
55
|
+
response = @shell.execute("say hi") do |stream, data|
|
56
|
+
assert_equal :out, stream
|
57
|
+
assert_equal "hi\n", data
|
58
|
+
end
|
59
|
+
assert_equal "hi", response
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
def test_execute_errorstatus
|
64
|
+
@shell.set_mock_response 1, "error me" => [:err, "ERROR'D!"]
|
65
|
+
|
66
|
+
begin
|
67
|
+
@shell.execute("error me") do |stream, data|
|
68
|
+
assert_equal :err, stream
|
69
|
+
assert_equal "ERROR'D!", data
|
70
|
+
end
|
71
|
+
raise "Didn't call CmdError when it should have"
|
72
|
+
rescue Sunshine::CmdError => e
|
73
|
+
msg = "Execution failed with status 1: error me"
|
74
|
+
assert_equal msg, e.message
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
def test_execute_stderronly
|
80
|
+
@shell.set_mock_response 0, "stderr" => [:err, "fake error"]
|
81
|
+
|
82
|
+
response = @shell.execute("stderr") do |stream, data|
|
83
|
+
assert_equal :err, stream
|
84
|
+
assert_equal "fake error", data
|
85
|
+
end
|
86
|
+
assert_equal "", response
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
def test_execute_password_prompt
|
91
|
+
@shell.set_mock_response 0, "do that thing" => [:err, "Password:"]
|
92
|
+
@shell.input.mock :ask, :return => "new_password"
|
93
|
+
|
94
|
+
@shell.execute("do that thing")
|
95
|
+
assert_equal "new_password", @shell.password
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
require 'test/test_helper'
|
2
|
+
|
3
|
+
class TestSunshine < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
end
|
7
|
+
|
8
|
+
|
9
|
+
def test_default_config
|
10
|
+
config = Sunshine::DEFAULT_CONFIG
|
11
|
+
Sunshine.setup config
|
12
|
+
|
13
|
+
assert Sunshine::Shell === Sunshine.shell
|
14
|
+
|
15
|
+
assert_equal config['deploy_env'].to_s, Sunshine.deploy_env
|
16
|
+
|
17
|
+
assert_equal !config['auto'], Sunshine.interactive?
|
18
|
+
|
19
|
+
assert Sunshine::Output === Sunshine.logger
|
20
|
+
assert_equal Logger::INFO, Sunshine.logger.level
|
21
|
+
|
22
|
+
assert_equal config['max_deploy_versions'], Sunshine.max_deploy_versions
|
23
|
+
|
24
|
+
assert_equal config['trace'], Sunshine.trace?
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
def test_find_command
|
29
|
+
assert !Sunshine.find_command('st')
|
30
|
+
assert_equal 'start', Sunshine.find_command('sta')
|
31
|
+
assert_equal 'stop', Sunshine.find_command('sto')
|
32
|
+
assert_equal 'add', Sunshine.find_command('a')
|
33
|
+
|
34
|
+
Sunshine::COMMANDS.each do |cmd|
|
35
|
+
assert_equal cmd, Sunshine.find_command(cmd)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
def test_exec_run_command
|
41
|
+
mock_sunshine_exit
|
42
|
+
mock_sunshine_command Sunshine::RunCommand
|
43
|
+
|
44
|
+
Sunshine.run %w{run somefile.rb -l debug -e prod --no-trace}
|
45
|
+
|
46
|
+
assert_command Sunshine::RunCommand, [['somefile.rb'], Sunshine.setup]
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
def test_exec_control_commands
|
51
|
+
mock_sunshine_exit
|
52
|
+
|
53
|
+
%w{add list restart rm start stop}.each do |name|
|
54
|
+
cmd = Sunshine.const_get("#{name.capitalize}Command")
|
55
|
+
|
56
|
+
mock_sunshine_command cmd
|
57
|
+
|
58
|
+
Sunshine.run %w{thing1 thing2 -r remoteserver.com}.unshift(name)
|
59
|
+
|
60
|
+
servers = [Sunshine::RemoteShell.new("remoteserver.com")]
|
61
|
+
|
62
|
+
args = [%w{thing1 thing2}, Sunshine.setup]
|
63
|
+
assert_command cmd, args
|
64
|
+
|
65
|
+
assert_equal servers, Sunshine.setup['servers']
|
66
|
+
|
67
|
+
|
68
|
+
Sunshine.run %w{thing1 thing2 -v}.unshift(name)
|
69
|
+
servers = [Sunshine.shell]
|
70
|
+
|
71
|
+
assert_command cmd, args
|
72
|
+
|
73
|
+
assert_equal servers, Sunshine.setup['servers']
|
74
|
+
assert Sunshine.setup['verbose']
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
def test_exec_local_cmd
|
80
|
+
mock_sunshine_exit
|
81
|
+
mock_sunshine_command Sunshine::RmCommand
|
82
|
+
|
83
|
+
Sunshine.run %w{rm app1 app2}
|
84
|
+
|
85
|
+
dsd = [Sunshine.shell]
|
86
|
+
|
87
|
+
args = [['app1', 'app2'], Sunshine.setup]
|
88
|
+
assert_command Sunshine::RmCommand, args
|
89
|
+
|
90
|
+
assert_equal dsd, Sunshine.setup['servers']
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
def test_exit
|
95
|
+
assert_sunshine_exit_status [true], 0
|
96
|
+
assert_sunshine_exit_status [false], 1
|
97
|
+
assert_sunshine_exit_status [0, "success!"], 0, "success!"
|
98
|
+
assert_sunshine_exit_status [2, "failed!"], 2, "failed!"
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
def assert_sunshine_exit_status args, expected_status, msg=""
|
103
|
+
args.map!{|a| a.inspect.gsub("\"", "\\\"")}
|
104
|
+
args = args.join(",")
|
105
|
+
cmd = "ruby -Ilib -e \"require 'sunshine'; Sunshine.exit(#{args})\""
|
106
|
+
|
107
|
+
pid, inn, out, err = Open4.popen4(*cmd)
|
108
|
+
|
109
|
+
status = Process.waitpid2(pid).last
|
110
|
+
|
111
|
+
out_data = out.read
|
112
|
+
err_data = err.read
|
113
|
+
|
114
|
+
out.close
|
115
|
+
err.close
|
116
|
+
inn.close
|
117
|
+
|
118
|
+
assert_equal expected_status, status.exitstatus
|
119
|
+
if expected_status == 0
|
120
|
+
assert_equal msg, out_data.strip
|
121
|
+
else
|
122
|
+
assert_equal msg, err_data.strip
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
|
127
|
+
def assert_command cmd, args
|
128
|
+
assert cmd.call_log.include?([:exec, args])
|
129
|
+
end
|
130
|
+
|
131
|
+
|
132
|
+
def mock_sunshine_command cmd
|
133
|
+
cmd.instance_eval do
|
134
|
+
undef exec
|
135
|
+
undef call_log if defined?(call_log)
|
136
|
+
|
137
|
+
def call_log
|
138
|
+
@call_log ||= []
|
139
|
+
end
|
140
|
+
|
141
|
+
def exec *args
|
142
|
+
call_log << [:exec, args]
|
143
|
+
true
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def mock_sunshine_exit
|
149
|
+
Sunshine.instance_eval do
|
150
|
+
undef exit
|
151
|
+
|
152
|
+
def exit *args
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|