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.
Files changed (71) hide show
  1. data/History.txt +237 -0
  2. data/Manifest.txt +70 -0
  3. data/README.txt +277 -0
  4. data/Rakefile +46 -0
  5. data/bin/sunshine +5 -0
  6. data/examples/deploy.rb +61 -0
  7. data/examples/deploy_tasks.rake +112 -0
  8. data/examples/standalone_deploy.rb +31 -0
  9. data/lib/commands/add.rb +96 -0
  10. data/lib/commands/default.rb +169 -0
  11. data/lib/commands/list.rb +322 -0
  12. data/lib/commands/restart.rb +62 -0
  13. data/lib/commands/rm.rb +83 -0
  14. data/lib/commands/run.rb +151 -0
  15. data/lib/commands/start.rb +72 -0
  16. data/lib/commands/stop.rb +61 -0
  17. data/lib/sunshine/app.rb +876 -0
  18. data/lib/sunshine/binder.rb +70 -0
  19. data/lib/sunshine/crontab.rb +143 -0
  20. data/lib/sunshine/daemon.rb +380 -0
  21. data/lib/sunshine/daemons/ar_sendmail.rb +28 -0
  22. data/lib/sunshine/daemons/delayed_job.rb +30 -0
  23. data/lib/sunshine/daemons/nginx.rb +104 -0
  24. data/lib/sunshine/daemons/rainbows.rb +35 -0
  25. data/lib/sunshine/daemons/server.rb +66 -0
  26. data/lib/sunshine/daemons/unicorn.rb +26 -0
  27. data/lib/sunshine/dependencies.rb +103 -0
  28. data/lib/sunshine/dependency_lib.rb +200 -0
  29. data/lib/sunshine/exceptions.rb +54 -0
  30. data/lib/sunshine/healthcheck.rb +83 -0
  31. data/lib/sunshine/output.rb +131 -0
  32. data/lib/sunshine/package_managers/apt.rb +48 -0
  33. data/lib/sunshine/package_managers/dependency.rb +349 -0
  34. data/lib/sunshine/package_managers/gem.rb +54 -0
  35. data/lib/sunshine/package_managers/yum.rb +62 -0
  36. data/lib/sunshine/remote_shell.rb +241 -0
  37. data/lib/sunshine/repo.rb +128 -0
  38. data/lib/sunshine/repos/git_repo.rb +122 -0
  39. data/lib/sunshine/repos/rsync_repo.rb +29 -0
  40. data/lib/sunshine/repos/svn_repo.rb +78 -0
  41. data/lib/sunshine/server_app.rb +554 -0
  42. data/lib/sunshine/shell.rb +384 -0
  43. data/lib/sunshine.rb +391 -0
  44. data/templates/logrotate/logrotate.conf.erb +11 -0
  45. data/templates/nginx/nginx.conf.erb +109 -0
  46. data/templates/nginx/nginx_optimize.conf +23 -0
  47. data/templates/nginx/nginx_proxy.conf +13 -0
  48. data/templates/rainbows/rainbows.conf.erb +18 -0
  49. data/templates/tasks/sunshine.rake +114 -0
  50. data/templates/unicorn/unicorn.conf.erb +6 -0
  51. data/test/fixtures/app_configs/test_app.yml +11 -0
  52. data/test/fixtures/sunshine_test/test_upload +0 -0
  53. data/test/mocks/mock_object.rb +179 -0
  54. data/test/mocks/mock_open4.rb +117 -0
  55. data/test/test_helper.rb +188 -0
  56. data/test/unit/test_app.rb +489 -0
  57. data/test/unit/test_binder.rb +20 -0
  58. data/test/unit/test_crontab.rb +128 -0
  59. data/test/unit/test_git_repo.rb +26 -0
  60. data/test/unit/test_healthcheck.rb +70 -0
  61. data/test/unit/test_nginx.rb +107 -0
  62. data/test/unit/test_rainbows.rb +26 -0
  63. data/test/unit/test_remote_shell.rb +102 -0
  64. data/test/unit/test_repo.rb +42 -0
  65. data/test/unit/test_server.rb +324 -0
  66. data/test/unit/test_server_app.rb +425 -0
  67. data/test/unit/test_shell.rb +97 -0
  68. data/test/unit/test_sunshine.rb +157 -0
  69. data/test/unit/test_svn_repo.rb +55 -0
  70. data/test/unit/test_unicorn.rb +22 -0
  71. 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