chef_cap 0.0.5

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.
@@ -0,0 +1,808 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "spec_helper"))
2
+
3
+ describe "chef_cap" do
4
+
5
+ let(:chef_cap) {
6
+ FakeChefCapConfiguration.create(@test_dna)
7
+ }
8
+
9
+ before do
10
+ @test_dna = <<-JS
11
+ {
12
+ "chef": {
13
+ "root": "path_to_cookbooks"
14
+ }
15
+ }
16
+ JS
17
+ end
18
+
19
+ it "hijacks the load method to silently ignore the config/deploy load line if deploy.rb does not exist" do
20
+ File.should_receive(:exist?).and_return(false)
21
+ chef_cap.load("foo").should == true
22
+ end
23
+
24
+ it "loads a JSON file and assigns values to capistrano variables" do
25
+ @test_dna = <<-JS
26
+ {
27
+ "chef": {
28
+ "root": "path_to_cookbooks"
29
+ },
30
+ "application": {
31
+ "name": "frobble"
32
+ }
33
+ }
34
+ JS
35
+ chef_cap.cap_variable[:application].should == "frobble"
36
+ end
37
+
38
+ it "loads all the required capistrano variables" do
39
+ @test_dna = <<-JS
40
+ {
41
+ "chef": {
42
+ "root": "path_to_cookbooks"
43
+ },
44
+ "application": {
45
+ "name": "frobble",
46
+ "repository": "git@somehost:user/repo.git"
47
+ },
48
+ "environments": {
49
+ "defaults": {
50
+ "user": "myuser"
51
+ },
52
+ "some_env": {
53
+ "user": "newenvuser",
54
+ "servers": [
55
+ {
56
+ "hostname": "localhost",
57
+ "roles": ["app", "someotherrole", "db"],
58
+ "primary": ["db"]
59
+ }
60
+ ]
61
+ }
62
+ }
63
+ }
64
+ JS
65
+ chef_cap.cap_variable[:application].should == "frobble"
66
+ chef_cap.cap_variable[:repository].should == "git@somehost:user/repo.git"
67
+ chef_cap.cap_variable[:scm].should == :git
68
+ chef_cap.cap_variable[:user].should == "myuser"
69
+
70
+ chef_cap.cap_variable[:rails_env].should be_nil
71
+ chef_cap.cap_task[:some_env].should_not be_nil
72
+ chef_cap.cap_task[:some_env].call
73
+ chef_cap.cap_variable[:rails_env].should == "some_env"
74
+ chef_cap.cap_variable[:user].should == "newenvuser"
75
+ chef_cap.cap_role[:someotherrole].should_not be_nil
76
+ chef_cap.cap_role[:someotherrole][:servers].should include("localhost")
77
+ chef_cap.cap_role[:app][:servers].should include("localhost")
78
+ chef_cap.cap_role[:db][:servers].should include("localhost")
79
+ chef_cap.cap_role[:db][:primary].should == "localhost"
80
+ end
81
+
82
+ describe "default_environment" do
83
+ it "sets the RAILS_ENV to rails_env" do
84
+ @test_dna = <<-ERB
85
+ {
86
+ "chef": {
87
+ "root": "path_to_cookbooks"
88
+ },
89
+ "environments": {
90
+ "some_env": {
91
+ "rails_env": "my_env"
92
+ }
93
+ }
94
+ }
95
+ ERB
96
+
97
+ chef_cap.cap_task[:some_env].call
98
+ chef_cap.default_environment["RAILS_ENV"].should == "my_env"
99
+ end
100
+ end
101
+
102
+
103
+ describe ":repositories" do
104
+ context "svn" do
105
+ before do
106
+ @test_dna = <<-JS
107
+ {
108
+ "chef": {
109
+ "root": "path_to_cookbooks"
110
+ },
111
+ "application": {
112
+ "repository": "svn://somehost:user/repo/trunk"
113
+ }
114
+ }
115
+ JS
116
+ end
117
+
118
+ it "sets the scm to svn if the repository looks to be subversion" do
119
+ chef_cap.cap_variable[:repository].should == "svn://somehost:user/repo/trunk"
120
+ chef_cap.cap_variable[:scm].should == :svn
121
+ end
122
+
123
+ it "adds a dependency on git existing on the remote machine" do
124
+ chef_cap.cap_depends["svn"].should_not be_nil
125
+ chef_cap.cap_depends["svn"].should == { :remote => :command }
126
+ end
127
+
128
+ end
129
+
130
+ context "git" do
131
+
132
+ before do
133
+ @test_dna = <<-JS
134
+ {
135
+ "chef": {
136
+ "root": "path_to_cookbooks"
137
+ },
138
+ "application": {
139
+ "repository": "git@somehost:user/repo.git"
140
+ }
141
+ }
142
+ JS
143
+ end
144
+
145
+ it "sets additional git settings if the repository looks to be git" do
146
+ chef_cap.cap_variable[:repository].should == "git@somehost:user/repo.git"
147
+ chef_cap.cap_variable[:scm].should == :git
148
+ chef_cap.cap_variable[:git_enable_submodules].should == 1
149
+ end
150
+
151
+ it "adds a dependency on git existing on the remote machine" do
152
+ chef_cap.cap_depends["git"].should_not be_nil
153
+ chef_cap.cap_depends["git"].should == { :remote => :command }
154
+ end
155
+
156
+ it "sets the default_run_options pty to true" do
157
+ chef_cap.default_run_options[:pty].should be_true
158
+ end
159
+ end
160
+
161
+ end
162
+
163
+ describe "ssh keys" do
164
+
165
+ before do
166
+ @test_dna = <<-ERB
167
+ {
168
+ "chef": {
169
+ "root": "path_to_cookbooks"
170
+ },
171
+ "environments": {
172
+ "defaults": {
173
+ "ssh": {
174
+ "deploy_key_file": "#{File.join(File.dirname(__FILE__), '..', 'fixtures', 'ssh_deploy_key')}",
175
+ "authorized_pub_file": "#{File.join(File.dirname(__FILE__), '..', 'fixtures', 'ssh_public_key')}",
176
+ "known_hosts": "knownhostscontent",
177
+ "options": {
178
+ "keys": "some_ssh_key_path"
179
+ }
180
+ }
181
+ }
182
+ }
183
+ }
184
+ ERB
185
+ end
186
+
187
+ it "parses out the deploy private key" do
188
+ chef_cap.cap_variable[:ssh_deploy_key_file].should_not be_nil
189
+ chef_cap.cap_variable[:ssh_deploy_key_file].should == File.join(File.dirname(__FILE__), '..', 'fixtures', 'ssh_deploy_key')
190
+ end
191
+
192
+ it "parses out the authorized public file" do
193
+ chef_cap.cap_variable[:ssh_authorized_pub_file].should_not be_nil
194
+ chef_cap.cap_variable[:ssh_authorized_pub_file].should == File.join(File.dirname(__FILE__), '..', 'fixtures', 'ssh_public_key')
195
+ end
196
+
197
+ it "parses out the known hosts file" do
198
+ chef_cap.cap_variable[:ssh_known_hosts].should_not be_nil
199
+ chef_cap.cap_variable[:ssh_known_hosts].should == "knownhostscontent"
200
+ end
201
+
202
+ it "creates a task that uploads the keys to the server users .ssh directory" do
203
+ chef_cap.cap_namespace[:ssh].should be_true
204
+ chef_cap.cap_task["ssh:transfer_keys"].should_not be_nil
205
+ chef_cap.should_receive(:put).with("dsa imaprivatekey", ".ssh/id_dsa", :mode => "0600").and_return(true)
206
+ chef_cap.should_receive(:put).with("imapublickey", ".ssh/authorized_keys", :mode => "0600").and_return(true)
207
+ chef_cap.should_receive(:put).with("knownhostscontent", ".ssh/known_hosts", :mode => "0600").and_return(true)
208
+
209
+ chef_cap.cap_task["ssh:transfer_keys"].call
210
+ end
211
+
212
+ it "adds a before chef:setup hook that that uploads the keys on every deploy" do
213
+ chef_cap.cap_before["chef:setup"].should_not be_nil
214
+ chef_cap.cap_before["chef:setup"].should include("ssh:transfer_keys")
215
+ end
216
+
217
+ it "adds dependencies on remote files for the ssh files to be uploaded" do
218
+ chef_cap.cap_depends[".ssh/id_dsa"].should_not be_nil
219
+ chef_cap.cap_depends[".ssh/id_dsa"].should == { :remote => :file }
220
+
221
+ chef_cap.cap_depends[".ssh/authorized_keys"].should_not be_nil
222
+ chef_cap.cap_depends[".ssh/authorized_keys"].should == { :remote => :file }
223
+
224
+ chef_cap.cap_depends[".ssh/known_hosts"].should_not be_nil
225
+ chef_cap.cap_depends[".ssh/known_hosts"].should == { :remote => :file }
226
+ end
227
+
228
+ describe "ssh_options" do
229
+ it "parses out keys" do
230
+ chef_cap.cap_ssh_options[:keys].should_not be_nil
231
+ chef_cap.cap_ssh_options[:keys].should == "some_ssh_key_path"
232
+ end
233
+ end
234
+
235
+ end
236
+
237
+ describe "rvm bootstrap" do
238
+ it "uploads a shell script to the server and runs it as root" do
239
+ @test_dna = <<-ERB
240
+ {
241
+ "chef": {
242
+ "root": "path_to_cookbooks"
243
+ },
244
+ "environments": {
245
+ "some_env": {
246
+ "rails_env": "my_env"
247
+ }
248
+ }
249
+ }
250
+ ERB
251
+
252
+ chef_cap.cap_task[:some_env].call
253
+ chef_cap.cap_namespace[:rvm].should_not be_nil
254
+ chef_cap.cap_task["rvm:bootstrap"].should_not be_nil
255
+
256
+ chef_cap.should_receive(:put)
257
+ chef_cap.should_receive(:sudo).with("/tmp/chef-cap-my_env-rvm-standup.sh")
258
+ chef_cap.cap_task["rvm:bootstrap"].call
259
+ end
260
+
261
+ it "adds a dependency check on the rvm command" do
262
+ chef_cap.cap_depends["rvm"].should_not be_nil
263
+ chef_cap.cap_depends["rvm"].should == { :remote => :command }
264
+ end
265
+ end
266
+
267
+ describe "task :chef:cleanup" do
268
+ it "creates a task that wipes all /tmp/chef-cap* files" do
269
+ chef_cap.cap_namespace[:chef].should_not be_nil
270
+ chef_cap.cap_task["chef:cleanup"].should_not be_nil
271
+
272
+ chef_cap.should_receive(:sudo).with("rm -rf /tmp/chef-cap*")
273
+ chef_cap.cap_task["chef:cleanup"].call
274
+ end
275
+ end
276
+
277
+ describe "namespace :chef" do
278
+
279
+ it "adds a remote dependency on chef-solo" do
280
+ chef_cap.cap_depends["chef-solo"].should_not be_nil
281
+ chef_cap.cap_depends["chef-solo"].should == { :remote => :command }
282
+ end
283
+
284
+ it "runs chef:setup before chef:deploy" do
285
+ chef_cap.cap_before["chef:deploy"].should_not be_nil
286
+ chef_cap.cap_before["chef:deploy"].should include("chef:setup")
287
+ end
288
+
289
+ it "runs rvm:bootstrap before chef:setup" do
290
+ chef_cap.cap_before["chef:setup"].should_not be_nil
291
+ chef_cap.cap_before["chef:setup"].should include("rvm:bootstrap")
292
+ end
293
+
294
+ describe "task :deploy" do
295
+
296
+ before do
297
+ @test_dna = <<-JS
298
+ {
299
+ "chef": {
300
+ "root": "path_to_cookbooks"
301
+ },
302
+ "environments": {
303
+ "some_env": {
304
+ "rails_env": "myenv",
305
+ "servers": [
306
+ {
307
+ "hostname": "localhost",
308
+ "roles": ["role1", "role2"]
309
+ },
310
+ {
311
+ "hostname": "otherhost.com",
312
+ "roles": ["role1"]
313
+ }
314
+ ]
315
+ }
316
+ },
317
+ "roles": {
318
+ "role1": { "run_list": ["foo"] },
319
+ "role2": { "run_list": ["foo", "bar"] }
320
+ }
321
+ }
322
+ JS
323
+
324
+ chef_cap.cap_task[:some_env].should_not be_nil
325
+ chef_cap.cap_task[:some_env].call
326
+ end
327
+
328
+ it "exists" do
329
+ chef_cap.cap_namespace[:chef].should be_true
330
+ chef_cap.cap_task["chef:deploy"].should_not be_nil
331
+ end
332
+
333
+ it "modifies the default run list for each host and stores all modified structure" do
334
+ chef_cap.roles.keys.should == ["role1", "role2"]
335
+
336
+ chef_cap.stub!(:put => "stubbed")
337
+ chef_cap.stub!(:upload => "stubbed")
338
+ chef_cap.stub!(:sudo => "stubbed")
339
+
340
+ chef_cap.cap_variable[:environment_settings].should_not be_nil
341
+
342
+ chef_cap.parallel_mocks << proc { |server_session|
343
+ server_session.stub!(:put => "stubbed")
344
+ server_session.stub!(:sudo => "stubbed")
345
+ }
346
+
347
+ chef_cap.cap_task["chef:deploy"].call
348
+
349
+ chef_cap.parallel_sessions.each do |server_session|
350
+ if server_session.things_that_were_set.keys.include? "node_hash_for_localhost"
351
+ server_session.things_that_were_set["node_hash_for_localhost"].should == {
352
+ "environments" => {"some_env"=>{ "rails_env" => "myenv",
353
+ "servers"=>[ {"hostname"=>"localhost", "roles"=>["role1", "role2"] }, {"hostname"=>"otherhost.com", "roles"=>["role1"]}]}},
354
+ "chef" => {"root"=>"path_to_cookbooks"},
355
+ "run_list" => ["foo", "bar"],
356
+ "environment" => {"rails_env" => "myenv", "servers"=>[ {"primary" => [], "hostname"=>"localhost", "roles"=>["role1", "role2"] },
357
+ {"primary" => [], "hostname"=>"otherhost.com", "roles"=>["role1"]}]},
358
+ "roles" => {"role1" => {"run_list"=>["foo"]}, "role2"=>{"run_list"=>["foo", "bar"]}}}
359
+ elsif server_session.things_that_were_set.keys.include? "node_hash_for_otherhost"
360
+ server_session.things_that_were_set["node_hash_for_otherhost"].should == {
361
+ "environments" => {"some_env"=>{ "rails_env" => "myenv",
362
+ "servers"=>[{"hostname"=>"localhost", "roles"=>["role1", "role2"]}, {"hostname"=>"otherhost.com", "roles"=>["role1"]}]}},
363
+ "chef"=>{"root"=>"path_to_cookbooks"},
364
+ "run_list"=>["foo"],
365
+ "environment"=>{"rails_env" => "myenv", "servers"=>[{"primary" => [], "hostname"=>"localhost", "roles"=>["role1", "role2"]},
366
+ {"primary" => [], "hostname"=>"otherhost.com", "roles"=>["role1"]}]},
367
+ "roles"=>{"role1"=>{"run_list"=>["foo"]}, "role2"=>{"run_list"=>["foo", "bar"]}}}
368
+ end
369
+ end
370
+ end
371
+
372
+ it "that uploads the DNA.json and a solo.rb file" do
373
+ pending "FIXME"
374
+ localhost_dna = JSON.parse(@test_dna).dup
375
+ otherhost_dna = JSON.parse(@test_dna).dup
376
+ localhost_dna["run_list"] = ["foo", "bar"]
377
+ localhost_dna["environment"] = localhost_dna["environments"]["some_env"]
378
+ otherhost_dna["run_list"] = ["foo"]
379
+ otherhost_dna["environment"] = otherhost_dna["environments"]["some_env"]
380
+
381
+ chef_cap.parallel_mocks << proc { |server_session|
382
+ server_session.should_receive(:put).ordered.with(localhost_dna.to_json, "/tmp/chef-cap-myenv.json", :mode => "0600", :hosts => "localhost").and_return("mocked")
383
+ server_session.should_receive(:put).ordered.with(otherhost_dna.to_json, "/tmp/chef-cap-myenv.json", :mode => "0600", :hosts => "otherhost.com").and_return("mocked")
384
+ server_session.stub!(:set => "stubbed")
385
+ server_session.stub!(:sudo => "stubbed")
386
+ }
387
+ chef_cap.should_receive(:put).ordered.with("cookbook_path '/tmp/chef-cap-myenv/cookbooks'", "/tmp/chef-cap-solo-myenv.rb", :mode => "0600").and_return("mocked")
388
+ chef_cap.stub!(:upload => "stubbed")
389
+ chef_cap.stub!(:sudo => "stubbed")
390
+ chef_cap.cap_task["chef:deploy"].call
391
+ end
392
+
393
+ it "uploads the cookbooks" do
394
+ chef_cap.stub!(:put => "stubbed")
395
+ chef_cap.should_receive(:upload).with("path_to_cookbooks", "/tmp/chef-cap-myenv", :mode => "0700").and_return("mocked")
396
+ chef_cap.stub!(:sudo => "stubbed")
397
+ chef_cap.parallel_mocks << proc { |server_session|
398
+ server_session.stub!(:put => "stubbed")
399
+ server_session.stub!(:set => "stubbed")
400
+ server_session.stub!(:sudo => "stubbed")
401
+ }
402
+ chef_cap.cap_task["chef:deploy"].call
403
+ end
404
+
405
+ it "sets up chef gem" do
406
+ chef_cap.cap_servers.should_not be_empty
407
+ chef_cap.should_receive(:sudo).ordered.with("rvm default exec gem specification --version '>=0.9.12' chef 2>&1 | awk 'BEGIN { s = 0 } /^name:/ { s = 1; exit }; END { if(s == 0) exit 1 }' || sudo rvm default exec gem install chef --no-ri --no-rdoc && echo 'Chef Solo already on this server.'").and_return("mocked")
408
+ chef_cap.should_receive(:sudo).ordered.with("rvm default exec which chef-solo").and_return("mocked")
409
+ chef_cap.cap_task["chef:setup"].call
410
+ end
411
+
412
+ it "installs rvm + ruby and run it if it does not exist" do
413
+ chef_cap.cap_servers.should_not be_empty
414
+ chef_cap.stub!(:put => "stubbed")
415
+ chef_cap.should_receive(:sudo).ordered.with("/tmp/chef-cap-myenv-rvm-standup.sh").and_return("mocked")
416
+ chef_cap.cap_task["rvm:bootstrap"].call
417
+ end
418
+
419
+ end
420
+
421
+ describe "task :run_chef_solo" do
422
+
423
+ before do
424
+ @test_dna = <<-JS
425
+ {
426
+ "chef": {
427
+ "root": "path_to_cookbooks"
428
+ },
429
+ "environments": {
430
+ "some_env": {
431
+ "rails_env": "myenv",
432
+ "servers": [
433
+ {
434
+ "hostname": "dbhost",
435
+ "roles": ["db"]
436
+ },
437
+ {
438
+ "hostname": "apphost",
439
+ "roles": ["app"]
440
+ }
441
+ ]
442
+ }
443
+ },
444
+ "roles": {
445
+ "db": { "run_list": [] },
446
+ "app": { "run_list": [] }
447
+ }
448
+ }
449
+ JS
450
+
451
+ chef_cap.cap_task[:some_env].should_not be_nil
452
+ chef_cap.cap_task[:some_env].call
453
+ end
454
+
455
+ it "invokes chef-solo on db hosts then app and web only hosts" do
456
+ chef_cap.cap_servers.should_not be_empty
457
+
458
+ chef_cap.should_receive(:sudo).ordered.with(/.*chef-solo.*/, :hosts => ["dbhost"]).and_return("mocked")
459
+ chef_cap.should_receive(:sudo).ordered.with(/.*chef-solo.*/, :hosts => ["apphost"]).and_return("mocked")
460
+ chef_cap.cap_task["chef:run_chef_solo"].call
461
+ end
462
+ end
463
+
464
+ describe "merging roles with shared" do
465
+
466
+ before do
467
+ @test_dna = <<-JS
468
+ {
469
+ "chef": {
470
+ "root": "path_to_cookbooks"
471
+ },
472
+ "environments": {
473
+ "some_env": {
474
+ "servers": [
475
+ {
476
+ "hostname": "localhost",
477
+ "roles": ["role1", "role2"]
478
+ },
479
+ {
480
+ "hostname": "otherhost",
481
+ "roles": ["role2"]
482
+ }
483
+ ]
484
+ }
485
+ },
486
+ "shared": {
487
+ "string": "shouldbeoverwritten",
488
+ "simple": ["one", "two"],
489
+ "complicated": {
490
+ "three": { "shared": "shouldbeoverwritten", "alsoshared": ["shared"] },
491
+ "four": "shouldbeoverwritten",
492
+ "five": "stringtype"
493
+ },
494
+ "run_list": ["shared"]
495
+ },
496
+ "roles": {
497
+ "role1": {
498
+ "string": "overwritten",
499
+ "simple": ["merged"],
500
+ "run_list": ["role1", "roleshared"]
501
+ },
502
+ "role2": {
503
+ "complicated": {
504
+ "three": { "shared": "overwritten", "alsoshared": ["merged"] },
505
+ "four": "overwritten",
506
+ "five": ["newtype"]
507
+ },
508
+ "run_list": ["role2", "roleshared"]
509
+ }
510
+ },
511
+ "run_list": ["everything"]
512
+ }
513
+ JS
514
+ end
515
+
516
+ it "merges recursively all shared and all roles data down into top level keys" do
517
+ chef_cap.stub!(:put => "stubbed")
518
+ chef_cap.stub!(:upload => "stubbed")
519
+ chef_cap.stub!(:sudo => "stubbed")
520
+
521
+ chef_cap.cap_task[:some_env].call
522
+
523
+ chef_cap.parallel_mocks << proc { |server_session|
524
+ server_session.stub!(:put => "stubbed")
525
+ server_session.stub!(:sudo => "stubbed")
526
+ }
527
+
528
+ chef_cap.cap_task["chef:deploy"].call
529
+
530
+ chef_cap.parallel_sessions.each do |server_session|
531
+ if server_session.things_that_were_set.keys.include? "node_hash_for_localhost"
532
+ server_session.things_that_were_set["node_hash_for_localhost"]["simple"].should == ["one", "two", "merged"]
533
+ server_session.things_that_were_set["node_hash_for_localhost"]["complicated"].should == {"three"=>{"alsoshared"=>["merged"], "shared"=>"overwritten"}, "four"=>"overwritten", "five"=>["newtype"]}
534
+ server_session.things_that_were_set["node_hash_for_localhost"]["string"].should == "overwritten"
535
+ server_session.things_that_were_set["node_hash_for_localhost"]["run_list"].should == ["everything", "shared", "role1", "roleshared", "role2"]
536
+ elsif server_session.things_that_were_set.keys.include? "node_hash_for_otherhost"
537
+ server_session.things_that_were_set["node_hash_for_otherhost"]["simple"].should == ["one", "two"]
538
+ server_session.things_that_were_set["node_hash_for_otherhost"]["complicated"].should == {"three"=>{"alsoshared"=>["merged"], "shared"=>"overwritten"}, "four"=>"overwritten", "five"=>["newtype"]}
539
+ server_session.things_that_were_set["node_hash_for_otherhost"]["string"].should == "shouldbeoverwritten"
540
+ server_session.things_that_were_set["node_hash_for_otherhost"]["run_list"].should == ["everything", "shared", "role2", "roleshared"]
541
+ end
542
+ end
543
+ end
544
+ end
545
+
546
+ describe "node[:deploy_recipe]" do
547
+ before do
548
+ @test_dna = <<-JS
549
+ {
550
+ "chef": {
551
+ "root": "path_to_cookbooks"
552
+ },
553
+ "deploy_recipe": "my_deploy_recipe",
554
+ "environments": {
555
+ "some_env": {
556
+ "something_else": "okay",
557
+ "servers": [
558
+ {
559
+ "hostname": "localhost",
560
+ "roles": ["role1", "role2"]
561
+ }
562
+ ]
563
+ }
564
+ },
565
+ "roles": {
566
+ "role1": {
567
+ "string": "overwritten",
568
+ "simple": ["merged"],
569
+ "run_list": ["role1", "roleshared"]
570
+ },
571
+ "role2": {
572
+ "complicated": {
573
+ "three": { "shared": "overwritten", "alsoshared": ["merged"] },
574
+ "four": "overwritten",
575
+ "five": ["newtype"]
576
+ },
577
+ "run_list": ["my_deploy_recipe", "something", "something", "darkside"]
578
+ }
579
+ }
580
+ }
581
+ JS
582
+ end
583
+
584
+ it "puts the specified deploy_recipe at the very end of the run list" do
585
+ chef_cap.stub!(:put => "stubbed")
586
+ chef_cap.stub!(:upload => "stubbed")
587
+ chef_cap.stub!(:sudo => "stubbed")
588
+
589
+ chef_cap.cap_task[:some_env].call
590
+
591
+ chef_cap.parallel_mocks << proc { |server_session|
592
+ server_session.stub!(:put => "stubbed")
593
+ server_session.stub!(:sudo => "stubbed")
594
+ }
595
+
596
+ chef_cap.cap_task["chef:deploy"].call
597
+
598
+ chef_cap.parallel_sessions.each do |server_session|
599
+ server_session.things_that_were_set["node_hash_for_localhost"]["run_list"].should == ["role1", "roleshared", "something", "darkside", "my_deploy_recipe"]
600
+ end
601
+ end
602
+ end
603
+
604
+ describe "node[:environment]" do
605
+ before do
606
+ @test_dna = <<-JS
607
+ {
608
+ "chef": {
609
+ "root": "path_to_cookbooks"
610
+ },
611
+ "environments": {
612
+ "defaults": {
613
+ "some_default": "yes"
614
+ },
615
+ "some_env": {
616
+ "something_else": "okay",
617
+ "servers": [
618
+ {
619
+ "hostname": "localhost",
620
+ "roles": ["role1", "role2"]
621
+ }
622
+ ]
623
+ },
624
+ "ignored_env": {
625
+ "should_not_be_there": "yup"
626
+ }
627
+ }
628
+ }
629
+ JS
630
+ end
631
+
632
+ it "contains a copy of the structure of the environment we are in that merged with the defaults" do
633
+ chef_cap.stub!(:put => "stubbed")
634
+ chef_cap.stub!(:upload => "stubbed")
635
+ chef_cap.stub!(:sudo => "stubbed")
636
+
637
+ chef_cap.cap_task[:some_env].call
638
+
639
+ chef_cap.parallel_mocks << proc { |server_session|
640
+ server_session.stub!(:put => "stubbed")
641
+ server_session.stub!(:sudo => "stubbed")
642
+ }
643
+
644
+ chef_cap.cap_task["chef:deploy"].call
645
+
646
+ chef_cap.parallel_sessions.each do |server_session|
647
+ if server_session.things_that_were_set.keys.include? "node_hash_for_localhost"
648
+ server_session.things_that_were_set["node_hash_for_localhost"]["environment"].should == {"some_default"=>"yes",
649
+ "something_else"=>"okay",
650
+ "servers"=>[{"primary" => [], "hostname"=>"localhost", "roles"=>["role1", "role2"]}]}
651
+ end
652
+ end
653
+ end
654
+ end
655
+
656
+ describe "upload" do
657
+ before do
658
+ @test_dna = <<-JS
659
+ {
660
+ "chef": {
661
+ "root": "path_to_cookbooks"
662
+ },
663
+ "upload": [
664
+ {
665
+ "source": "some_source",
666
+ "destination": "some_destination",
667
+ "roles": ["role1"]
668
+ }
669
+ ],
670
+ "environments": {
671
+ "defaults": {
672
+ },
673
+ "some_env": {
674
+ "servers": [
675
+ {
676
+ "hostname": "localhost",
677
+ "roles": ["role1", "role2"]
678
+ },
679
+ {
680
+ "hostname": "otherhost",
681
+ "roles": ["role2"]
682
+ }
683
+ ]
684
+ }
685
+ }
686
+ }
687
+ JS
688
+ end
689
+
690
+ it "defines a chef:upload task and per role tasks" do
691
+ chef_cap.cap_task["chef:upload_all"].should_not be_nil
692
+ chef_cap.cap_task[:chef_upload_for_role1].should_not be_nil
693
+ end
694
+
695
+ it "runs chef:upload before chef:deploy" do
696
+ chef_cap.cap_before["chef:deploy"].should_not be_nil
697
+ chef_cap.cap_before["chef:deploy"].should include("chef:upload_all")
698
+ end
699
+
700
+ it "takes all hashes listed and uploads the source to the destinations for the given roles" do
701
+ pending "Need to mock out channel inside of run"
702
+ chef_cap.cap_task[:some_env].call
703
+
704
+ chef_cap.cap_task["chef:upload_all"].call
705
+ chef_cap.cap_run["md5sum some_destination | cut -f1 -d ' '"].should_not be_nil
706
+ result = chef_cap.cap_run["md5sum some_destination | cut -f1 -d ' '"]
707
+ chef_cap.stub!(:'`' => "whatever result")
708
+ chef_cap.should_receive(:upload).with("some_source", "some_destination", {:mode => "0644"})
709
+ result.call("channel", "stream", "data")
710
+ end
711
+ end
712
+ end
713
+
714
+ describe "task :cook" do
715
+ before do
716
+ @test_dna = <<-JS
717
+ {
718
+ "chef": {
719
+ "root": "path_to_cookbooks"
720
+ },
721
+ "deploy_recipe": "my_deploy_recipe",
722
+ "environments": {
723
+ "some_env": {
724
+ "servers": [
725
+ {
726
+ "hostname": "localhost",
727
+ "roles": ["role1", "role2"]
728
+ }
729
+ ]
730
+ }
731
+ },
732
+ "roles": {
733
+ "role1": {
734
+ "string": "overwritten",
735
+ "simple": ["merged"],
736
+ "run_list": ["role1", "roleshared"]
737
+ }
738
+ }
739
+ }
740
+ JS
741
+ end
742
+
743
+ it "defines a cook task that calls chef deploy but without the deploy recipe" do
744
+ chef_cap.cap_task[:cook].should_not be_nil
745
+
746
+ chef_cap.cap_task[:some_env].call
747
+
748
+ chef_cap.cap_task[:cook].call
749
+ end
750
+
751
+ it "calls chef:setup before cook" do
752
+ chef_cap.cap_before["cook"].should_not be_nil
753
+ chef_cap.cap_before["cook"].should include("chef:setup")
754
+ end
755
+ end
756
+
757
+ describe "rev environment variable" do
758
+ before do
759
+ @test_dna = <<-JS
760
+ {
761
+ "chef": {
762
+ "root": "path_to_cookbooks"
763
+ },
764
+ "environments": {
765
+ "some_env": {
766
+ "servers": [
767
+ {
768
+ "hostname": "localhost",
769
+ "roles": ["role1", "role2"]
770
+ }
771
+ ]
772
+ }
773
+ },
774
+ "shared": {
775
+ "foo": "bar"
776
+ },
777
+ "roles": {
778
+ "role1": {
779
+ "something": "other"
780
+ }
781
+ }
782
+ }
783
+ JS
784
+ end
785
+
786
+ it "shoves the value into the node json alongside branch" do
787
+ ENV['rev'] = "123"
788
+ chef_cap.stub!(:put => "stubbed")
789
+ chef_cap.stub!(:upload => "stubbed")
790
+ chef_cap.stub!(:sudo => "stubbed")
791
+
792
+ chef_cap.cap_task[:some_env].call
793
+ chef_cap.parallel_mocks << proc { |server_session|
794
+ server_session.stub!(:put => "stubbed")
795
+ server_session.stub!(:sudo => "stubbed")
796
+ server_session.should_receive(:set).with("node_hash_for_localhost",
797
+ {"environments" => { "some_env"=>{"servers"=>[{"hostname"=>"localhost", "roles"=>["role1", "role2"]}]}},
798
+ "something"=>"other", "foo"=>"bar",
799
+ "chef"=>{"root"=>"path_to_cookbooks"},
800
+ "run_list"=>nil, "shared"=>{"foo"=>"bar"},
801
+ "environment"=> {"revision"=>"123", "servers"=>[{"primary" => [], "hostname"=>"localhost", "roles"=>["role1", "role2"]}]}, "roles"=>{"role1"=>{"something"=>"other"}}}
802
+ )
803
+ }
804
+ chef_cap.cap_task["chef:deploy"].call
805
+ end
806
+ end
807
+
808
+ end