auser-sprinkle 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. data/CREDITS +16 -0
  2. data/History.txt +4 -0
  3. data/MIT-LICENSE +20 -0
  4. data/Manifest.txt +67 -0
  5. data/README.rdoc +224 -0
  6. data/Rakefile +4 -0
  7. data/bin/sprinkle +86 -0
  8. data/config/hoe.rb +70 -0
  9. data/config/requirements.rb +17 -0
  10. data/examples/merb/deploy.rb +5 -0
  11. data/examples/rails/README +15 -0
  12. data/examples/rails/deploy.rb +2 -0
  13. data/examples/rails/packages/database.rb +9 -0
  14. data/examples/rails/packages/essential.rb +6 -0
  15. data/examples/rails/packages/rails.rb +28 -0
  16. data/examples/rails/packages/search.rb +11 -0
  17. data/examples/rails/packages/server.rb +28 -0
  18. data/examples/rails/rails.rb +71 -0
  19. data/examples/sprinkle/sprinkle.rb +38 -0
  20. data/lib/sprinkle.rb +28 -0
  21. data/lib/sprinkle/actors/capistrano.rb +89 -0
  22. data/lib/sprinkle/actors/vlad.rb +39 -0
  23. data/lib/sprinkle/configurable.rb +24 -0
  24. data/lib/sprinkle/deployment.rb +33 -0
  25. data/lib/sprinkle/extensions/arbitrary_options.rb +10 -0
  26. data/lib/sprinkle/extensions/array.rb +7 -0
  27. data/lib/sprinkle/extensions/blank_slate.rb +5 -0
  28. data/lib/sprinkle/extensions/dsl_accessor.rb +15 -0
  29. data/lib/sprinkle/extensions/string.rb +10 -0
  30. data/lib/sprinkle/extensions/symbol.rb +7 -0
  31. data/lib/sprinkle/installers/apt.rb +25 -0
  32. data/lib/sprinkle/installers/gem.rb +33 -0
  33. data/lib/sprinkle/installers/installer.rb +74 -0
  34. data/lib/sprinkle/installers/rake.rb +17 -0
  35. data/lib/sprinkle/installers/rpm.rb +20 -0
  36. data/lib/sprinkle/installers/source.rb +121 -0
  37. data/lib/sprinkle/package.rb +127 -0
  38. data/lib/sprinkle/policy.rb +85 -0
  39. data/lib/sprinkle/script.rb +13 -0
  40. data/lib/sprinkle/verifiers/directory.rb +11 -0
  41. data/lib/sprinkle/verifiers/executable.rb +17 -0
  42. data/lib/sprinkle/verifiers/file.rb +11 -0
  43. data/lib/sprinkle/verifiers/symlink.rb +15 -0
  44. data/lib/sprinkle/verify.rb +55 -0
  45. data/lib/sprinkle/version.rb +9 -0
  46. data/script/destroy +14 -0
  47. data/script/generate +14 -0
  48. data/spec/spec.opts +1 -0
  49. data/spec/spec_helper.rb +17 -0
  50. data/spec/sprinkle/actors/capistrano_spec.rb +170 -0
  51. data/spec/sprinkle/configurable_spec.rb +46 -0
  52. data/spec/sprinkle/deployment_spec.rb +80 -0
  53. data/spec/sprinkle/extensions/array_spec.rb +19 -0
  54. data/spec/sprinkle/extensions/string_spec.rb +21 -0
  55. data/spec/sprinkle/installers/apt_spec.rb +74 -0
  56. data/spec/sprinkle/installers/gem_spec.rb +75 -0
  57. data/spec/sprinkle/installers/installer_spec.rb +151 -0
  58. data/spec/sprinkle/installers/rpm_spec.rb +50 -0
  59. data/spec/sprinkle/installers/source_spec.rb +331 -0
  60. data/spec/sprinkle/package_spec.rb +422 -0
  61. data/spec/sprinkle/policy_spec.rb +126 -0
  62. data/spec/sprinkle/script_spec.rb +51 -0
  63. data/spec/sprinkle/sprinkle_spec.rb +25 -0
  64. data/spec/sprinkle/verify_spec.rb +137 -0
  65. data/sprinkle.gemspec +43 -0
  66. data/tasks/deployment.rake +34 -0
  67. data/tasks/environment.rake +7 -0
  68. data/tasks/rspec.rake +21 -0
  69. metadata +158 -0
