chef_cap 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -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