sunshine 1.0.0.pre

Sign up to get free protection for your applications and to get access to all the features.
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,489 @@
1
+ require 'test/test_helper'
2
+
3
+ class TestApp < Test::Unit::TestCase
4
+
5
+ def setup
6
+ mock_remote_shell_popen4
7
+ @svn_url = "svn://subversion/path/to/app_name/trunk"
8
+
9
+ @config = {:name => "app_name",
10
+ :repo => {:type => "svn", :url => @svn_url},
11
+ :remote_shells => ["user@some_server.com"],
12
+ :root_path => "/usr/local/my_user/app_name"}
13
+
14
+ @app = Sunshine::App.new @config
15
+ @app.each do |server_app|
16
+ server_app.extend MockObject
17
+ server_app.shell.extend MockObject
18
+ end
19
+
20
+ @tmpdir = File.join Dir.tmpdir, "test_sunshine_#{$$}"
21
+
22
+ mock_svn_response @app.repo.url
23
+ end
24
+
25
+ def teardown
26
+ FileUtils.rm_f @tmpdir
27
+ end
28
+
29
+
30
+ def test_initialize_without_name
31
+ app = Sunshine::App.new :repo => {:type => "svn", :url => @svn_url},
32
+ :remote_shells => ["user@some_server.com"]
33
+
34
+ assert_equal "app_name", app.name
35
+ end
36
+
37
+
38
+ def test_initialize_with_config_file
39
+ app = Sunshine::App.new TEST_APP_CONFIG_FILE
40
+ config = YAML.load_file(TEST_APP_CONFIG_FILE)[:default]
41
+ assert_attributes_equal config, app
42
+ end
43
+
44
+
45
+ def test_initialize_with_file_object
46
+ file = File.open TEST_APP_CONFIG_FILE
47
+ app = Sunshine::App.new file
48
+ config = YAML.load_file(TEST_APP_CONFIG_FILE)[:default]
49
+ assert_attributes_equal config, app
50
+ end
51
+
52
+
53
+ def test_initialize_with_options
54
+ assert_attributes_equal @config, @app
55
+ end
56
+
57
+
58
+ def test_initialize_with_options_and_config_file
59
+ app = Sunshine::App.new TEST_APP_CONFIG_FILE, @config
60
+ assert_attributes_equal @config, app
61
+ end
62
+
63
+
64
+ def test_app_deploy
65
+ yield_called = false
66
+
67
+ @app.deploy do |app|
68
+ assert app.connected?
69
+
70
+ yield_called = true
71
+ end
72
+
73
+ assert !@app.connected?
74
+
75
+ setup_cmd =
76
+ "test -d #{@app.checkout_path} && rm -rf #{@app.checkout_path}"+
77
+ " || echo false"
78
+
79
+ mkdir_cmd = "mkdir -p #{@app.checkout_path}"
80
+
81
+ checkout_cmd = "svn checkout " +
82
+ "#{@app.repo.scm_flags} #{@app.repo.url} #{@app.checkout_path}"
83
+
84
+ run_results = [
85
+ "mkdir -p #{@app.server_apps.first.directories.join(" ")}",
86
+ setup_cmd,
87
+ mkdir_cmd,
88
+ checkout_cmd,
89
+ "ln -sfT #{@app.checkout_path} #{@app.current_path}"
90
+ ]
91
+
92
+
93
+ @app.each do |server_app|
94
+ use_remote_shell server_app.shell
95
+
96
+ run_results.each_index do |i|
97
+ assert_ssh_call run_results[i]
98
+ end
99
+ end
100
+
101
+ assert yield_called
102
+ end
103
+
104
+
105
+ TEST_CONFIG = <<-STR
106
+ :conf1:
107
+ :common: "conf1"
108
+ :from_conf1: true
109
+ :not_conf4: "conf1"
110
+
111
+ :conf2:
112
+ :inherits: :conf1
113
+ :common: "conf2"
114
+ :from_conf2: true
115
+ :not_conf4: "conf2"
116
+
117
+ :conf3:
118
+ :common: "conf3"
119
+ :from_conf3: true
120
+ :not_conf4: "conf3"
121
+
122
+ :conf4:
123
+ :inherits:
124
+ - :conf2
125
+ - :conf3
126
+ :common: "conf4"
127
+ :from_conf4: true
128
+ STR
129
+
130
+ def test_merge_config_inheritance
131
+ all_configs = YAML.load TEST_CONFIG
132
+ main_conf = all_configs[:conf2]
133
+
134
+ main_conf = @app.send(:merge_config_inheritance, main_conf, all_configs)
135
+
136
+ assert main_conf[:from_conf1]
137
+ assert_equal "conf2", main_conf[:common]
138
+ end
139
+
140
+
141
+ def test_multiple_merge_config_inheritance
142
+ all_configs = YAML.load TEST_CONFIG
143
+ main_conf = all_configs[:conf4]
144
+
145
+ main_conf = @app.send(:merge_config_inheritance, main_conf, all_configs)
146
+
147
+ assert main_conf[:from_conf1]
148
+ assert main_conf[:from_conf2]
149
+ assert main_conf[:from_conf3]
150
+ assert_equal "conf4", main_conf[:common]
151
+ assert_equal "conf3", main_conf[:not_conf4]
152
+ end
153
+
154
+
155
+ class MockError < Exception; end
156
+
157
+ def test_app_deploy_error_handling
158
+ [ MockError,
159
+ Sunshine::CriticalDeployError,
160
+ Sunshine::FatalDeployError ].each do |error|
161
+
162
+ begin
163
+ app = Sunshine::App.deploy @config do |app|
164
+ raise error, "#{error} was not caught"
165
+ end
166
+
167
+ rescue MockError => e
168
+ assert_equal MockError, e.class
169
+ end
170
+ end
171
+ end
172
+
173
+
174
+ def test_revert
175
+ set_mock_response_for @app, 0,
176
+ "ls -rc1 #{@app.deploys_path}" => [:out, "last_deploy_dir"]
177
+
178
+ @app.revert!
179
+
180
+ @app.each do |sa|
181
+ use_remote_shell sa.shell
182
+
183
+ assert_ssh_call "rm -rf #{@app.checkout_path}"
184
+
185
+ assert_ssh_call "ls -rc1 #{@app.deploys_path}"
186
+
187
+ last_deploy = "#{@app.deploys_path}/last_deploy_dir"
188
+ assert_ssh_call "ln -sfT #{last_deploy} #{@app.current_path}"
189
+ end
190
+ end
191
+
192
+
193
+ def test_build_control_scripts
194
+ @app.add_to_script :start, "start script"
195
+ @app.add_to_script :stop, "stop script"
196
+ @app.add_to_script :custom, "custom script"
197
+
198
+ @app.build_control_scripts
199
+
200
+ each_remote_shell do |ds|
201
+
202
+ %w{start stop restart custom env}.each do |script|
203
+ assert_rsync(/#{script}/, "#{ds.host}:#{@app.checkout_path}/#{script}")
204
+ end
205
+ end
206
+ end
207
+
208
+
209
+ def test_build_deploy_info_file
210
+ @app.build_deploy_info_file
211
+
212
+ each_remote_shell do |ds|
213
+ assert_rsync(/info/, "#{ds.host}:#{@app.checkout_path}/info")
214
+ end
215
+ end
216
+
217
+
218
+ def test_build_erb
219
+ erb_file = File.join(@tmpdir, "tmp.erb")
220
+
221
+ FileUtils.mkdir_p @tmpdir
222
+ File.open(erb_file, "w+") do |f|
223
+ f.write "<%= name %>"
224
+ end
225
+
226
+ name = "test name"
227
+
228
+ local_name = @app.build_erb(erb_file, binding)
229
+ app_name = @app.build_erb(erb_file)
230
+
231
+ assert_equal name, local_name
232
+ assert_equal @app.name, app_name
233
+ end
234
+
235
+
236
+ def test_checkout_codebase
237
+ @app.checkout_codebase
238
+
239
+ each_remote_shell do |ds|
240
+ path = @app.checkout_path
241
+ setup_cmd = "test -d #{path} && rm -rf #{path} || echo false"
242
+
243
+ url = @app.repo.url
244
+ flags = @app.repo.scm_flags
245
+ checkout_cmd =
246
+ "svn checkout #{flags} #{url} #{path}"
247
+
248
+ assert_ssh_call setup_cmd
249
+ assert_ssh_call checkout_cmd
250
+ end
251
+ end
252
+
253
+
254
+ def test_deployed?
255
+ deployed = @app.deployed?
256
+
257
+ state = true
258
+ @app.server_apps.each do |sa|
259
+ assert sa.method_called? :deployed?
260
+ state = false unless sa.deployed?
261
+ end
262
+
263
+ assert_equal state, deployed
264
+ end
265
+
266
+
267
+ def test_install_deps
268
+ nginx_dep = Sunshine.dependencies.get 'nginx'
269
+ ruby_dep = Sunshine.dependencies.get 'ruby'
270
+
271
+ yum_sudo = Sunshine::Yum.sudo
272
+
273
+ check_nginx = "test \"$(yum list installed #{nginx_dep.pkg} | "+
274
+ "grep -c #{nginx_dep.pkg})\" -ge 1"
275
+ check_ruby = "test \"$(yum list installed #{ruby_dep.pkg} | "+
276
+ "grep -c #{ruby_dep.pkg})\" -ge 1"
277
+
278
+
279
+ set_mock_response_for @app, 1,
280
+ {check_nginx => [:err, ""],
281
+ check_ruby => [:err, ""]},
282
+ {:sudo => yum_sudo}
283
+
284
+ @app.install_deps 'ruby', nginx_dep
285
+
286
+
287
+ each_remote_shell do |ds|
288
+ [nginx_dep, ruby_dep].each do |dep|
289
+ check =
290
+ "test \"$(yum list installed #{dep.pkg} | grep -c #{dep.pkg})\" -ge 1"
291
+ install = dep.instance_variable_get "@install"
292
+
293
+ assert_ssh_call check, ds, :sudo => yum_sudo
294
+ assert_ssh_call install, ds, :sudo => yum_sudo
295
+ end
296
+ end
297
+ end
298
+
299
+
300
+ def test_install_gem_deps
301
+ rake_dep = Sunshine.dependencies.get 'rake'
302
+ bundler_dep = Sunshine.dependencies.get 'bundler'
303
+
304
+ gem_sudo = Sunshine::Gem.sudo
305
+
306
+ checks = {
307
+ rake_dep => "gem list #{rake_dep.pkg} -i --version '>=0.8'",
308
+ bundler_dep => "gem list #{bundler_dep.pkg} -i --version '>=0.9'"
309
+ }
310
+
311
+ checks.values.each do |check|
312
+ set_mock_response_for @app, 1, {check => [:err, ""]}, {:sudo => gem_sudo}
313
+ end
314
+
315
+ @app.install_deps 'rake', bundler_dep
316
+
317
+
318
+ each_remote_shell do |ds|
319
+ [rake_dep, bundler_dep].each do |dep|
320
+
321
+ install = dep.instance_variable_get "@install"
322
+
323
+ assert_ssh_call checks[dep], ds, :sudo => gem_sudo
324
+ assert_ssh_call install, ds, :sudo => gem_sudo
325
+ end
326
+ end
327
+ end
328
+
329
+
330
+ def test_make_app_directories
331
+ @app.make_app_directories
332
+
333
+ each_remote_shell do |ds|
334
+ assert_ssh_call "mkdir -p #{@app.server_apps.first.directories.join(" ")}"
335
+ end
336
+ end
337
+
338
+
339
+ def test_rake
340
+ @app.rake("test:task")
341
+
342
+ each_remote_shell do |ds|
343
+ assert_ssh_call "cd #{@app.checkout_path} && rake test:task"
344
+ end
345
+ end
346
+
347
+
348
+ def test_register_as_deployed
349
+ @app.register_as_deployed
350
+
351
+ each_remote_shell do |ds|
352
+ assert_ssh_call "test -d #{@app.root_path}"
353
+
354
+ yml_list = {@app.name => @app.root_path}.to_yaml
355
+ path = ds.expand_path(Sunshine::APP_LIST_PATH)
356
+
357
+ assert ds.method_called?(:make_file, :args => [path, yml_list])
358
+ end
359
+ end
360
+
361
+
362
+ def test_remove_old_deploys
363
+ returned_dirs = %w{old_deploy1 old_deploy2 old_deploy3 main_deploy}
364
+ old_deploys = returned_dirs[0..-2].map{|d| "#{@app.deploys_path}/#{d}"}
365
+
366
+ list_cmd = "ls -1 #{@app.deploys_path}"
367
+ rm_cmd = "rm -rf #{old_deploys.join(" ")}"
368
+
369
+ set_mock_response_for @app, 0,
370
+ list_cmd => [:out, returned_dirs.join("\n")]
371
+
372
+ Sunshine.setup 'max_deploy_versions' => 1
373
+
374
+ @app.remove_old_deploys
375
+
376
+ each_remote_shell do |ds|
377
+ assert_ssh_call list_cmd
378
+ assert_ssh_call rm_cmd
379
+ end
380
+ end
381
+
382
+
383
+ def test_run_post_user_lambdas
384
+ lambdas_ran = 0
385
+ count = 5
386
+
387
+ count.times do
388
+ @app.after_user_script do |app|
389
+ lambdas_ran = lambdas_ran.next
390
+ end
391
+ end
392
+
393
+ assert_equal 0, lambdas_ran
394
+
395
+ @app.run_post_user_lambdas
396
+
397
+ assert_equal count, lambdas_ran
398
+ end
399
+
400
+
401
+ def test_shell_env
402
+ new_env = {
403
+ "PATH" => "/etc/lib:$PATH",
404
+ "RACK_ENV" => "test",
405
+ "RAILS_ENV" => "test"
406
+ }
407
+
408
+ @app.shell_env new_env
409
+
410
+ assert_equal new_env, @app.shell_env
411
+ end
412
+
413
+
414
+ def test_symlink_current_dir
415
+ @app.symlink_current_dir
416
+
417
+ each_remote_shell do |ds|
418
+ assert_ssh_call "ln -sfT #{@app.checkout_path} #{@app.current_path}"
419
+ end
420
+ end
421
+
422
+
423
+ def test_upload_tasks
424
+ path = "/path/to/tasks"
425
+
426
+ @app.upload_tasks 'common', 'tpkg',
427
+ :host => 'some_server.com',
428
+ :remote_path => path
429
+
430
+ each_remote_shell do |ds|
431
+ assert_ssh_call "mkdir -p /path/to/tasks"
432
+
433
+ %w{common tpkg}.each do |task|
434
+ from = "#{Sunshine::ROOT}/templates/tasks/#{task}.rake"
435
+ to = "#{ds.host}:#{path}/#{task}.rake"
436
+
437
+ assert_rsync from, to
438
+ end
439
+ end
440
+ end
441
+
442
+
443
+ def test_upload_tasks_simple
444
+ @app.upload_tasks
445
+
446
+ path = "#{@app.checkout_path}/lib/tasks"
447
+
448
+ tasks =
449
+ Dir.glob("#{Sunshine::ROOT}/templates/tasks/*").map{|t| File.basename t}
450
+
451
+ each_remote_shell do |ds|
452
+ assert_ssh_call "mkdir -p #{path}"
453
+
454
+ tasks.each do |task|
455
+ from = "#{Sunshine::ROOT}/templates/tasks/#{task}"
456
+ to = "#{ds.host}:#{path}/#{task}"
457
+
458
+ assert_rsync from, to
459
+ end
460
+ end
461
+ end
462
+
463
+
464
+ def test_sudo_assignment
465
+ @app.sudo = "someuser"
466
+
467
+ @app.each do |server_app|
468
+ assert_equal "someuser", server_app.shell.sudo
469
+ end
470
+ end
471
+
472
+
473
+ private
474
+
475
+
476
+ def assert_attributes_equal(attr_hash, app)
477
+ assert_equal attr_hash[:name], app.name
478
+ assert_equal attr_hash[:repo][:url], app.repo.url
479
+ assert_equal attr_hash[:root_path], app.root_path
480
+
481
+ attr_hash[:remote_shells].each_with_index do |server_def, i|
482
+ server_def = server_def.first if Array === server_def
483
+ user, host = server_def.split("@")
484
+ assert_equal host, app.server_apps[i].shell.host
485
+ assert_equal user, app.server_apps[i].shell.user
486
+ end
487
+ end
488
+
489
+ end
@@ -0,0 +1,20 @@
1
+ require 'test/test_helper'
2
+
3
+ class TestBinder < Test::Unit::TestCase
4
+
5
+ def setup
6
+ @target = [1,2,3]
7
+ @binder = Sunshine::Binder.new @target
8
+ end
9
+
10
+ def test_set
11
+ @binder.set :blah, "somevalue"
12
+ assert_equal "somevalue", @binder.blah
13
+ end
14
+
15
+ def test_forward
16
+ @binder.forward :join, :length
17
+ assert_equal @target.join(" "), @binder.join(" ")
18
+ assert_equal @target.length, @binder.length
19
+ end
20
+ end
@@ -0,0 +1,128 @@
1
+ require 'test/test_helper'
2
+
3
+ class TestCrontab < Test::Unit::TestCase
4
+
5
+ def setup
6
+ @crontab_str = <<-STR
7
+ # sunshine crontest:job1:begin
8
+ this job should stay
9
+ # sunshine crontest:job1:end
10
+
11
+ # sunshine crontest:job2:begin
12
+ job2 part 1
13
+ # sunshine crontest:job2:end
14
+
15
+ # sunshine otherapp:blah:begin
16
+ otherapp blah job
17
+ # sunshine otherapp:blah:end
18
+
19
+ # sunshine crontest:job2:begin
20
+ job2 part 2
21
+ # sunshine crontest:job2:end
22
+
23
+ # sunshine otherapp:job1:begin
24
+ job for otherapp
25
+ # sunshine otherapp:job1:end
26
+ STR
27
+
28
+ @shell = mock_remote_shell
29
+
30
+ @cron = Sunshine::Crontab.new "crontest", @shell
31
+
32
+ @othercron = Sunshine::Crontab.new "otherapp", @shell
33
+
34
+ @shell.set_mock_response 0, "crontab -l" => [:out, @crontab_str]
35
+ end
36
+
37
+
38
+ def test_parse
39
+ jobs = @cron.parse @crontab_str
40
+ assert_equal "this job should stay\n", jobs['job1']
41
+ assert_equal "job2 part 1\njob2 part 2\n", jobs['job2']
42
+ assert jobs['blah'].nil?
43
+ end
44
+
45
+
46
+ def test_build
47
+ @cron.jobs["job2"] << "new job2"
48
+ @cron.jobs["job3"] = "new job3"
49
+
50
+ @cron.build @crontab_str
51
+
52
+ assert_cronjob "job1", "this job should stay"
53
+ assert_cronjob "job2", "job2 part 1\njob2 part 2\nnew job2"
54
+ assert_cronjob "job3", "new job3"
55
+
56
+ assert_cronjob "blah", "otherapp blah job", @othercron
57
+ assert_cronjob "job1", "job for otherapp", @othercron
58
+ end
59
+
60
+
61
+ def test_delete!
62
+ assert_cronjob "blah", "otherapp blah job", @othercron
63
+ assert_cronjob "job1", "job for otherapp", @othercron
64
+
65
+ @crontab_str = @othercron.delete!
66
+
67
+ assert !@crontab_str.include?("job for otherapp")
68
+ assert !@crontab_str.include?("otherapp blah job")
69
+
70
+ assert_cronjob "job1", "this job should stay"
71
+ assert_cronjob "job2", "job2 part 1"
72
+ assert_cronjob "job2", "job2 part 2"
73
+ end
74
+
75
+
76
+ def test_write!
77
+ @cron.jobs["job2"] << "new job2"
78
+ @cron.jobs["job3"] = "new job3"
79
+
80
+ @shell.set_mock_response 0, "crontab -l" => [:out, @crontab_str]
81
+
82
+ @crontab_str = @cron.write!
83
+
84
+ assert_cronjob "job1", "this job should stay"
85
+ assert_cronjob "job2", "job2 part 1\njob2 part 2\nnew job2"
86
+ assert_cronjob "job3", "new job3"
87
+
88
+ assert_cronjob "blah", "otherapp blah job", @othercron
89
+ assert_cronjob "job1", "job for otherapp", @othercron
90
+
91
+ cmd = "echo '#{@crontab_str.gsub(/'/){|s| "'\\''"}}' | crontab"
92
+
93
+ assert_ssh_call cmd
94
+ end
95
+
96
+
97
+ def test_deleted_jobs_write!
98
+ @cron.jobs.delete "job1"
99
+
100
+ @shell.set_mock_response 0, "crontab -l" => [:out, @crontab_str]
101
+
102
+ @crontab_str = @cron.write!
103
+
104
+ assert !@crontab_str.include?("this job should stay")
105
+ assert_cronjob "job2", "job2 part 1\njob2 part 2"
106
+
107
+ assert_cronjob "blah", "otherapp blah job", @othercron
108
+ assert_cronjob "job1", "job for otherapp", @othercron
109
+
110
+ cmd = "echo '#{@crontab_str.gsub(/'/){|s| "'\\''"}}' | crontab"
111
+
112
+ assert_ssh_call cmd
113
+ end
114
+
115
+
116
+ def assert_cronjob namespace, job, crontab=@cron
117
+ assert @crontab_str.include?(cronjob(namespace, job, crontab))
118
+ end
119
+
120
+
121
+ def cronjob namespace, job, crontab
122
+ <<-STR
123
+ # sunshine #{crontab.name}:#{namespace}:begin
124
+ #{job}
125
+ # sunshine #{crontab.name}:#{namespace}:end
126
+ STR
127
+ end
128
+ end
@@ -0,0 +1,26 @@
1
+ require 'test/test_helper'
2
+
3
+ class TestGitRepo < Test::Unit::TestCase
4
+
5
+ def test_name
6
+ git = Sunshine::GitRepo.new "git://myrepo/project.git"
7
+ assert_equal "project", git.name
8
+
9
+ git = Sunshine::GitRepo.new "ssh://user@host.xz:456/path/to/project.git"
10
+ assert_equal "project", git.name
11
+
12
+ git = Sunshine::GitRepo.new "user@host.xz:~user/path/to/project.git"
13
+ assert_equal "project", git.name
14
+ end
15
+
16
+
17
+ def test_invalid_name
18
+ git = Sunshine::GitRepo.new "project.git"
19
+ git.name
20
+ raise "GitRepo didn't catch invalid naming scheme: #{git.url}"
21
+ rescue => e
22
+ assert_equal "Git url must match #{Sunshine::GitRepo::NAME_MATCH.inspect}",
23
+ e.message
24
+ end
25
+
26
+ end