@@ -0,0 +1,50 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+
3
+ describe Sprinkle::Installers::Rpm do
4
+
5
+ before do
6
+ @package = mock(Sprinkle::Package, :name => 'package')
7
+ end
8
+
9
+ def create_rpm(debs, &block)
10
+ Sprinkle::Installers::Rpm.new(@package, debs, &block)
11
+ end
12
+
13
+ describe 'when created' do
14
+
15
+ it 'should accept a single package to install' do
16
+ @installer = create_rpm 'ruby'
17
+ @installer.packages.should == [ 'ruby' ]
18
+ end
19
+
20
+ it 'should accept an array of packages to install' do
21
+ @installer = create_rpm %w( gcc gdb g++ )
22
+ @installer.packages.should == ['gcc', 'gdb', 'g++']
23
+ end
24
+
25
+ end
26
+
27
+ describe 'during installation' do
28
+
29
+ before do
30
+ @installer = create_rpm 'ruby' do
31
+ pre :install, 'op1'
32
+ post :install, 'op2'
33
+ end
34
+ @install_commands = @installer.send :install_commands
35
+ end
36
+
37
+ it 'should invoke the rpm installer for all specified packages' do
38
+ @install_commands.should =~ /rpm -Uvh ruby/
39
+ end
40
+
41
+ it 'should automatically insert pre/post commands for the specified package' do
42
+ @installer.send(:install_sequence).should == [ 'op1', 'rpm -Uvh ruby', 'op2' ]
43
+ end
44
+
45
+ it 'should specify a non interactive mode to the apt installer'
46
+ it 'should install a specific version if defined'
47
+
48
+ end
49
+
50
+ end
@@ -0,0 +1,331 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+
3
+ describe Sprinkle::Installers::Source do
4
+ include Sprinkle::Deployment
5
+
6
+ before do
7
+ @source = 'ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.6-p111.tar.gz'
8
+
9
+ @deployment = deployment do
10
+ delivery :capistrano
11
+ source do
12
+ prefix '/usr'
13
+ archives '/usr/archives'
14
+ builds '/usr/builds'
15
+ end
16
+ end
17
+
18
+ @installer = create_source @source do
19
+ prefix '/usr/local'
20
+ archives '/usr/local/archives'
21
+ builds '/usr/local/builds'
22
+
23
+ enable %w( headers ssl deflate so )
24
+ disable %w( cache proxy rewrite )
25
+
26
+ with %w( debug extras )
27
+ without %w( fancyisms )
28
+ end
29
+
30
+ @installer.defaults(@deployment)
31
+ end
32
+
33
+ def create_source(source, version = nil, &block)
34
+ @package = mock(Sprinkle::Package, :name => 'package', :version => version)
35
+ Sprinkle::Installers::Source.new(@package, source, &block)
36
+ end
37
+
38
+ describe 'when created' do
39
+
40
+ it 'should accept a source archive name to install' do
41
+ @installer.source.should == @source
42
+ end
43
+
44
+ end
45
+
46
+ describe 'before installation' do
47
+
48
+ before do
49
+ @settings = { :prefix => '/usr/local', :archives => '/usr/local/tmp', :builds => '/usr/local/stage' }
50
+ end
51
+
52
+ it 'should fail if no installation area has been specified' do
53
+ @settings.delete(:prefix)
54
+ end
55
+
56
+ it 'should fail if no build area has been specified' do
57
+ @settings.delete(:builds)
58
+ end
59
+
60
+ it 'should fail if no source download area has been specified' do
61
+ @settings.delete(:archives)
62
+ end
63
+
64
+ after do
65
+ @settings.each { |k, v| @installer.send k, v }
66
+ lambda { @installer.install_sequence }.should raise_error
67
+ end
68
+
69
+ end
70
+
71
+ describe 'customized configuration' do
72
+
73
+ it 'should support specification of "enable" options' do
74
+ @installer.enable.should == %w( headers ssl deflate so )
75
+ end
76
+
77
+ it 'should support specification of "disable" options' do
78
+ @installer.disable.should == %w( cache proxy rewrite )
79
+ end
80
+
81
+ it 'should support specification of "with" options' do
82
+ @installer.with.should == %w( debug extras )
83
+ end
84
+
85
+ it 'should support specification of "without" options' do
86
+ @installer.without.should == %w( fancyisms )
87
+ end
88
+
89
+ it 'should support customized build area' do
90
+ @installer.prefix.should == '/usr/local'
91
+ end
92
+
93
+ it 'should support customized source area' do
94
+ @installer.archives.should == '/usr/local/archives'
95
+ end
96
+
97
+ it 'should support customized install area' do
98
+ @installer.builds.should == '/usr/local/builds'
99
+ end
100
+
101
+ end
102
+
103
+ describe 'during gnu source archive style installation' do
104
+
105
+ it 'should prepare the build, installation and source archives area' do
106
+ @installer.should_receive(:prepare).and_return(
107
+ [
108
+ 'mkdir -p /usr/local',
109
+ 'mkdir -p /usr/local/builds',
110
+ 'mkdir -p /usr/local/archives'
111
+ ]
112
+ )
113
+
114
+ end
115
+
116
+ it 'should download the source archive' do
117
+ @installer.should_receive(:download).and_return(
118
+ [
119
+ "wget -cq --directory-prefix='/usr/local/archives' #{@source}"
120
+ ]
121
+ )
122
+ end
123
+
124
+ it 'should extract the source archive' do
125
+ @installer.should_receive(:extract).and_return(
126
+ [
127
+ "bash -c 'cd /usr/local/builds && tar xzf /usr/local/archives/ruby-1.8.6-p111.tar.gz"
128
+ ]
129
+ )
130
+ end
131
+
132
+ it 'should configure the source' do
133
+ enable = %w( headers ssl deflate so ).inject([]) { |m, value| m << "--enable-#{value}"; m }
134
+ disable = %w( cache proxy rewrite ).inject([]) { |m, value| m << "--disable-#{value}"; m }
135
+
136
+ with = %w( debug extras ).inject([]) { |m, value| m << "--with-#{value}"; m }
137
+ without = %w( fancyisms ).inject([]) { |m, value| m << "--without-#{value}"; m }
138
+
139
+ options = "#{enable.join(' ')} #{disable.join(' ')} #{with.join(' ')} #{without.join(' ')}"
140
+
141
+ @installer.should_receive(:build).and_return(
142
+ [
143
+ "bash -c 'cd /usr/local/builds && ./configure --prefix=/usr/local #{options} > #{@package.name}-configure.log 2>&1'"
144
+ ]
145
+ )
146
+ end
147
+
148
+ it 'should build the source' do
149
+ @installer.should_receive(:build).and_return(
150
+ [
151
+ "bash -c 'cd /usr/local/builds && make > #{@package.name}-build.log 2>&1'"
152
+ ]
153
+ )
154
+ end
155
+
156
+ it 'should install the source' do
157
+ @installer.should_receive(:install).and_return(
158
+ [
159
+ "bash -c 'cd /usr/local/builds && make install > #{@package.name}-install.log 2>&1'"
160
+ ]
161
+ )
162
+ end
163
+
164
+ describe 'during a customized install' do
165
+
166
+ before do
167
+ @installer = create_source @source do
168
+ custom_install 'ruby setup.rb'
169
+ end
170
+
171
+ @installer.defaults(@deployment)
172
+ end
173
+
174
+ it 'should store the custom install commands' do
175
+ @installer.options[:custom_install].should == 'ruby setup.rb'
176
+ end
177
+
178
+ it 'should identify as having a custom install command' do
179
+ @installer.should be_custom_install
180
+ end
181
+
182
+ it 'should not configure the source automatically' do
183
+ @installer.should_receive(:configure).and_return([])
184
+ end
185
+
186
+ it 'should not build the source automatically' do
187
+ @installer.should_receive(:build).and_return([])
188
+ end
189
+
190
+ it 'should install the source using a custom installation command' do
191
+ @installer.send(:custom_install_commands).first.should =~ /ruby setup.rb/
192
+ end
193
+
194
+ it 'should be run relative to the source build area' do
195
+ @installer.send(:custom_install_commands).first.should =~ %r{cd /usr/builds/ruby-1.8.6-p111}
196
+ end
197
+
198
+ describe 'with a customized directory' do
199
+
200
+ before do
201
+ @installer.options[:custom_dir] = 'test'
202
+ end
203
+
204
+ it 'should install the source from the custom dir path' do
205
+ @installer.send(:custom_install_commands).first.should =~ /test/
206
+ end
207
+
208
+ it 'should store the custom build dir path' do
209
+ @installer.options[:custom_dir].should == 'test'
210
+ end
211
+
212
+ end
213
+
214
+ end
215
+
216
+ after do
217
+ @installer.send :install_sequence
218
+ end
219
+
220
+ end
221
+
222
+ describe 'pre stage commands' do
223
+
224
+ before do
225
+ @commands = {
226
+ :prepare => %w( prepare1 prepare2 ),
227
+ :download => %w( down1 down2 ),
228
+ :extract => %w( ex1 ex2 ),
229
+ :configure => %w( conf1 conf2 ),
230
+ :build => %w( build1 build2 ),
231
+ :install => %w( install1 install2 )
232
+ }
233
+
234
+ @installer = create_source @source
235
+ @commands.each { |k, v| @installer.pre k, *v }
236
+ @installer.defaults(@deployment)
237
+ end
238
+
239
+ it 'should run all pre-prepare commands' do
240
+ @commands.each { |k, v| @installer.should_receive(:pre_commands).with(k).and_return(v) }
241
+ end
242
+
243
+ it 'should be run relative to the source build area' do
244
+ @commands.each { |stage, command| @installer.send(:pre_commands, stage).first.should =~ %r{cd /usr/builds/ruby-1.8.6-p111} }
245
+ end
246
+
247
+ after do
248
+ @installer.send :install_sequence
249
+ end
250
+
251
+ end
252
+
253
+ describe 'post stage commands' do
254
+
255
+ before do
256
+ @commands = {
257
+ :prepare => %w( prepare1 prepare2 ),
258
+ :download => %w( down1 down2 ),
259
+ :extract => %w( ex1 ex2 ),
260
+ :configure => %w( conf1 conf2 ),
261
+ :build => %w( build1 build2 ),
262
+ :install => %w( install1 install2 )
263
+ }
264
+
265
+ @installer = create_source @source
266
+ @commands.each { |k, v| @installer.post k, *v }
267
+ @installer.defaults(@deployment)
268
+ end
269
+
270
+ it 'should run all post-prepare commands' do
271
+ @commands.each { |k, v| @installer.should_receive(:post_commands).with(k).and_return(v) }
272
+ end
273
+
274
+ it 'should be run relative to the source build area' do
275
+ @commands.each { |stage, command| @installer.send(:post_commands, stage).first.should =~ %r{cd /usr/builds/ruby-1.8.6-p111} }
276
+ end
277
+
278
+ after do
279
+ @installer.send :install_sequence
280
+ end
281
+
282
+ end
283
+
284
+ describe 'install sequence' do
285
+
286
+ it 'should prepare, then download, then extract, then configure, then build, then install' do
287
+ %w( prepare download extract configure build install ).each do |stage|
288
+ @installer.should_receive(stage).ordered.and_return([])
289
+ end
290
+ end
291
+
292
+ after do
293
+ @installer.send :install_sequence
294
+ end
295
+
296
+ end
297
+
298
+ describe 'source extraction' do
299
+
300
+ it 'should support tgz archives' do
301
+ @installer.source = 'blah.tgz'
302
+ @extraction = 'tar xzf'
303
+ end
304
+
305
+ it 'should support tar.gz archives' do
306
+ @installer.source = 'blah.tgz'
307
+ @extraction = 'tar xzf'
308
+ end
309
+
310
+ it 'should support tar.bz2 archives' do
311
+ @installer.source = 'blah.tar.bz2'
312
+ @extraction = 'tar xjf'
313
+ end
314
+
315
+ it 'should support tb2 archives' do
316
+ @installer.source = 'blah.tb2'
317
+ @extraction = 'tar xjf'
318
+ end
319
+
320
+ it 'should support zip archives' do
321
+ @installer.source = 'blah.zip'
322
+ @extraction = 'unzip'
323
+ end
324
+
325
+ after do
326
+ @installer.send(:extract_command).should == @extraction
327
+ end
328
+
329
+ end
330
+
331
+ end
@@ -0,0 +1,422 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Sprinkle::Package do
4
+ include Sprinkle::Package
5
+
6
+ before do
7
+ @name = :package_name
8
+ @empty = Proc.new { }
9
+ @opts = { }
10
+ end
11
+
12
+ # Kind of a messy way to do this but it works and DRYs out
13
+ # the specs. Checks to make sure an installer is receiving
14
+ # the block passed to it throught the package block.
15
+ def check_block_forwarding_on(installer)
16
+ eval(<<CODE)
17
+ pre_count = 0
18
+ lambda {
19
+ pkg = package @name do
20
+ #{installer} 'archive' do
21
+ pre :install, 'preOp'
22
+ end
23
+ end
24
+
25
+ pre_count = pkg.installer.instance_variable_get(:@pre)[:install].length
26
+ }.should change { pre_count }.by(1)
27
+ CODE
28
+ end
29
+
30
+ # More of Mitchell's meta-programming to dry up specs.
31
+ def create_package_with_blank_verify(n = 1)
32
+ eval(<<CODE)
33
+ @pkg = package @name do
34
+ gem 'gem'
35
+ #{"verify 'stuff happens' do; end\n" * n}
36
+ end
37
+ CODE
38
+ end
39
+
40
+ describe 'when created' do
41
+
42
+ it 'should be invalid without a block descriptor' do
43
+ lambda { package @name }.should raise_error
44
+ end
45
+
46
+ it 'should be invalid without a name' do
47
+ lambda { package nil, &@empty }.should raise_error
48
+ lambda { package @name, &@empty }.should_not raise_error
49
+ end
50
+
51
+ it 'should optionally accept a description' do
52
+ pkg = package @name do
53
+ description 'my package description'
54
+ end
55
+ pkg.description.should == 'my package description'
56
+ end
57
+
58
+ it 'should optionally accept a version' do
59
+ pkg = package @name do
60
+ version '2.0.2'
61
+ end
62
+ pkg.version.should == '2.0.2'
63
+ end
64
+
65
+ it 'should optionally accept an installer' do
66
+ pkg = package @name do
67
+ gem 'rails'
68
+ end
69
+ pkg.installer.should_not be_nil
70
+ end
71
+
72
+ it 'should optionally accept dependencies' do
73
+ pkg = package @name do
74
+ requires :webserver, :database
75
+ end
76
+ pkg.dependencies.should == [:webserver, :database]
77
+ end
78
+
79
+ it 'should optionally accept recommended dependencies' do
80
+ pkg = package @name do
81
+ recommends :webserver, :database
82
+ end
83
+ pkg.recommends.should == [:webserver, :database]
84
+ end
85
+
86
+ it 'should optionally define a virtual package implementation' do
87
+ pkg = package @name, :provides => :database do; end
88
+ pkg.provides.should == :database
89
+ end
90
+
91
+ it 'should be able to represent itself as a string' do
92
+ pkg = package @name do; end
93
+ pkg.to_s.should == @name
94
+ end
95
+
96
+ end
97
+
98
+ describe 'helper method' do
99
+
100
+ it 'should added new packages to the global package hash' do
101
+ pkg = package @name do; end
102
+ Sprinkle::Package::PACKAGES[@name].should == pkg
103
+ end
104
+
105
+ it 'should add the new package to the provides list if specified' do
106
+ pkg = package @name, :provides => :database do; end
107
+ Sprinkle::Package::PACKAGES[:database].last.should == pkg
108
+ end
109
+
110
+ end
111
+
112
+ describe 'installer configuration' do
113
+
114
+ it 'should optionally accept an apt installer' do
115
+ pkg = package @name do
116
+ apt %w( deb1 deb2 )
117
+ end
118
+ pkg.should respond_to(:apt)
119
+ pkg.installer.class.should == Sprinkle::Installers::Apt
120
+ end
121
+
122
+ it 'should optionally accept an rpm installer' do
123
+ pkg = package @name do
124
+ rpm %w( rpm1 rpm2 )
125
+ end
126
+ pkg.should respond_to(:rpm)
127
+ pkg.installer.class.should == Sprinkle::Installers::Rpm
128
+ end
129
+
130
+ it 'should optionally accept a gem installer' do
131
+ pkg = package @name do
132
+ gem 'gem'
133
+ end
134
+ pkg.should respond_to(:gem)
135
+ pkg.installer.class.should == Sprinkle::Installers::Gem
136
+ end
137
+
138
+ it 'should optionally accept a source installer' do
139
+ pkg = package @name do
140
+ source 'archive'
141
+ end
142
+ pkg.should respond_to(:source)
143
+ pkg.installer.class.should == Sprinkle::Installers::Source
144
+ end
145
+
146
+ end
147
+
148
+ describe 'with a source installer' do
149
+
150
+ it 'should optionally accept a block containing customisations' do
151
+ pkg = package @name do
152
+ source 'archive' do; end
153
+ end
154
+ pkg.should respond_to(:source)
155
+ pkg.installer.class.should == Sprinkle::Installers::Source
156
+ end
157
+
158
+ it 'should forward block to installer superclass' do
159
+ check_block_forwarding_on(:source)
160
+ end
161
+
162
+ it 'should automatically add a build essential recommendation' do
163
+ pkg = package @name do
164
+ source 'archive'
165
+ end
166
+ pkg.recommends.should include(:build_essential)
167
+ end
168
+
169
+ end
170
+
171
+ describe 'with an apt installer' do
172
+ it 'should forward block to installer superclass' do
173
+ check_block_forwarding_on(:apt)
174
+ end
175
+ end
176
+
177
+ describe 'with an rpm installer' do
178
+ it 'should forward block to installer superclass' do
179
+ check_block_forwarding_on(:rpm)
180
+ end
181
+ end
182
+
183
+ describe 'with an gem installer' do
184
+
185
+ it 'should automatically add a rubygems recommendation' do
186
+ pkg = package @name do
187
+ gem 'gem'
188
+ end
189
+ pkg.recommends.should include(:rubygems)
190
+ end
191
+
192
+ it 'should forward block to installer superclass' do
193
+ check_block_forwarding_on(:gem)
194
+ end
195
+
196
+ end
197
+
198
+ describe 'when processing' do
199
+
200
+ before do
201
+ @deployment = mock(Sprinkle::Deployment)
202
+ @roles = [ :app, :db ]
203
+ @installer = mock(Sprinkle::Installers::Installer, :defaults => true, :process => true)
204
+ @package = package @name do; end
205
+ end
206
+
207
+ describe 'with an installer' do
208
+
209
+ before do
210
+ @package.installer = @installer
211
+ end
212
+
213
+ it 'should configure itself against the deployment context' do
214
+ @installer.should_receive(:defaults).with(@deployment).and_return
215
+ end
216
+
217
+ it 'should request the installer to process itself' do
218
+ @installer.should_receive(:process).with(@roles).and_return
219
+ end
220
+
221
+ after do
222
+ @package.process(@deployment, @roles)
223
+ end
224
+ end
225
+
226
+ describe 'without an installer' do
227
+
228
+ it 'should not request the installer to process if the package is a metapackage' do
229
+ @installer.should_not_receive(:process)
230
+ @package.process(@deployment, @roles)
231
+ end
232
+
233
+ end
234
+
235
+ describe 'with verifications' do
236
+ before do
237
+ @pkg = create_package_with_blank_verify(3)
238
+ @pkg.installer = @installer
239
+ @installer.stub!(:defaults)
240
+ @installer.stub!(:process)
241
+ end
242
+
243
+ describe 'with forcing' do
244
+ before do
245
+ # Being explicit
246
+ Sprinkle::OPTIONS[:force] = true
247
+ end
248
+
249
+ it 'should process verifications only once' do
250
+ @pkg.should_receive(:process_verifications).once
251
+ @pkg.process(@deployment, @roles)
252
+ end
253
+
254
+ after do
255
+ # Being explicit
256
+ Sprinkle::OPTIONS[:force] = false
257
+ end
258
+ end
259
+
260
+ describe 'without forcing' do
261
+ before do
262
+ # Being explicit
263
+ Sprinkle::OPTIONS[:force] = false
264
+ end
265
+
266
+ it 'should process verifications twice' do
267
+ @pkg.should_receive(:process_verifications).once.with(@deployment, @roles, true).and_raise(Sprinkle::VerificationFailed.new(@pkg, ''))
268
+ @pkg.should_receive(:process_verifications).once.with(@deployment, @roles).and_raise(Sprinkle::VerificationFailed.new(@pkg, ''))
269
+ end
270
+
271
+ it 'should continue with installation if pre-verification fails' do
272
+ @pkg.should_receive(:process_verifications).twice.and_raise(Sprinkle::VerificationFailed.new(@pkg, ''))
273
+ @installer.should_receive(:defaults)
274
+ @installer.should_receive(:process)
275
+ end
276
+
277
+ it 'should only process verifications once and should not process installer if verifications succeed' do
278
+ @pkg.should_receive(:process_verifications).once.and_return(nil)
279
+ @installer.should_not_receive(:defaults)
280
+ @installer.should_not_receive(:process)
281
+ end
282
+
283
+ after do
284
+ begin
285
+ @pkg.process(@deployment, @roles)
286
+ rescue Sprinkle::VerificationFailed => e; end
287
+ end
288
+ end
289
+ end
290
+
291
+ end
292
+
293
+ describe 'when processing verifications' do
294
+ before do
295
+ @deployment = mock(Sprinkle::Deployment)
296
+ @roles = [ :app, :db ]
297
+ @installer = mock(Sprinkle::Installers::Installer, :defaults => true, :process => true)
298
+ @pkg = create_package_with_blank_verify(3)
299
+ @pkg.installer = @installer
300
+ @installer.stub!(:defaults)
301
+ @installer.stub!(:process)
302
+ @logger = mock(ActiveSupport::BufferedLogger, :debug => true, :debug? => true)
303
+ @logger.stub!(:info)
304
+ end
305
+
306
+ it 'should request _each_ verification to configure itself against the deployment context' do
307
+ @pkg.verifications.each do |v|
308
+ v.should_receive(:defaults).with(@deployment).once
309
+ v.stub!(:process)
310
+ end
311
+ end
312
+
313
+ it 'should request _each_ verification to process' do
314
+ @pkg.verifications.each do |v|
315
+ v.stub!(:defaults)
316
+ v.should_receive(:process).with(@roles).once
317
+ end
318
+ end
319
+
320
+ it 'should enter a log info event to notify user whats happening' do
321
+ @pkg.verifications.each do |v|
322
+ v.stub!(:defaults)
323
+ v.stub!(:process)
324
+ end
325
+
326
+ @pkg.should_receive(:logger).once.and_return(@logger)
327
+ end
328
+
329
+ after do
330
+ @pkg.process_verifications(@deployment, @roles)
331
+ end
332
+ end
333
+
334
+ describe 'hierarchies' do
335
+
336
+ before do
337
+ @a = package :a do; requires :b; end
338
+ @b = package :b do; requires :c; end
339
+ @c = package :c do; recommends :d; end
340
+ @d = package :d do; end
341
+ end
342
+
343
+ it 'should be able to return a dependency hierarchy tree' do
344
+ @a.tree.flatten.should == [ @d, @c, @b, @a ]
345
+ @b.tree.flatten.should == [ @d, @c, @b ]
346
+ @c.tree.flatten.should == [ @d, @c ]
347
+ @d.tree.flatten.should == [ @d ]
348
+ end
349
+
350
+ describe 'with missing recommendations' do
351
+
352
+ before do
353
+ @d.recommends :e
354
+ end
355
+
356
+ it 'should ignore missing recommendations' do
357
+ @d.tree.flatten.should == [ @d ]
358
+ end
359
+
360
+ end
361
+
362
+ it 'should optionally accept a block to call upon item in the tree during hierarchy traversal' do
363
+ @count = 0
364
+ @a.tree do
365
+ @count += 1
366
+ end
367
+ @count.should == 3
368
+ end
369
+
370
+ it 'should maintain a depth count of how deep the hierarchy is' do
371
+ @b.should_receive(:tree).with(2).and_return([@b])
372
+ @a.tree do; end
373
+ end
374
+
375
+ end
376
+
377
+ describe 'with missing dependencies' do
378
+
379
+ before do
380
+ @pkg = package @name do
381
+ gem 'gem'
382
+ requires :missing
383
+ end
384
+ end
385
+
386
+ it 'should raise an error if a package is missing' do
387
+ lambda { @pkg.tree }.should raise_error
388
+ end
389
+
390
+ end
391
+
392
+ describe 'with verifications' do
393
+ it 'should create a Sprinkle::Verification object for the verify block' do
394
+ Sprinkle::Verify.should_receive(:new).once
395
+
396
+ create_package_with_blank_verify
397
+ end
398
+
399
+ it 'should create multiple Sprinkle::Verification objects for multiple verify blocks' do
400
+ Sprinkle::Verify.should_receive(:new).twice
401
+
402
+ create_package_with_blank_verify(2)
403
+ end
404
+
405
+ it 'should add each Sprinkle::Verificaton object to the @verifications array' do
406
+ @pkg = create_package_with_blank_verify(3)
407
+ @pkg.verifications.length.should eql(3)
408
+ end
409
+
410
+ it 'should initialize Sprinkle::Verification with the package name, description, and block' do
411
+ Sprinkle::Verify.should_receive(:new) do |pkg, desc|
412
+ pkg.name.should eql(@name)
413
+ desc.should eql('stuff happens')
414
+ end
415
+
416
+ # We do a should_not raise_error because if a block was NOT passed, an error
417
+ # is raised. This is specced in verification_spec.rb
418
+ lambda { create_package_with_blank_verify }.should_not raise_error
419
+ end
420
+ end
421
+
422
+ end