puppet 2.7.5 → 2.7.6

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of puppet might be problematic. Click here for more details.

Files changed (140) hide show
  1. data/CHANGELOG +121 -0
  2. data/conf/redhat/puppet.spec +16 -7
  3. data/lib/puppet.rb +1 -1
  4. data/lib/puppet/application/cert.rb +17 -3
  5. data/lib/puppet/application/device.rb +1 -0
  6. data/lib/puppet/application/kick.rb +0 -2
  7. data/lib/puppet/application/resource.rb +73 -66
  8. data/lib/puppet/configurer/plugin_handler.rb +6 -2
  9. data/lib/puppet/defaults.rb +60 -5
  10. data/lib/puppet/face/ca.rb +11 -2
  11. data/lib/puppet/face/certificate.rb +33 -4
  12. data/lib/puppet/file_serving/fileset.rb +1 -1
  13. data/lib/puppet/file_serving/indirection_hooks.rb +2 -2
  14. data/lib/puppet/file_serving/metadata.rb +43 -4
  15. data/lib/puppet/indirector.rb +0 -1
  16. data/lib/puppet/indirector/request.rb +3 -4
  17. data/lib/puppet/indirector/resource/active_record.rb +3 -10
  18. data/lib/puppet/indirector/resource/ral.rb +2 -2
  19. data/lib/puppet/indirector/rest.rb +1 -1
  20. data/lib/puppet/network/handler/ca.rb +16 -106
  21. data/lib/puppet/network/handler/master.rb +0 -3
  22. data/lib/puppet/network/handler/runner.rb +1 -0
  23. data/lib/puppet/parser/scope.rb +10 -0
  24. data/lib/puppet/provider/file/posix.rb +72 -34
  25. data/lib/puppet/provider/file/windows.rb +100 -0
  26. data/lib/puppet/provider/group/windows_adsi.rb +2 -2
  27. data/lib/puppet/provider/user/windows_adsi.rb +19 -4
  28. data/lib/puppet/resource.rb +16 -0
  29. data/lib/puppet/resource/catalog.rb +1 -1
  30. data/lib/puppet/ssl/certificate.rb +2 -2
  31. data/lib/puppet/ssl/certificate_authority.rb +86 -10
  32. data/lib/puppet/ssl/certificate_authority/interface.rb +64 -19
  33. data/lib/puppet/ssl/certificate_factory.rb +112 -91
  34. data/lib/puppet/ssl/certificate_request.rb +88 -1
  35. data/lib/puppet/ssl/host.rb +20 -3
  36. data/lib/puppet/type/file.rb +15 -34
  37. data/lib/puppet/type/file/group.rb +11 -91
  38. data/lib/puppet/type/file/mode.rb +11 -41
  39. data/lib/puppet/type/file/owner.rb +18 -34
  40. data/lib/puppet/type/file/source.rb +22 -7
  41. data/lib/puppet/type/group.rb +4 -3
  42. data/lib/puppet/type/user.rb +4 -1
  43. data/lib/puppet/util.rb +59 -6
  44. data/lib/puppet/util/adsi.rb +11 -0
  45. data/lib/puppet/util/log.rb +4 -0
  46. data/lib/puppet/util/log/destinations.rb +7 -1
  47. data/lib/puppet/util/monkey_patches.rb +19 -0
  48. data/lib/puppet/util/network_device/config.rb +4 -5
  49. data/lib/puppet/util/settings.rb +5 -0
  50. data/lib/puppet/util/suidmanager.rb +0 -1
  51. data/lib/puppet/util/windows.rb +4 -0
  52. data/lib/puppet/util/windows/error.rb +16 -0
  53. data/lib/puppet/util/windows/security.rb +593 -0
  54. data/spec/integration/defaults_spec.rb +27 -0
  55. data/spec/integration/network/handler_spec.rb +1 -1
  56. data/spec/integration/type/file_spec.rb +382 -145
  57. data/spec/integration/util/windows/security_spec.rb +468 -0
  58. data/spec/shared_behaviours/file_serving.rb +4 -3
  59. data/spec/unit/application/agent_spec.rb +1 -0
  60. data/spec/unit/application/device_spec.rb +5 -0
  61. data/spec/unit/application/resource_spec.rb +62 -101
  62. data/spec/unit/configurer/downloader_spec.rb +2 -2
  63. data/spec/unit/configurer/plugin_handler_spec.rb +15 -8
  64. data/spec/unit/configurer_spec.rb +2 -2
  65. data/spec/unit/face/ca_spec.rb +34 -0
  66. data/spec/unit/face/certificate_spec.rb +168 -1
  67. data/spec/unit/file_serving/fileset_spec.rb +1 -1
  68. data/spec/unit/file_serving/indirection_hooks_spec.rb +1 -1
  69. data/spec/unit/file_serving/metadata_spec.rb +151 -107
  70. data/spec/unit/indirector/certificate_request/ca_spec.rb +0 -3
  71. data/spec/unit/indirector/direct_file_server_spec.rb +10 -9
  72. data/spec/unit/indirector/file_metadata/file_spec.rb +6 -4
  73. data/spec/unit/indirector/request_spec.rb +13 -3
  74. data/spec/unit/indirector/resource/active_record_spec.rb +4 -10
  75. data/spec/unit/indirector/resource/ral_spec.rb +6 -4
  76. data/spec/unit/indirector/rest_spec.rb +5 -6
  77. data/spec/unit/network/handler/ca_spec.rb +86 -0
  78. data/spec/unit/parser/collector_spec.rb +7 -7
  79. data/spec/unit/parser/scope_spec.rb +20 -0
  80. data/spec/unit/provider/file/posix_spec.rb +226 -0
  81. data/spec/unit/provider/file/windows_spec.rb +136 -0
  82. data/spec/unit/provider/group/windows_adsi_spec.rb +7 -2
  83. data/spec/unit/provider/user/windows_adsi_spec.rb +36 -3
  84. data/spec/unit/resource/catalog_spec.rb +20 -10
  85. data/spec/unit/resource_spec.rb +55 -8
  86. data/spec/unit/ssl/certificate_authority/interface_spec.rb +97 -54
  87. data/spec/unit/ssl/certificate_authority_spec.rb +133 -23
  88. data/spec/unit/ssl/certificate_factory_spec.rb +90 -70
  89. data/spec/unit/ssl/certificate_request_spec.rb +62 -1
  90. data/spec/unit/ssl/certificate_spec.rb +20 -14
  91. data/spec/unit/ssl/host_spec.rb +52 -6
  92. data/spec/unit/type/file/content_spec.rb +4 -4
  93. data/spec/unit/type/file/group_spec.rb +34 -96
  94. data/spec/unit/type/file/mode_spec.rb +88 -0
  95. data/spec/unit/type/file/owner_spec.rb +32 -123
  96. data/spec/unit/type/file/source_spec.rb +120 -41
  97. data/spec/unit/type/file_spec.rb +1033 -753
  98. data/spec/unit/type_spec.rb +19 -1
  99. data/spec/unit/util/adsi_spec.rb +19 -0
  100. data/spec/unit/util/log/destinations_spec.rb +75 -0
  101. data/spec/unit/util/log_spec.rb +15 -0
  102. data/spec/unit/util/network_device/config_spec.rb +7 -0
  103. data/spec/unit/util/settings_spec.rb +10 -0
  104. data/spec/unit/util_spec.rb +126 -13
  105. data/test/language/functions.rb +0 -1
  106. data/test/language/snippets.rb +0 -9
  107. data/test/lib/puppettest/exetest.rb +1 -1
  108. data/test/lib/puppettest/servertest.rb +0 -1
  109. data/test/rails/rails.rb +0 -1
  110. data/test/ral/type/filesources.rb +0 -60
  111. metadata +13 -33
  112. data/lib/puppet/network/client.rb +0 -174
  113. data/lib/puppet/network/client/ca.rb +0 -56
  114. data/lib/puppet/network/client/file.rb +0 -6
  115. data/lib/puppet/network/client/proxy.rb +0 -27
  116. data/lib/puppet/network/client/report.rb +0 -26
  117. data/lib/puppet/network/client/runner.rb +0 -10
  118. data/lib/puppet/network/client/status.rb +0 -4
  119. data/lib/puppet/network/http_server.rb +0 -3
  120. data/lib/puppet/network/http_server/mongrel.rb +0 -130
  121. data/lib/puppet/network/http_server/webrick.rb +0 -155
  122. data/lib/puppet/network/xmlrpc/client.rb +0 -211
  123. data/lib/puppet/provider/file/win32.rb +0 -72
  124. data/lib/puppet/sslcertificates.rb +0 -146
  125. data/lib/puppet/sslcertificates/ca.rb +0 -375
  126. data/lib/puppet/sslcertificates/certificate.rb +0 -255
  127. data/lib/puppet/sslcertificates/inventory.rb +0 -38
  128. data/lib/puppet/sslcertificates/support.rb +0 -146
  129. data/spec/integration/network/client_spec.rb +0 -18
  130. data/spec/unit/network/xmlrpc/client_spec.rb +0 -172
  131. data/spec/unit/sslcertificates/ca_spec.rb +0 -106
  132. data/test/certmgr/certmgr.rb +0 -308
  133. data/test/certmgr/inventory.rb +0 -69
  134. data/test/certmgr/support.rb +0 -105
  135. data/test/network/client/ca.rb +0 -69
  136. data/test/network/client/dipper.rb +0 -34
  137. data/test/network/handler/ca.rb +0 -273
  138. data/test/network/server/mongrel_test.rb +0 -99
  139. data/test/network/server/webrick.rb +0 -111
  140. data/test/network/xmlrpc/client.rb +0 -45
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env rspec
2
2
  require 'spec_helper'
3
+ require 'uri'
3
4
 
4
5
  source = Puppet::Type.type(:file).attrclass(:source)
5
6
  describe Puppet::Type.type(:file).attrclass(:source) do
@@ -8,26 +9,83 @@ describe Puppet::Type.type(:file).attrclass(:source) do
8
9
  before do
9
10
  # Wow that's a messy interface to the resource.
10
11
  @resource = stub 'resource', :[]= => nil, :property => nil, :catalog => stub("catalog", :dependent_data_expired? => false), :line => 0, :file => ''
11
- @foobar = make_absolute("/foo/bar")
12
- @feebooz = make_absolute("/fee/booz")
12
+ @foobar = make_absolute("/foo/bar baz")
13
+ @feebooz = make_absolute("/fee/booz baz")
14
+
15
+ @foobar_uri = URI.unescape(Puppet::Util.path_to_uri(@foobar).to_s)
16
+ @feebooz_uri = URI.unescape(Puppet::Util.path_to_uri(@feebooz).to_s)
13
17
  end
14
18
 
15
19
  it "should be a subclass of Parameter" do
16
20
  source.superclass.must == Puppet::Parameter
17
21
  end
18
22
 
19
- describe "when initializing" do
23
+ describe "#validate" do
24
+ let(:path) { tmpfile('file_source_validate') }
25
+ let(:resource) { Puppet::Type.type(:file).new(:path => path) }
26
+
20
27
  it "should fail if the set values are not URLs" do
21
- s = source.new(:resource => @resource)
22
28
  URI.expects(:parse).with('foo').raises RuntimeError
23
29
 
24
- lambda { s.value = %w{foo} }.must raise_error(Puppet::Error)
30
+ lambda { resource[:source] = %w{foo} }.must raise_error(Puppet::Error)
25
31
  end
26
32
 
27
33
  it "should fail if the URI is not a local file, file URI, or puppet URI" do
28
- s = source.new(:resource => @resource)
34
+ lambda { resource[:source] = %w{http://foo/bar} }.must raise_error(Puppet::Error, /Cannot use URLs of type 'http' as source for fileserving/)
35
+ end
36
+
37
+ it "should strip trailing forward slashes", :unless => Puppet.features.microsoft_windows? do
38
+ resource[:source] = "/foo/bar\\//"
39
+ resource[:source].should == %w{file:/foo/bar\\}
40
+ end
41
+
42
+ it "should strip trailing forward and backslashes", :if => Puppet.features.microsoft_windows? do
43
+ resource[:source] = "X:/foo/bar\\//"
44
+ resource[:source].should == %w{file:/X:/foo/bar}
45
+ end
46
+
47
+ it "should accept an array of sources" do
48
+ resource[:source] = %w{file:///foo/bar puppet://host:8140/foo/bar}
49
+ resource[:source].should == %w{file:///foo/bar puppet://host:8140/foo/bar}
50
+ end
29
51
 
30
- lambda { s.value = %w{http://foo/bar} }.must raise_error(Puppet::Error)
52
+ it "should accept file path characters that are not valid in URI" do
53
+ resource[:source] = 'file:///foo bar'
54
+ end
55
+
56
+ it "should reject relative URI sources" do
57
+ lambda { resource[:source] = 'foo/bar' }.must raise_error(Puppet::Error)
58
+ end
59
+
60
+ it "should reject opaque sources" do
61
+ lambda { resource[:source] = 'mailto:foo@com' }.must raise_error(Puppet::Error)
62
+ end
63
+
64
+ it "should accept URI authority component" do
65
+ resource[:source] = 'file://host/foo'
66
+ resource[:source].should == %w{file://host/foo}
67
+ end
68
+
69
+ it "should accept when URI authority is absent" do
70
+ resource[:source] = 'file:///foo/bar'
71
+ resource[:source].should == %w{file:///foo/bar}
72
+ end
73
+ end
74
+
75
+ describe "#munge" do
76
+ let(:path) { tmpfile('file_source_munge') }
77
+ let(:resource) { Puppet::Type.type(:file).new(:path => path) }
78
+
79
+ it "should prefix file scheme to absolute paths" do
80
+ resource[:source] = path
81
+ resource[:source].should == [URI.unescape(Puppet::Util.path_to_uri(path).to_s)]
82
+ end
83
+
84
+ %w[file puppet].each do |scheme|
85
+ it "should not prefix valid #{scheme} URIs" do
86
+ resource[:source] = "#{scheme}:///foo bar"
87
+ resource[:source].should == ["#{scheme}:///foo bar"]
88
+ end
31
89
  end
32
90
  end
33
91
 
@@ -49,30 +107,30 @@ describe Puppet::Type.type(:file).attrclass(:source) do
49
107
 
50
108
  it "should collect its metadata using the Metadata class if it is not already set" do
51
109
  @source = source.new(:resource => @resource, :value => @foobar)
52
- Puppet::FileServing::Metadata.indirection.expects(:find).with(@foobar).returns @metadata
110
+ Puppet::FileServing::Metadata.indirection.expects(:find).with(@foobar_uri).returns @metadata
53
111
  @source.metadata
54
112
  end
55
113
 
56
114
  it "should use the metadata from the first found source" do
57
115
  metadata = stub 'metadata', :source= => nil
58
116
  @source = source.new(:resource => @resource, :value => [@foobar, @feebooz])
59
- Puppet::FileServing::Metadata.indirection.expects(:find).with(@foobar).returns nil
60
- Puppet::FileServing::Metadata.indirection.expects(:find).with(@feebooz).returns metadata
117
+ Puppet::FileServing::Metadata.indirection.expects(:find).with(@foobar_uri).returns nil
118
+ Puppet::FileServing::Metadata.indirection.expects(:find).with(@feebooz_uri).returns metadata
61
119
  @source.metadata.should equal(metadata)
62
120
  end
63
121
 
64
122
  it "should store the found source as the metadata's source" do
65
123
  metadata = mock 'metadata'
66
124
  @source = source.new(:resource => @resource, :value => @foobar)
67
- Puppet::FileServing::Metadata.indirection.expects(:find).with(@foobar).returns metadata
125
+ Puppet::FileServing::Metadata.indirection.expects(:find).with(@foobar_uri).returns metadata
68
126
 
69
- metadata.expects(:source=).with(@foobar)
127
+ metadata.expects(:source=).with(@foobar_uri)
70
128
  @source.metadata
71
129
  end
72
130
 
73
131
  it "should fail intelligently if an exception is encountered while querying for metadata" do
74
132
  @source = source.new(:resource => @resource, :value => @foobar)
75
- Puppet::FileServing::Metadata.indirection.expects(:find).with(@foobar).raises RuntimeError
133
+ Puppet::FileServing::Metadata.indirection.expects(:find).with(@foobar_uri).raises RuntimeError
76
134
 
77
135
  @source.expects(:fail).raises ArgumentError
78
136
  lambda { @source.metadata }.should raise_error(ArgumentError)
@@ -80,7 +138,7 @@ describe Puppet::Type.type(:file).attrclass(:source) do
80
138
 
81
139
  it "should fail if no specified sources can be found" do
82
140
  @source = source.new(:resource => @resource, :value => @foobar)
83
- Puppet::FileServing::Metadata.indirection.expects(:find).with(@foobar).returns nil
141
+ Puppet::FileServing::Metadata.indirection.expects(:find).with(@foobar_uri).returns nil
84
142
 
85
143
  @source.expects(:fail).raises RuntimeError
86
144
 
@@ -185,67 +243,88 @@ describe Puppet::Type.type(:file).attrclass(:source) do
185
243
  end
186
244
 
187
245
  context "when accessing source properties" do
188
- before(:each) do
189
- @source = source.new(:resource => @resource)
190
- @metadata = stub_everything
191
- @source.stubs(:metadata).returns(@metadata)
192
- end
246
+ let(:path) { tmpfile('file_resource') }
247
+ let(:resource) { Puppet::Type.type(:file).new(:path => path) }
248
+ let(:sourcepath) { tmpfile('file_source') }
193
249
 
194
250
  describe "for local sources" do
195
- before(:each) do
196
- @metadata.stubs(:ftype).returns "file"
197
- @metadata.stubs(:source).returns("file:///path/to/source")
251
+ before :each do
252
+ FileUtils.touch(sourcepath)
198
253
  end
199
254
 
200
- it "should be local" do
201
- @source.must be_local
255
+ describe "on POSIX systems", :if => Puppet.features.posix? do
256
+ ['', "file:", "file://"].each do |prefix|
257
+ it "with prefix '#{prefix}' should be local" do
258
+ resource[:source] = "#{prefix}#{sourcepath}"
259
+ resource.parameter(:source).must be_local
260
+ end
261
+
262
+ it "should be able to return the metadata source full path" do
263
+ resource[:source] = "#{prefix}#{sourcepath}"
264
+ resource.parameter(:source).full_path.should == sourcepath
265
+ end
266
+ end
202
267
  end
203
268
 
204
- it "should be local if there is no scheme" do
205
- @metadata.stubs(:source).returns("/path/to/source")
206
- @source.must be_local
207
- end
269
+ describe "on Windows systems", :if => Puppet.features.microsoft_windows? do
270
+ ['', "file:/", "file:///"].each do |prefix|
271
+ it "should be local with prefix '#{prefix}'" do
272
+ resource[:source] = "#{prefix}#{sourcepath}"
273
+ resource.parameter(:source).must be_local
274
+ end
275
+
276
+ it "should be able to return the metadata source full path" do
277
+ resource[:source] = "#{prefix}#{sourcepath}"
278
+ resource.parameter(:source).full_path.should == sourcepath
279
+ end
280
+
281
+ it "should convert backslashes to forward slashes" do
282
+ resource[:source] = "#{prefix}#{sourcepath.gsub(/\\/, '/')}"
283
+ end
284
+ end
208
285
 
209
- it "should be able to return the metadata source full path" do
210
- @source.full_path.should == "/path/to/source"
286
+ it "should be UNC with two slashes"
211
287
  end
212
288
  end
213
289
 
214
290
  describe "for remote sources" do
291
+ let(:sourcepath) { "/path/to/source" }
292
+ let(:uri) { URI::Generic.build(:scheme => 'puppet', :host => 'server', :port => 8192, :path => sourcepath).to_s }
293
+
215
294
  before(:each) do
216
- @metadata.stubs(:ftype).returns "file"
217
- @metadata.stubs(:source).returns("puppet://server:8192/path/to/source")
295
+ metadata = Puppet::FileServing::Metadata.new(path, :source => uri, 'type' => 'file')
296
+ #metadata = stub('remote', :ftype => "file", :source => uri)
297
+ Puppet::FileServing::Metadata.indirection.stubs(:find).with(uri).returns metadata
298
+ resource[:source] = uri
218
299
  end
219
300
 
220
301
  it "should not be local" do
221
- @source.should_not be_local
302
+ resource.parameter(:source).should_not be_local
222
303
  end
223
304
 
224
305
  it "should be able to return the metadata source full path" do
225
- @source.full_path.should == "/path/to/source"
306
+ resource.parameter(:source).full_path.should == "/path/to/source"
226
307
  end
227
308
 
228
309
  it "should be able to return the source server" do
229
- @source.server.should == "server"
310
+ resource.parameter(:source).server.should == "server"
230
311
  end
231
312
 
232
313
  it "should be able to return the source port" do
233
- @source.port.should == 8192
314
+ resource.parameter(:source).port.should == 8192
234
315
  end
235
316
 
236
317
  describe "which don't specify server or port" do
237
- before(:each) do
238
- @metadata.stubs(:source).returns("puppet:///path/to/source")
239
- end
318
+ let(:uri) { "puppet:///path/to/source" }
240
319
 
241
320
  it "should return the default source server" do
242
321
  Puppet.settings.expects(:[]).with(:server).returns("myserver")
243
- @source.server.should == "myserver"
322
+ resource.parameter(:source).server.should == "myserver"
244
323
  end
245
324
 
246
325
  it "should return the default source port" do
247
326
  Puppet.settings.expects(:[]).with(:masterport).returns(1234)
248
- @source.port.should == 1234
327
+ resource.parameter(:source).port.should == 1234
249
328
  end
250
329
  end
251
330
  end
@@ -2,622 +2,635 @@
2
2
  require 'spec_helper'
3
3
 
4
4
  describe Puppet::Type.type(:file) do
5
+ include PuppetSpec::Files
6
+
7
+ let(:path) { tmpfile('file_testing') }
8
+ let(:file) { described_class.new(:path => path, :catalog => catalog) }
9
+ let(:provider) { file.provider }
10
+ let(:catalog) { Puppet::Resource::Catalog.new }
11
+
5
12
  before do
6
- Puppet.settings.stubs(:use)
7
13
  @real_posix = Puppet.features.posix?
8
14
  Puppet.features.stubs("posix?").returns(true)
9
-
10
- @path = Tempfile.new("puppetspec")
11
- pathname = @path.path
12
- @path.close!()
13
- @path = pathname
14
- @file = Puppet::Type::File.new(:name => @path)
15
-
16
- @catalog = Puppet::Resource::Catalog.new
17
- @file.catalog = @catalog
18
15
  end
19
16
 
20
- describe "when determining if recursion is enabled" do
21
- it "should default to recursion being disabled" do
22
- @file.should_not be_recurse
23
- end
24
- [true, "true", 10, "inf", "remote"].each do |value|
25
- it "should consider #{value} to enable recursion" do
26
- @file[:recurse] = value
27
- @file.must be_recurse
17
+ describe "the path parameter" do
18
+ describe "on POSIX systems", :if => Puppet.features.posix? do
19
+ it "should remove trailing slashes" do
20
+ file[:path] = "/foo/bar/baz/"
21
+ file[:path].should == "/foo/bar/baz"
28
22
  end
29
- end
30
23
 
31
- [false, "false", 0].each do |value|
32
- it "should consider #{value} to disable recursion" do
33
- @file[:recurse] = value
34
- @file.should_not be_recurse
24
+ it "should remove double slashes" do
25
+ file[:path] = "/foo/bar//baz"
26
+ file[:path].should == "/foo/bar/baz"
35
27
  end
36
- end
37
- end
38
-
39
- describe "#write" do
40
- it "should propagate failures encountered when renaming the temporary file" do
41
- File.stubs(:open)
42
28
 
43
- File.expects(:rename).raises ArgumentError
44
- file = Puppet::Type::File.new(:name => "/my/file", :backup => "puppet")
29
+ it "should remove trailing double slashes" do
30
+ file[:path] = "/foo/bar/baz//"
31
+ file[:path].should == "/foo/bar/baz"
32
+ end
45
33
 
46
- file.stubs(:validate_checksum?).returns(false)
34
+ it "should leave a single slash alone" do
35
+ file[:path] = "/"
36
+ file[:path].should == "/"
37
+ end
47
38
 
48
- property = stub('content_property', :actual_content => "something", :length => "something".length)
49
- file.stubs(:property).with(:content).returns(property)
39
+ it "should accept a double-slash at the start of the path" do
40
+ expect {
41
+ file[:path] = "//tmp/xxx"
42
+ # REVISIT: This should be wrong, later. See the next test.
43
+ # --daniel 2011-01-31
44
+ file[:path].should == '/tmp/xxx'
45
+ }.should_not raise_error
46
+ end
50
47
 
51
- lambda { file.write(:content) }.should raise_error(Puppet::Error)
48
+ # REVISIT: This is pending, because I don't want to try and audit the
49
+ # entire codebase to make sure we get this right. POSIX treats two (and
50
+ # exactly two) '/' characters at the start of the path specially.
51
+ #
52
+ # See sections 3.2 and 4.11, which allow DomainOS to be all special like
53
+ # and still have the POSIX branding and all. --daniel 2011-01-31
54
+ it "should preserve the double-slash at the start of the path"
52
55
  end
53
56
 
54
- it "should delegate writing to the content property" do
55
- filehandle = stub_everything 'fh'
56
- File.stubs(:open).yields(filehandle)
57
- File.stubs(:rename)
58
- property = stub('content_property', :actual_content => "something", :length => "something".length)
59
- file = Puppet::Type::File.new(:name => "/my/file", :backup => "puppet")
60
- file.stubs(:validate_checksum?).returns(false)
61
- file.stubs(:property).with(:content).returns(property)
57
+ describe "on Windows systems", :if => Puppet.features.microsoft_windows? do
58
+ it "should remove trailing slashes" do
59
+ file[:path] = "X:/foo/bar/baz/"
60
+ file[:path].should == "X:/foo/bar/baz"
61
+ end
62
62
 
63
- property.expects(:write).with(filehandle)
63
+ it "should remove double slashes" do
64
+ file[:path] = "X:/foo/bar//baz"
65
+ file[:path].should == "X:/foo/bar/baz"
66
+ end
64
67
 
65
- file.write(:content)
66
- end
68
+ it "should remove trailing double slashes" do
69
+ file[:path] = "X:/foo/bar/baz//"
70
+ file[:path].should == "X:/foo/bar/baz"
71
+ end
67
72
 
68
- describe "when validating the checksum" do
69
- before { @file.stubs(:validate_checksum?).returns(true) }
73
+ it "should leave a drive letter with a slash alone", :'fails_on_ruby_1.9.2' => true do
74
+ file[:path] = "X:/"
75
+ file[:path].should == "X:/"
76
+ end
70
77
 
71
- it "should fail if the checksum parameter and content checksums do not match" do
72
- checksum = stub('checksum_parameter', :sum => 'checksum_b', :sum_file => 'checksum_b')
73
- @file.stubs(:parameter).with(:checksum).returns(checksum)
78
+ it "should not accept a drive letter without a slash", :'fails_on_ruby_1.9.2' => true do
79
+ lambda { file[:path] = "X:" }.should raise_error(/File paths must be fully qualified/)
80
+ end
74
81
 
75
- property = stub('content_property', :actual_content => "something", :length => "something".length, :write => 'checksum_a')
76
- @file.stubs(:property).with(:content).returns(property)
82
+ describe "when using UNC filenames", :if => Puppet.features.microsoft_windows?, :'fails_on_ruby_1.9.2' => true do
83
+ before :each do
84
+ pending("UNC file paths not yet supported")
85
+ end
77
86
 
78
- lambda { @file.write :NOTUSED }.should raise_error(Puppet::Error)
79
- end
80
- end
87
+ it "should remove trailing slashes" do
88
+ file[:path] = "//server/foo/bar/baz/"
89
+ file[:path].should == "//server/foo/bar/baz"
90
+ end
81
91
 
82
- describe "when not validating the checksum" do
83
- before { @file.stubs(:validate_checksum?).returns(false) }
92
+ it "should remove double slashes" do
93
+ file[:path] = "//server/foo/bar//baz"
94
+ file[:path].should == "//server/foo/bar/baz"
95
+ end
84
96
 
85
- it "should not fail if the checksum property and content checksums do not match" do
86
- checksum = stub('checksum_parameter', :sum => 'checksum_b')
87
- @file.stubs(:parameter).with(:checksum).returns(checksum)
97
+ it "should remove trailing double slashes" do
98
+ file[:path] = "//server/foo/bar/baz//"
99
+ file[:path].should == "//server/foo/bar/baz"
100
+ end
88
101
 
89
- property = stub('content_property', :actual_content => "something", :length => "something".length, :write => 'checksum_a')
90
- @file.stubs(:property).with(:content).returns(property)
102
+ it "should remove a trailing slash from a sharename" do
103
+ file[:path] = "//server/foo/"
104
+ file[:path].should == "//server/foo"
105
+ end
91
106
 
92
- lambda { @file.write :NOTUSED }.should_not raise_error(Puppet::Error)
107
+ it "should not modify a sharename" do
108
+ file[:path] = "//server/foo"
109
+ file[:path].should == "//server/foo"
110
+ end
93
111
  end
94
112
  end
95
113
  end
96
114
 
97
- it "should have a method for determining if the file is present" do
98
- @file.must respond_to(:exist?)
99
- end
115
+ describe "the backup parameter" do
116
+ [false, 'false', :false].each do |value|
117
+ it "should disable backup if the value is #{value.inspect}" do
118
+ file[:backup] = value
119
+ file[:backup].should == false
120
+ end
121
+ end
100
122
 
101
- it "should be considered existent if it can be stat'ed" do
102
- @file.expects(:stat).returns mock('stat')
103
- @file.must be_exist
104
- end
123
+ [true, 'true', '.puppet-bak'].each do |value|
124
+ it "should use .puppet-bak if the value is #{value.inspect}" do
125
+ file[:backup] = value
126
+ file[:backup].should == '.puppet-bak'
127
+ end
128
+ end
105
129
 
106
- it "should be considered nonexistent if it can not be stat'ed" do
107
- @file.expects(:stat).returns nil
108
- @file.must_not be_exist
109
- end
130
+ it "should use the provided value if it's any other string" do
131
+ file[:backup] = "over there"
132
+ file[:backup].should == "over there"
133
+ end
110
134
 
111
- it "should have a method for determining if the file should be a normal file" do
112
- @file.must respond_to(:should_be_file?)
135
+ it "should fail if backup is set to anything else" do
136
+ expect do
137
+ file[:backup] = 97
138
+ end.to raise_error(Puppet::Error, /Invalid backup type 97/)
139
+ end
113
140
  end
114
141
 
115
- it "should be a file if :ensure is set to :file" do
116
- @file[:ensure] = :file
117
- @file.must be_should_be_file
118
- end
142
+ describe "the recurse parameter" do
143
+ it "should default to recursion being disabled" do
144
+ file[:recurse].should be_false
145
+ end
119
146
 
120
- it "should be a file if :ensure is set to :present and the file exists as a normal file" do
121
- @file.stubs(:stat).returns(mock('stat', :ftype => "file"))
122
- @file[:ensure] = :present
123
- @file.must be_should_be_file
124
- end
147
+ [true, "true", 10, "inf", "remote"].each do |value|
148
+ it "should consider #{value} to enable recursion" do
149
+ file[:recurse] = value
150
+ file[:recurse].should be_true
151
+ end
152
+ end
125
153
 
126
- it "should not be a file if :ensure is set to something other than :file" do
127
- @file[:ensure] = :directory
128
- @file.must_not be_should_be_file
129
- end
154
+ [false, "false", 0].each do |value|
155
+ it "should consider #{value} to disable recursion" do
156
+ file[:recurse] = value
157
+ file[:recurse].should be_false
158
+ end
159
+ end
130
160
 
131
- it "should not be a file if :ensure is set to :present and the file exists but is not a normal file" do
132
- @file.stubs(:stat).returns(mock('stat', :ftype => "directory"))
133
- @file[:ensure] = :present
134
- @file.must_not be_should_be_file
161
+ it "should warn if recurse is specified as a number" do
162
+ file[:recurse] = 3
163
+ message = /Setting recursion depth with the recurse parameter is now deprecated, please use recurselimit/
164
+ @logs.find { |log| log.level == :warning and log.message =~ message}.should_not be_nil
165
+ end
135
166
  end
136
167
 
137
- it "should be a file if :ensure is not set and :content is" do
138
- @file[:content] = "foo"
139
- @file.must be_should_be_file
140
- end
168
+ describe "the recurselimit parameter" do
169
+ it "should accept integers" do
170
+ file[:recurselimit] = 12
171
+ file[:recurselimit].should == 12
172
+ end
141
173
 
142
- it "should be a file if neither :ensure nor :content is set but the file exists as a normal file" do
143
- @file.stubs(:stat).returns(mock("stat", :ftype => "file"))
144
- @file.must be_should_be_file
145
- end
174
+ it "should munge string numbers to number numbers" do
175
+ file[:recurselimit] = '12'
176
+ file[:recurselimit].should == 12
177
+ end
146
178
 
147
- it "should not be a file if neither :ensure nor :content is set but the file exists but not as a normal file" do
148
- @file.stubs(:stat).returns(mock("stat", :ftype => "directory"))
149
- @file.must_not be_should_be_file
179
+ it "should fail if given a non-number" do
180
+ expect do
181
+ file[:recurselimit] = 'twelve'
182
+ end.to raise_error(Puppet::Error, /Invalid value "twelve"/)
183
+ end
150
184
  end
151
185
 
152
- describe "when using POSIX filenames" do
153
- it "should autorequire its parent directory" do
154
- file = Puppet::Type::File.new(:path => "/foo/bar")
155
- dir = Puppet::Type::File.new(:path => "/foo")
156
- @catalog.add_resource file
157
- @catalog.add_resource dir
158
- reqs = file.autorequire
159
- reqs[0].source.must == dir
160
- reqs[0].target.must == file
186
+ describe "the replace parameter" do
187
+ [true, :true, :yes].each do |value|
188
+ it "should consider #{value} to be true" do
189
+ file[:replace] = value
190
+ file[:replace].should == :true
191
+ end
161
192
  end
162
193
 
163
- it "should autorequire its nearest ancestor directory" do
164
- file = Puppet::Type::File.new(:path => "/foo/bar/baz")
165
- dir = Puppet::Type::File.new(:path => "/foo")
166
- root = Puppet::Type::File.new(:path => "/")
167
- @catalog.add_resource file
168
- @catalog.add_resource dir
169
- @catalog.add_resource root
170
- reqs = file.autorequire
171
- reqs.length.must == 1
172
- reqs[0].source.must == dir
173
- reqs[0].target.must == file
194
+ [false, :false, :no].each do |value|
195
+ it "should consider #{value} to be false" do
196
+ file[:replace] = value
197
+ file[:replace].should == :false
198
+ end
174
199
  end
200
+ end
175
201
 
176
- it "should not autorequire anything when there is no nearest ancestor directory" do
177
- file = Puppet::Type::File.new(:path => "/foo/bar/baz")
178
- @catalog.add_resource file
179
- file.autorequire.should be_empty
202
+ describe "#[]" do
203
+ it "should raise an exception" do
204
+ expect do
205
+ described_class['anything']
206
+ end.to raise_error("Global resource access is deprecated")
180
207
  end
208
+ end
181
209
 
182
- it "should not autorequire its parent dir if its parent dir is itself" do
183
- file = Puppet::Type::File.new(:path => "/")
184
- @catalog.add_resource file
185
- file.autorequire.should be_empty
210
+ describe ".instances" do
211
+ it "should return an empty array" do
212
+ described_class.instances.should == []
186
213
  end
214
+ end
187
215
 
188
- it "should remove trailing slashes" do
189
- file = Puppet::Type::File.new(:path => "/foo/bar/baz/")
190
- file[:path].should == "/foo/bar/baz"
216
+ describe "#asuser" do
217
+ before :each do
218
+ # Mocha won't let me just stub SUIDManager.asuser to yield and return,
219
+ # but it will do exactly that if we're not root.
220
+ Puppet.features.stubs(:root?).returns false
191
221
  end
192
222
 
193
- it "should remove double slashes" do
194
- file = Puppet::Type::File.new(:path => "/foo/bar//baz")
195
- file[:path].should == "/foo/bar/baz"
196
- end
223
+ it "should return the desired owner if they can write to the parent directory" do
224
+ file[:owner] = 1001
225
+ FileTest.stubs(:writable?).with(File.dirname file[:path]).returns true
197
226
 
198
- it "should remove trailing double slashes" do
199
- file = Puppet::Type::File.new(:path => "/foo/bar/baz//")
200
- file[:path].should == "/foo/bar/baz"
227
+ file.asuser.should == 1001
201
228
  end
202
229
 
203
- it "should leave a single slash alone" do
204
- file = Puppet::Type::File.new(:path => "/")
205
- file[:path].should == "/"
206
- end
230
+ it "should return nil if the desired owner can't write to the parent directory" do
231
+ file[:owner] = 1001
232
+ FileTest.stubs(:writable?).with(File.dirname file[:path]).returns false
207
233
 
208
- it "should accept a double-slash at the start of the path" do
209
- expect {
210
- file = Puppet::Type::File.new(:path => "//tmp/xxx")
211
- # REVISIT: This should be wrong, later. See the next test.
212
- # --daniel 2011-01-31
213
- file[:path].should == '/tmp/xxx'
214
- }.should_not raise_error
234
+ file.asuser.should == nil
215
235
  end
216
236
 
217
- # REVISIT: This is pending, because I don't want to try and audit the
218
- # entire codebase to make sure we get this right. POSIX treats two (and
219
- # exactly two) '/' characters at the start of the path specially.
220
- #
221
- # See sections 3.2 and 4.11, which allow DomainOS to be all special like
222
- # and still have the POSIX branding and all. --daniel 2011-01-31
223
- it "should preserve the double-slash at the start of the path"
237
+ it "should return nil if not managing owner" do
238
+ file.asuser.should == nil
239
+ end
224
240
  end
225
241
 
226
- describe "when using Microsoft Windows filenames" do
227
- it "should autorequire its parent directory" do
228
- file = Puppet::Type::File.new(:path => "X:/foo/bar")
229
- dir = Puppet::Type::File.new(:path => "X:/foo")
230
- @catalog.add_resource file
231
- @catalog.add_resource dir
232
- reqs = file.autorequire
233
- reqs[0].source.must == dir
234
- reqs[0].target.must == file
242
+ describe "#bucket" do
243
+ it "should return nil if backup is off" do
244
+ file[:backup] = false
245
+ file.bucket.should == nil
235
246
  end
236
247
 
237
- it "should autorequire its nearest ancestor directory" do
238
- file = Puppet::Type::File.new(:path => "X:/foo/bar/baz")
239
- dir = Puppet::Type::File.new(:path => "X:/foo")
240
- root = Puppet::Type::File.new(:path => "X:/")
241
- @catalog.add_resource file
242
- @catalog.add_resource dir
243
- @catalog.add_resource root
244
- reqs = file.autorequire
245
- reqs.length.must == 1
246
- reqs[0].source.must == dir
247
- reqs[0].target.must == file
248
- end
248
+ it "should not return a bucket if using a file extension for backup" do
249
+ file[:backup] = '.backup'
249
250
 
250
- it "should not autorequire anything when there is no nearest ancestor directory" do
251
- file = Puppet::Type::File.new(:path => "X:/foo/bar/baz")
252
- @catalog.add_resource file
253
- file.autorequire.should be_empty
251
+ file.bucket.should == nil
254
252
  end
255
253
 
256
- it "should not autorequire its parent dir if its parent dir is itself" do
257
- file = Puppet::Type::File.new(:path => "X:/")
258
- @catalog.add_resource file
259
- file.autorequire.should be_empty
260
- end
254
+ it "should return the default filebucket if using the 'puppet' filebucket" do
255
+ file[:backup] = 'puppet'
256
+ bucket = stub('bucket')
257
+ file.stubs(:default_bucket).returns bucket
261
258
 
262
- it "should remove trailing slashes" do
263
- file = Puppet::Type::File.new(:path => "X:/foo/bar/baz/")
264
- file[:path].should == "X:/foo/bar/baz"
259
+ file.bucket.should == bucket
265
260
  end
266
261
 
267
- it "should remove double slashes" do
268
- file = Puppet::Type::File.new(:path => "X:/foo/bar//baz")
269
- file[:path].should == "X:/foo/bar/baz"
270
- end
262
+ it "should fail if using a remote filebucket and no catalog exists" do
263
+ file.catalog = nil
264
+ file[:backup] = 'my_bucket'
271
265
 
272
- it "should remove trailing double slashes" do
273
- file = Puppet::Type::File.new(:path => "X:/foo/bar/baz//")
274
- file[:path].should == "X:/foo/bar/baz"
266
+ expect { file.bucket }.to raise_error(Puppet::Error, "Can not find filebucket for backups without a catalog")
275
267
  end
276
268
 
277
- it "should leave a drive letter with a slash alone", :'fails_on_ruby_1.9.2' => true do
278
- file = Puppet::Type::File.new(:path => "X:/")
279
- file[:path].should == "X:/"
269
+ it "should fail if the specified filebucket isn't in the catalog" do
270
+ file[:backup] = 'my_bucket'
271
+
272
+ expect { file.bucket }.to raise_error(Puppet::Error, "Could not find filebucket my_bucket specified in backup")
280
273
  end
281
274
 
282
- it "should not accept a drive letter without a slash", :'fails_on_ruby_1.9.2' => true do
283
- lambda { Puppet::Type::File.new(:path => "X:") }.should raise_error(/File paths must be fully qualified/)
275
+ it "should use the specified filebucket if it is in the catalog" do
276
+ file[:backup] = 'my_bucket'
277
+ filebucket = Puppet::Type.type(:filebucket).new(:name => 'my_bucket')
278
+ catalog.add_resource(filebucket)
279
+
280
+ file.bucket.should == filebucket.bucket
284
281
  end
285
282
  end
286
283
 
287
- describe "when using UNC filenames", :'fails_on_ruby_1.9.2' => true do
284
+ describe "#asuser" do
288
285
  before :each do
289
- pending("UNC file paths not yet supported")
286
+ # Mocha won't let me just stub SUIDManager.asuser to yield and return,
287
+ # but it will do exactly that if we're not root.
288
+ Puppet.features.stubs(:root?).returns false
290
289
  end
291
290
 
292
- it "should autorequire its parent directory" do
293
- file = Puppet::Type::File.new(:path => "//server/foo/bar")
294
- dir = Puppet::Type::File.new(:path => "//server/foo")
295
- @catalog.add_resource file
296
- @catalog.add_resource dir
297
- reqs = file.autorequire
298
- reqs[0].source.must == dir
299
- reqs[0].target.must == file
291
+ it "should return the desired owner if they can write to the parent directory" do
292
+ file[:owner] = 1001
293
+ FileTest.stubs(:writable?).with(File.dirname file[:path]).returns true
294
+
295
+ file.asuser.should == 1001
300
296
  end
301
297
 
302
- it "should autorequire its nearest ancestor directory" do
303
- file = Puppet::Type::File.new(:path => "//server/foo/bar/baz/qux")
304
- dir = Puppet::Type::File.new(:path => "//server/foo/bar")
305
- root = Puppet::Type::File.new(:path => "//server/foo")
306
- @catalog.add_resource file
307
- @catalog.add_resource dir
308
- @catalog.add_resource root
309
- reqs = file.autorequire
310
- reqs.length.must == 1
311
- reqs[0].source.must == dir
312
- reqs[0].target.must == file
298
+ it "should return nil if the desired owner can't write to the parent directory" do
299
+ file[:owner] = 1001
300
+ FileTest.stubs(:writable?).with(File.dirname file[:path]).returns false
301
+
302
+ file.asuser.should == nil
313
303
  end
314
304
 
315
- it "should not autorequire anything when there is no nearest ancestor directory" do
316
- file = Puppet::Type::File.new(:path => "//server/foo/bar/baz/qux")
317
- @catalog.add_resource file
318
- file.autorequire.should be_empty
305
+ it "should return nil if not managing owner" do
306
+ file.asuser.should == nil
319
307
  end
308
+ end
320
309
 
321
- it "should not autorequire its parent dir if its parent dir is itself" do
322
- file = Puppet::Type::File.new(:path => "//server/foo")
323
- @catalog.add_resource file
324
- puts file.autorequire
325
- file.autorequire.should be_empty
310
+ describe "#bucket" do
311
+ it "should return nil if backup is off" do
312
+ file[:backup] = false
313
+ file.bucket.should == nil
326
314
  end
327
315
 
328
- it "should remove trailing slashes" do
329
- file = Puppet::Type::File.new(:path => "//server/foo/bar/baz/")
330
- file[:path].should == "//server/foo/bar/baz"
316
+ it "should return nil if using a file extension for backup" do
317
+ file[:backup] = '.backup'
318
+
319
+ file.bucket.should == nil
331
320
  end
332
321
 
333
- it "should remove double slashes" do
334
- file = Puppet::Type::File.new(:path => "//server/foo/bar//baz")
335
- file[:path].should == "//server/foo/bar/baz"
322
+ it "should return the default filebucket if using the 'puppet' filebucket" do
323
+ file[:backup] = 'puppet'
324
+ bucket = stub('bucket')
325
+ file.stubs(:default_bucket).returns bucket
326
+
327
+ file.bucket.should == bucket
336
328
  end
337
329
 
338
- it "should remove trailing double slashes" do
339
- file = Puppet::Type::File.new(:path => "//server/foo/bar/baz//")
340
- file[:path].should == "//server/foo/bar/baz"
330
+ it "should fail if using a remote filebucket and no catalog exists" do
331
+ file.catalog = nil
332
+ file[:backup] = 'my_bucket'
333
+
334
+ expect { file.bucket }.to raise_error(Puppet::Error, "Can not find filebucket for backups without a catalog")
341
335
  end
342
336
 
343
- it "should remove a trailing slash from a sharename" do
344
- file = Puppet::Type::File.new(:path => "//server/foo/")
345
- file[:path].should == "//server/foo"
337
+ it "should fail if the specified filebucket isn't in the catalog" do
338
+ file[:backup] = 'my_bucket'
339
+
340
+ expect { file.bucket }.to raise_error(Puppet::Error, "Could not find filebucket my_bucket specified in backup")
346
341
  end
347
342
 
348
- it "should not modify a sharename" do
349
- file = Puppet::Type::File.new(:path => "//server/foo")
350
- file[:path].should == "//server/foo"
343
+ it "should use the specified filebucket if it is in the catalog" do
344
+ file[:backup] = 'my_bucket'
345
+ filebucket = Puppet::Type.type(:filebucket).new(:name => 'my_bucket')
346
+ catalog.add_resource(filebucket)
347
+
348
+ file.bucket.should == filebucket.bucket
351
349
  end
352
350
  end
353
351
 
354
- describe "when initializing" do
355
- it "should set a desired 'ensure' value if none is set and 'content' is set" do
356
- file = Puppet::Type::File.new(:name => "/my/file", :content => "/foo/bar")
357
- file[:ensure].should == :file
352
+ describe "#exist?" do
353
+ it "should be considered existent if it can be stat'ed" do
354
+ file.expects(:stat).returns mock('stat')
355
+ file.must be_exist
358
356
  end
359
357
 
360
- it "should set a desired 'ensure' value if none is set and 'target' is set" do
361
- file = Puppet::Type::File.new(:name => "/my/file", :target => "/foo/bar")
362
- file[:ensure].should == :symlink
358
+ it "should be considered nonexistent if it can not be stat'ed" do
359
+ file.expects(:stat).returns nil
360
+ file.must_not be_exist
363
361
  end
364
362
  end
365
363
 
366
- describe "when validating attributes" do
367
- %w{path checksum backup recurse recurselimit source replace force ignore links purge sourceselect}.each do |attr|
368
- it "should have a '#{attr}' parameter" do
369
- Puppet::Type.type(:file).attrtype(attr.intern).should == :param
370
- end
364
+ describe "#eval_generate" do
365
+ before do
366
+ @graph = stub 'graph', :add_edge => nil
367
+ catalog.stubs(:relationship_graph).returns @graph
371
368
  end
372
369
 
373
- %w{content target ensure owner group mode type}.each do |attr|
374
- it "should have a '#{attr}' property" do
375
- Puppet::Type.type(:file).attrtype(attr.intern).should == :property
376
- end
377
- end
370
+ it "should recurse if recursion is enabled" do
371
+ resource = stub('resource', :[] => 'resource')
372
+ file.expects(:recurse).returns [resource]
373
+
374
+ file[:recurse] = true
378
375
 
379
- it "should have its 'path' attribute set as its namevar" do
380
- Puppet::Type.type(:file).key_attributes.should == [:path]
376
+ file.eval_generate.should == [resource]
381
377
  end
382
- end
383
378
 
384
- describe "when managing links" do
385
- require 'tempfile'
379
+ it "should not recurse if recursion is disabled" do
380
+ file.expects(:recurse).never
386
381
 
387
- if @real_posix
388
- describe "on POSIX systems" do
389
- before do
390
- @basedir = tempfile
391
- Dir.mkdir(@basedir)
392
- @file = File.join(@basedir, "file")
393
- @link = File.join(@basedir, "link")
382
+ file[:recurse] = false
394
383
 
395
- File.open(@file, "w", 0644) { |f| f.puts "yayness"; f.flush }
396
- File.symlink(@file, @link)
384
+ file.eval_generate.should == []
385
+ end
386
+ end
397
387
 
398
- @resource = Puppet::Type.type(:file).new(:path => @link, :mode => "755")
399
- @catalog.add_resource @resource
400
- end
388
+ describe "#flush" do
389
+ it "should flush all properties that respond to :flush" do
390
+ file[:source] = File.expand_path(__FILE__)
391
+ file.parameter(:source).expects(:flush)
392
+ file.flush
393
+ end
401
394
 
402
- after do
403
- remove_tmp_files
404
- end
395
+ it "should reset its stat reference" do
396
+ FileUtils.touch(path)
397
+ stat1 = file.stat
405
398
 
406
- it "should default to managing the link" do
407
- @catalog.apply
408
- # I convert them to strings so they display correctly if there's an error.
409
- ("%o" % (File.stat(@file).mode & 007777)).should == "%o" % 0644
410
- end
399
+ file.stat.should equal(stat1)
411
400
 
412
- it "should be able to follow links" do
413
- @resource[:links] = :follow
414
- @catalog.apply
401
+ file.flush
415
402
 
416
- ("%o" % (File.stat(@file).mode & 007777)).should == "%o" % 0755
417
- end
418
- end
419
- else # @real_posix
420
- # should recode tests using expectations instead of using the filesystem
403
+ file.stat.should_not equal(stat1)
421
404
  end
405
+ end
422
406
 
423
- describe "on Microsoft Windows systems" do
424
- before do
425
- Puppet.features.stubs(:posix?).returns(false)
426
- Puppet.features.stubs(:microsoft_windows?).returns(true)
427
- end
407
+ describe "#initialize" do
408
+ it "should remove a trailing slash from the title to create the path" do
409
+ title = File.expand_path("/abc/\n\tdef/")
410
+ file = described_class.new(:title => title)
411
+ file[:path].should == title
412
+ end
428
413
 
429
- it "should refuse to work with links"
414
+ it "should set a desired 'ensure' value if none is set and 'content' is set" do
415
+ file = described_class.new(:path => path, :content => "/foo/bar")
416
+ file[:ensure].should == :file
430
417
  end
431
- end
432
418
 
433
- it "should be able to retrieve a stat instance for the file it is managing" do
434
- Puppet::Type.type(:file).new(:path => "/foo/bar", :source => "/bar/foo").should respond_to(:stat)
419
+ it "should set a desired 'ensure' value if none is set and 'target' is set" do
420
+ file = described_class.new(:path => path, :target => File.expand_path(__FILE__))
421
+ file[:ensure].should == :symlink
422
+ end
435
423
  end
436
424
 
437
- describe "when stat'ing its file" do
438
- before do
439
- @resource = Puppet::Type.type(:file).new(:path => "/foo/bar")
440
- @resource[:links] = :manage # so we always use :lstat
441
- end
425
+ describe "#mark_children_for_purging" do
426
+ it "should set each child's ensure to absent" do
427
+ paths = %w[foo bar baz]
428
+ children = paths.inject({}) do |children,child|
429
+ children.merge child => described_class.new(:path => File.join(path, child), :ensure => :present)
430
+ end
442
431
 
443
- it "should use :stat if it is following links" do
444
- @resource[:links] = :follow
445
- File.expects(:stat)
432
+ file.mark_children_for_purging(children)
446
433
 
447
- @resource.stat
434
+ children.length.should == 3
435
+ children.values.each do |child|
436
+ child[:ensure].should == :absent
437
+ end
448
438
  end
449
439
 
450
- it "should use :lstat if is it not following links" do
451
- @resource[:links] = :manage
452
- File.expects(:lstat)
453
-
454
- @resource.stat
455
- end
440
+ it "should skip children which have a source" do
441
+ child = described_class.new(:path => path, :ensure => :present, :source => File.expand_path(__FILE__))
456
442
 
457
- it "should stat the path of the file" do
458
- File.expects(:lstat).with("/foo/bar")
443
+ file.mark_children_for_purging('foo' => child)
459
444
 
460
- @resource.stat
445
+ child[:ensure].should == :present
461
446
  end
447
+ end
462
448
 
463
- # This only happens in testing.
464
- it "should return nil if the stat does not exist" do
465
- File.expects(:lstat).returns nil
466
-
467
- @resource.stat.should be_nil
449
+ describe "#newchild" do
450
+ it "should create a new resource relative to the parent" do
451
+ child = file.newchild('bar')
452
+
453
+ child.should be_a(described_class)
454
+ child[:path].should == File.join(file[:path], 'bar')
455
+ end
456
+
457
+ {
458
+ :ensure => :present,
459
+ :recurse => true,
460
+ :recurselimit => 5,
461
+ :target => "some_target",
462
+ :source => File.expand_path("some_source"),
463
+ }.each do |param, value|
464
+ it "should omit the #{param} parameter" do
465
+ # Make a new file, because we have to set the param at initialization
466
+ # or it wouldn't be copied regardless.
467
+ file = described_class.new(:path => path, param => value)
468
+ child = file.newchild('bar')
469
+ child[param].should_not == value
470
+ end
468
471
  end
469
472
 
470
- it "should return nil if the file does not exist" do
471
- File.expects(:lstat).raises(Errno::ENOENT)
472
-
473
- @resource.stat.should be_nil
474
- end
473
+ it "should copy all of the parent resource's 'should' values that were set at initialization" do
474
+ parent = described_class.new(:path => path, :owner => 'root', :group => 'wheel')
475
475
 
476
- it "should return nil if the file cannot be stat'ed" do
477
- File.expects(:lstat).raises(Errno::EACCES)
476
+ child = parent.newchild("my/path")
478
477
 
479
- @resource.stat.should be_nil
478
+ child[:owner].should == 'root'
479
+ child[:group].should == 'wheel'
480
480
  end
481
481
 
482
- it "should return the stat instance" do
483
- File.expects(:lstat).returns "mystat"
484
-
485
- @resource.stat.should == "mystat"
482
+ it "should not copy default values to the new child" do
483
+ child = file.newchild("my/path")
484
+ child.original_parameters.should_not include(:backup)
486
485
  end
487
486
 
488
- it "should cache the stat instance if it has a catalog and is applying" do
489
- stat = mock 'stat'
490
- File.expects(:lstat).returns stat
487
+ it "should not copy values to the child which were set by the source" do
488
+ file[:source] = File.expand_path(__FILE__)
489
+ metadata = stub 'metadata', :owner => "root", :group => "root", :mode => 0755, :ftype => "file", :checksum => "{md5}whatever"
490
+ file.parameter(:source).stubs(:metadata).returns metadata
491
491
 
492
- catalog = Puppet::Resource::Catalog.new
493
- @resource.catalog = catalog
492
+ file.parameter(:source).copy_source_values
494
493
 
495
- catalog.stubs(:applying?).returns true
496
-
497
- @resource.stat.should equal(@resource.stat)
494
+ file.class.expects(:new).with { |params| params[:group].nil? }
495
+ file.newchild("my/path")
498
496
  end
499
497
  end
500
498
 
501
- describe "when flushing" do
502
- it "should flush all properties that respond to :flush" do
503
- @resource = Puppet::Type.type(:file).new(:path => "/foo/bar", :source => "/bar/foo")
504
- @resource.parameter(:source).expects(:flush)
505
- @resource.flush
499
+ describe "#purge?" do
500
+ it "should return false if purge is not set" do
501
+ file.must_not be_purge
506
502
  end
507
503
 
508
- it "should reset its stat reference" do
509
- @resource = Puppet::Type.type(:file).new(:path => "/foo/bar")
510
- File.expects(:lstat).times(2).returns("stat1").then.returns("stat2")
511
- @resource.stat.should == "stat1"
512
- @resource.flush
513
- @resource.stat.should == "stat2"
504
+ it "should return true if purge is set to true" do
505
+ file[:purge] = true
506
+
507
+ file.must be_purge
514
508
  end
515
- end
516
509
 
517
- it "should have a method for performing recursion" do
518
- @file.must respond_to(:perform_recursion)
519
- end
510
+ it "should return false if purge is set to false" do
511
+ file[:purge] = false
520
512
 
521
- describe "when executing a recursive search" do
522
- it "should use Metadata to do its recursion" do
523
- Puppet::FileServing::Metadata.indirection.expects(:search)
524
- @file.perform_recursion(@file[:path])
513
+ file.must_not be_purge
525
514
  end
515
+ end
526
516
 
527
- it "should use the provided path as the key to the search" do
528
- Puppet::FileServing::Metadata.indirection.expects(:search).with { |key, options| key == "/foo" }
529
- @file.perform_recursion("/foo")
517
+ describe "#recurse" do
518
+ before do
519
+ file[:recurse] = true
520
+ @metadata = Puppet::FileServing::Metadata
530
521
  end
531
522
 
532
- it "should return the results of the metadata search" do
533
- Puppet::FileServing::Metadata.indirection.expects(:search).returns "foobar"
534
- @file.perform_recursion(@file[:path]).should == "foobar"
523
+ describe "and a source is set" do
524
+ it "should pass the already-discovered resources to recurse_remote" do
525
+ file[:source] = File.expand_path(__FILE__)
526
+ file.stubs(:recurse_local).returns(:foo => "bar")
527
+ file.expects(:recurse_remote).with(:foo => "bar").returns []
528
+ file.recurse
529
+ end
535
530
  end
536
531
 
537
- it "should pass its recursion value to the search" do
538
- @file[:recurse] = true
539
- Puppet::FileServing::Metadata.indirection.expects(:search).with { |key, options| options[:recurse] == true }
540
- @file.perform_recursion(@file[:path])
532
+ describe "and a target is set" do
533
+ it "should use recurse_link" do
534
+ file[:target] = File.expand_path(__FILE__)
535
+ file.stubs(:recurse_local).returns(:foo => "bar")
536
+ file.expects(:recurse_link).with(:foo => "bar").returns []
537
+ file.recurse
538
+ end
541
539
  end
542
540
 
543
- it "should pass true if recursion is remote" do
544
- @file[:recurse] = :remote
545
- Puppet::FileServing::Metadata.indirection.expects(:search).with { |key, options| options[:recurse] == true }
546
- @file.perform_recursion(@file[:path])
541
+ it "should use recurse_local if recurse is not remote" do
542
+ file.expects(:recurse_local).returns({})
543
+ file.recurse
547
544
  end
548
545
 
549
- it "should pass its recursion limit value to the search" do
550
- @file[:recurselimit] = 10
551
- Puppet::FileServing::Metadata.indirection.expects(:search).with { |key, options| options[:recurselimit] == 10 }
552
- @file.perform_recursion(@file[:path])
546
+ it "should not use recurse_local if recurse is remote" do
547
+ file[:recurse] = :remote
548
+ file.expects(:recurse_local).never
549
+ file.recurse
553
550
  end
554
551
 
555
- it "should configure the search to ignore or manage links" do
556
- @file[:links] = :manage
557
- Puppet::FileServing::Metadata.indirection.expects(:search).with { |key, options| options[:links] == :manage }
558
- @file.perform_recursion(@file[:path])
552
+ it "should return the generated resources as an array sorted by file path" do
553
+ one = stub 'one', :[] => "/one"
554
+ two = stub 'two', :[] => "/one/two"
555
+ three = stub 'three', :[] => "/three"
556
+ file.expects(:recurse_local).returns(:one => one, :two => two, :three => three)
557
+ file.recurse.should == [one, two, three]
559
558
  end
560
559
 
561
- it "should pass its 'ignore' setting to the search if it has one" do
562
- @file[:ignore] = %w{.svn CVS}
563
- Puppet::FileServing::Metadata.indirection.expects(:search).with { |key, options| options[:ignore] == %w{.svn CVS} }
564
- @file.perform_recursion(@file[:path])
560
+ describe "and purging is enabled" do
561
+ before do
562
+ file[:purge] = true
563
+ end
564
+
565
+ it "should mark each file for removal" do
566
+ local = described_class.new(:path => path, :ensure => :present)
567
+ file.expects(:recurse_local).returns("local" => local)
568
+
569
+ file.recurse
570
+ local[:ensure].should == :absent
571
+ end
572
+
573
+ it "should not remove files that exist in the remote repository" do
574
+ file[:source] = File.expand_path(__FILE__)
575
+ file.expects(:recurse_local).returns({})
576
+
577
+ remote = described_class.new(:path => path, :source => File.expand_path(__FILE__), :ensure => :present)
578
+
579
+ file.expects(:recurse_remote).with { |hash| hash["remote"] = remote }
580
+
581
+ file.recurse
582
+
583
+ remote[:ensure].should_not == :absent
584
+ end
565
585
  end
566
- end
567
586
 
568
- it "should have a method for performing local recursion" do
569
- @file.must respond_to(:recurse_local)
570
587
  end
571
588
 
572
- describe "when doing local recursion" do
573
- before do
574
- @metadata = stub 'metadata', :relative_path => "my/file"
575
- end
589
+ describe "#remove_less_specific_files" do
590
+ it "should remove any nested files that are already in the catalog" do
591
+ foo = described_class.new :path => File.join(file[:path], 'foo')
592
+ bar = described_class.new :path => File.join(file[:path], 'bar')
593
+ baz = described_class.new :path => File.join(file[:path], 'baz')
576
594
 
577
- it "should pass its path to the :perform_recursion method" do
578
- @file.expects(:perform_recursion).with(@file[:path]).returns [@metadata]
579
- @file.stubs(:newchild)
580
- @file.recurse_local
581
- end
595
+ catalog.add_resource(foo)
596
+ catalog.add_resource(bar)
582
597
 
583
- it "should return an empty hash if the recursion returns nothing" do
584
- @file.expects(:perform_recursion).returns nil
585
- @file.recurse_local.should == {}
598
+ file.remove_less_specific_files([foo, bar, baz]).should == [baz]
586
599
  end
600
+ end
587
601
 
588
- it "should create a new child resource with each generated metadata instance's relative path" do
589
- @file.expects(:perform_recursion).returns [@metadata]
590
- @file.expects(:newchild).with(@metadata.relative_path).returns "fiebar"
591
- @file.recurse_local
592
- end
602
+ describe "#remove_less_specific_files" do
603
+ it "should remove any nested files that are already in the catalog" do
604
+ foo = described_class.new :path => File.join(file[:path], 'foo')
605
+ bar = described_class.new :path => File.join(file[:path], 'bar')
606
+ baz = described_class.new :path => File.join(file[:path], 'baz')
593
607
 
594
- it "should not create a new child resource for the '.' directory" do
595
- @metadata.stubs(:relative_path).returns "."
608
+ catalog.add_resource(foo)
609
+ catalog.add_resource(bar)
596
610
 
597
- @file.expects(:perform_recursion).returns [@metadata]
598
- @file.expects(:newchild).never
599
- @file.recurse_local
611
+ file.remove_less_specific_files([foo, bar, baz]).should == [baz]
600
612
  end
601
613
 
602
- it "should return a hash of the created resources with the relative paths as the hash keys" do
603
- @file.expects(:perform_recursion).returns [@metadata]
604
- @file.expects(:newchild).with("my/file").returns "fiebar"
605
- @file.recurse_local.should == {"my/file" => "fiebar"}
614
+ end
615
+
616
+ describe "#recurse?" do
617
+ it "should be true if recurse is true" do
618
+ file[:recurse] = true
619
+ file.must be_recurse
606
620
  end
607
621
 
608
- it "should set checksum_type to none if this file checksum is none" do
609
- @file[:checksum] = :none
610
- Puppet::FileServing::Metadata.indirection.expects(:search).with { |path,params| params[:checksum_type] == :none }.returns [@metadata]
611
- @file.expects(:newchild).with("my/file").returns "fiebar"
612
- @file.recurse_local
622
+ it "should be true if recurse is remote" do
623
+ file[:recurse] = :remote
624
+ file.must be_recurse
613
625
  end
614
- end
615
626
 
616
- it "should have a method for performing link recursion" do
617
- @file.must respond_to(:recurse_link)
627
+ it "should be false if recurse is false" do
628
+ file[:recurse] = false
629
+ file.must_not be_recurse
630
+ end
618
631
  end
619
632
 
620
- describe "when doing link recursion" do
633
+ describe "#recurse_link" do
621
634
  before do
622
635
  @first = stub 'first', :relative_path => "first", :full_path => "/my/first", :ftype => "directory"
623
636
  @second = stub 'second', :relative_path => "second", :full_path => "/my/second", :ftype => "file"
@@ -626,66 +639,102 @@ describe Puppet::Type.type(:file) do
626
639
  end
627
640
 
628
641
  it "should pass its target to the :perform_recursion method" do
629
- @file[:target] = "mylinks"
630
- @file.expects(:perform_recursion).with("mylinks").returns [@first]
631
- @file.stubs(:newchild).returns @resource
632
- @file.recurse_link({})
642
+ file[:target] = "mylinks"
643
+ file.expects(:perform_recursion).with("mylinks").returns [@first]
644
+ file.stubs(:newchild).returns @resource
645
+ file.recurse_link({})
633
646
  end
634
647
 
635
648
  it "should ignore the recursively-found '.' file and configure the top-level file to create a directory" do
636
649
  @first.stubs(:relative_path).returns "."
637
- @file[:target] = "mylinks"
638
- @file.expects(:perform_recursion).with("mylinks").returns [@first]
639
- @file.stubs(:newchild).never
640
- @file.expects(:[]=).with(:ensure, :directory)
641
- @file.recurse_link({})
650
+ file[:target] = "mylinks"
651
+ file.expects(:perform_recursion).with("mylinks").returns [@first]
652
+ file.stubs(:newchild).never
653
+ file.expects(:[]=).with(:ensure, :directory)
654
+ file.recurse_link({})
642
655
  end
643
656
 
644
657
  it "should create a new child resource for each generated metadata instance's relative path that doesn't already exist in the children hash" do
645
- @file.expects(:perform_recursion).returns [@first, @second]
646
- @file.expects(:newchild).with(@first.relative_path).returns @resource
647
- @file.recurse_link("second" => @resource)
658
+ file.expects(:perform_recursion).returns [@first, @second]
659
+ file.expects(:newchild).with(@first.relative_path).returns @resource
660
+ file.recurse_link("second" => @resource)
648
661
  end
649
662
 
650
663
  it "should not create a new child resource for paths that already exist in the children hash" do
651
- @file.expects(:perform_recursion).returns [@first]
652
- @file.expects(:newchild).never
653
- @file.recurse_link("first" => @resource)
664
+ file.expects(:perform_recursion).returns [@first]
665
+ file.expects(:newchild).never
666
+ file.recurse_link("first" => @resource)
654
667
  end
655
668
 
656
669
  it "should set the target to the full path of discovered file and set :ensure to :link if the file is not a directory" do
657
- file = stub 'file'
658
- file.expects(:[]=).with(:target, "/my/second")
659
- file.expects(:[]=).with(:ensure, :link)
670
+ file.stubs(:perform_recursion).returns [@first, @second]
671
+ file.recurse_link("first" => @resource, "second" => file)
660
672
 
661
- @file.stubs(:perform_recursion).returns [@first, @second]
662
- @file.recurse_link("first" => @resource, "second" => file)
673
+ file[:ensure].should == :link
674
+ file[:target].should == "/my/second"
663
675
  end
664
676
 
665
677
  it "should :ensure to :directory if the file is a directory" do
666
- file = stub 'file'
667
- file.expects(:[]=).with(:ensure, :directory)
678
+ file.stubs(:perform_recursion).returns [@first, @second]
679
+ file.recurse_link("first" => file, "second" => @resource)
680
+
681
+ file[:ensure].should == :directory
682
+ end
683
+
684
+ it "should return a hash with both created and existing resources with the relative paths as the hash keys" do
685
+ file.expects(:perform_recursion).returns [@first, @second]
686
+ file.stubs(:newchild).returns file
687
+ file.recurse_link("second" => @resource).should == {"second" => @resource, "first" => file}
688
+ end
689
+ end
690
+
691
+ describe "#recurse_local" do
692
+ before do
693
+ @metadata = stub 'metadata', :relative_path => "my/file"
694
+ end
695
+
696
+ it "should pass its path to the :perform_recursion method" do
697
+ file.expects(:perform_recursion).with(file[:path]).returns [@metadata]
698
+ file.stubs(:newchild)
699
+ file.recurse_local
700
+ end
701
+
702
+ it "should return an empty hash if the recursion returns nothing" do
703
+ file.expects(:perform_recursion).returns nil
704
+ file.recurse_local.should == {}
705
+ end
706
+
707
+ it "should create a new child resource with each generated metadata instance's relative path" do
708
+ file.expects(:perform_recursion).returns [@metadata]
709
+ file.expects(:newchild).with(@metadata.relative_path).returns "fiebar"
710
+ file.recurse_local
711
+ end
712
+
713
+ it "should not create a new child resource for the '.' directory" do
714
+ @metadata.stubs(:relative_path).returns "."
668
715
 
669
- @file.stubs(:perform_recursion).returns [@first, @second]
670
- @file.recurse_link("first" => file, "second" => @resource)
716
+ file.expects(:perform_recursion).returns [@metadata]
717
+ file.expects(:newchild).never
718
+ file.recurse_local
671
719
  end
672
720
 
673
- it "should return a hash with both created and existing resources with the relative paths as the hash keys" do
674
- file = stub 'file', :[]= => nil
675
-
676
- @file.expects(:perform_recursion).returns [@first, @second]
677
- @file.stubs(:newchild).returns file
678
- @file.recurse_link("second" => @resource).should == {"second" => @resource, "first" => file}
721
+ it "should return a hash of the created resources with the relative paths as the hash keys" do
722
+ file.expects(:perform_recursion).returns [@metadata]
723
+ file.expects(:newchild).with("my/file").returns "fiebar"
724
+ file.recurse_local.should == {"my/file" => "fiebar"}
679
725
  end
680
- end
681
726
 
682
- it "should have a method for performing remote recursion" do
683
- @file.must respond_to(:recurse_remote)
727
+ it "should set checksum_type to none if this file checksum is none" do
728
+ file[:checksum] = :none
729
+ Puppet::FileServing::Metadata.indirection.expects(:search).with { |path,params| params[:checksum_type] == :none }.returns [@metadata]
730
+ file.expects(:newchild).with("my/file").returns "fiebar"
731
+ file.recurse_local
732
+ end
684
733
  end
685
734
 
686
- describe "when doing remote recursion" do
735
+ describe "#recurse_remote" do
687
736
  before do
688
- @file[:source] = "puppet://foo/bar"
737
+ file[:source] = "puppet://foo/bar"
689
738
 
690
739
  @first = Puppet::FileServing::Metadata.new("/my", :relative_path => "first")
691
740
  @second = Puppet::FileServing::Metadata.new("/my", :relative_path => "second")
@@ -698,497 +747,728 @@ describe Puppet::Type.type(:file) do
698
747
 
699
748
  it "should pass its source to the :perform_recursion method" do
700
749
  data = Puppet::FileServing::Metadata.new("/whatever", :relative_path => "foobar")
701
- @file.expects(:perform_recursion).with("puppet://foo/bar").returns [data]
702
- @file.stubs(:newchild).returns @resource
703
- @file.recurse_remote({})
750
+ file.expects(:perform_recursion).with("puppet://foo/bar").returns [data]
751
+ file.stubs(:newchild).returns @resource
752
+ file.recurse_remote({})
704
753
  end
705
754
 
706
755
  it "should not recurse when the remote file is not a directory" do
707
756
  data = Puppet::FileServing::Metadata.new("/whatever", :relative_path => ".")
708
757
  data.stubs(:ftype).returns "file"
709
- @file.expects(:perform_recursion).with("puppet://foo/bar").returns [data]
710
- @file.expects(:newchild).never
711
- @file.recurse_remote({})
758
+ file.expects(:perform_recursion).with("puppet://foo/bar").returns [data]
759
+ file.expects(:newchild).never
760
+ file.recurse_remote({})
712
761
  end
713
762
 
714
763
  it "should set the source of each returned file to the searched-for URI plus the found relative path" do
715
764
  @first.expects(:source=).with File.join("puppet://foo/bar", @first.relative_path)
716
- @file.expects(:perform_recursion).returns [@first]
717
- @file.stubs(:newchild).returns @resource
718
- @file.recurse_remote({})
765
+ file.expects(:perform_recursion).returns [@first]
766
+ file.stubs(:newchild).returns @resource
767
+ file.recurse_remote({})
719
768
  end
720
769
 
721
770
  it "should create a new resource for any relative file paths that do not already have a resource" do
722
- @file.stubs(:perform_recursion).returns [@first]
723
- @file.expects(:newchild).with("first").returns @resource
724
- @file.recurse_remote({}).should == {"first" => @resource}
771
+ file.stubs(:perform_recursion).returns [@first]
772
+ file.expects(:newchild).with("first").returns @resource
773
+ file.recurse_remote({}).should == {"first" => @resource}
725
774
  end
726
775
 
727
776
  it "should not create a new resource for any relative file paths that do already have a resource" do
728
- @file.stubs(:perform_recursion).returns [@first]
729
- @file.expects(:newchild).never
730
- @file.recurse_remote("first" => @resource)
777
+ file.stubs(:perform_recursion).returns [@first]
778
+ file.expects(:newchild).never
779
+ file.recurse_remote("first" => @resource)
731
780
  end
732
781
 
733
782
  it "should set the source of each resource to the source of the metadata" do
734
- @file.stubs(:perform_recursion).returns [@first]
783
+ file.stubs(:perform_recursion).returns [@first]
735
784
  @resource.stubs(:[]=)
736
785
  @resource.expects(:[]=).with(:source, File.join("puppet://foo/bar", @first.relative_path))
737
- @file.recurse_remote("first" => @resource)
786
+ file.recurse_remote("first" => @resource)
738
787
  end
739
788
 
740
789
  # LAK:FIXME This is a bug, but I can't think of a fix for it. Fortunately it's already
741
790
  # filed, and when it's fixed, we'll just fix the whole flow.
742
791
  it "should set the checksum type to :md5 if the remote file is a file" do
743
792
  @first.stubs(:ftype).returns "file"
744
- @file.stubs(:perform_recursion).returns [@first]
793
+ file.stubs(:perform_recursion).returns [@first]
745
794
  @resource.stubs(:[]=)
746
795
  @resource.expects(:[]=).with(:checksum, :md5)
747
- @file.recurse_remote("first" => @resource)
796
+ file.recurse_remote("first" => @resource)
748
797
  end
749
798
 
750
799
  it "should store the metadata in the source property for each resource so the source does not have to requery the metadata" do
751
- @file.stubs(:perform_recursion).returns [@first]
800
+ file.stubs(:perform_recursion).returns [@first]
752
801
  @resource.expects(:parameter).with(:source).returns @parameter
753
802
 
754
803
  @parameter.expects(:metadata=).with(@first)
755
804
 
756
- @file.recurse_remote("first" => @resource)
805
+ file.recurse_remote("first" => @resource)
757
806
  end
758
807
 
759
808
  it "should not create a new resource for the '.' file" do
760
809
  @first.stubs(:relative_path).returns "."
761
- @file.stubs(:perform_recursion).returns [@first]
810
+ file.stubs(:perform_recursion).returns [@first]
762
811
 
763
- @file.expects(:newchild).never
812
+ file.expects(:newchild).never
764
813
 
765
- @file.recurse_remote({})
814
+ file.recurse_remote({})
766
815
  end
767
816
 
768
817
  it "should store the metadata in the main file's source property if the relative path is '.'" do
769
818
  @first.stubs(:relative_path).returns "."
770
- @file.stubs(:perform_recursion).returns [@first]
819
+ file.stubs(:perform_recursion).returns [@first]
771
820
 
772
- @file.parameter(:source).expects(:metadata=).with @first
821
+ file.parameter(:source).expects(:metadata=).with @first
773
822
 
774
- @file.recurse_remote("first" => @resource)
823
+ file.recurse_remote("first" => @resource)
775
824
  end
776
825
 
777
826
  describe "and multiple sources are provided" do
827
+ let(:sources) do
828
+ h = {}
829
+ %w{/one /two /three /four}.each do |key|
830
+ h[key] = URI.unescape(Puppet::Util.path_to_uri(File.expand_path(key)).to_s)
831
+ end
832
+ h
833
+ end
834
+
778
835
  describe "and :sourceselect is set to :first" do
779
836
  it "should create file instances for the results for the first source to return any values" do
780
837
  data = Puppet::FileServing::Metadata.new("/whatever", :relative_path => "foobar")
781
- @file[:source] = %w{/one /two /three /four}
782
- @file.expects(:perform_recursion).with("/one").returns nil
783
- @file.expects(:perform_recursion).with("/two").returns []
784
- @file.expects(:perform_recursion).with("/three").returns [data]
785
- @file.expects(:perform_recursion).with("/four").never
786
- @file.expects(:newchild).with("foobar").returns @resource
787
- @file.recurse_remote({})
838
+ file[:source] = sources.keys.map { |key| File.expand_path(key) }
839
+ file.expects(:perform_recursion).with(sources['/one']).returns nil
840
+ file.expects(:perform_recursion).with(sources['/two']).returns []
841
+ file.expects(:perform_recursion).with(sources['/three']).returns [data]
842
+ file.expects(:perform_recursion).with(sources['/four']).never
843
+ file.expects(:newchild).with("foobar").returns @resource
844
+ file.recurse_remote({})
788
845
  end
789
846
  end
790
847
 
791
848
  describe "and :sourceselect is set to :all" do
792
849
  before do
793
- @file[:sourceselect] = :all
850
+ file[:sourceselect] = :all
794
851
  end
795
852
 
796
853
  it "should return every found file that is not in a previous source" do
797
854
  klass = Puppet::FileServing::Metadata
798
- @file[:source] = %w{/one /two /three /four}
799
- @file.stubs(:newchild).returns @resource
855
+ file[:source] = %w{/one /two /three /four}.map {|f| File.expand_path(f) }
856
+ file.stubs(:newchild).returns @resource
800
857
 
801
858
  one = [klass.new("/one", :relative_path => "a")]
802
- @file.expects(:perform_recursion).with("/one").returns one
803
- @file.expects(:newchild).with("a").returns @resource
859
+ file.expects(:perform_recursion).with(sources['/one']).returns one
860
+ file.expects(:newchild).with("a").returns @resource
804
861
 
805
862
  two = [klass.new("/two", :relative_path => "a"), klass.new("/two", :relative_path => "b")]
806
- @file.expects(:perform_recursion).with("/two").returns two
807
- @file.expects(:newchild).with("b").returns @resource
863
+ file.expects(:perform_recursion).with(sources['/two']).returns two
864
+ file.expects(:newchild).with("b").returns @resource
808
865
 
809
866
  three = [klass.new("/three", :relative_path => "a"), klass.new("/three", :relative_path => "c")]
810
- @file.expects(:perform_recursion).with("/three").returns three
811
- @file.expects(:newchild).with("c").returns @resource
867
+ file.expects(:perform_recursion).with(sources['/three']).returns three
868
+ file.expects(:newchild).with("c").returns @resource
812
869
 
813
- @file.expects(:perform_recursion).with("/four").returns []
870
+ file.expects(:perform_recursion).with(sources['/four']).returns []
814
871
 
815
- @file.recurse_remote({})
872
+ file.recurse_remote({})
816
873
  end
817
874
  end
818
875
  end
819
876
  end
820
877
 
821
- describe "when specifying both source, and content properties" do
822
- before do
823
- @file[:source] = '/one'
824
- @file[:content] = 'file contents'
878
+ describe "#perform_recursion" do
879
+ it "should use Metadata to do its recursion" do
880
+ Puppet::FileServing::Metadata.indirection.expects(:search)
881
+ file.perform_recursion(file[:path])
825
882
  end
826
883
 
827
- it "should raise an exception" do
828
- lambda {@file.validate }.should raise_error(/You cannot specify more than one of/)
884
+ it "should use the provided path as the key to the search" do
885
+ Puppet::FileServing::Metadata.indirection.expects(:search).with { |key, options| key == "/foo" }
886
+ file.perform_recursion("/foo")
829
887
  end
830
- end
831
888
 
832
- describe "when using source" do
833
- before do
834
- @file[:source] = '/one'
889
+ it "should return the results of the metadata search" do
890
+ Puppet::FileServing::Metadata.indirection.expects(:search).returns "foobar"
891
+ file.perform_recursion(file[:path]).should == "foobar"
835
892
  end
836
- Puppet::Type::File::ParameterChecksum.value_collection.values.reject {|v| v == :none}.each do |checksum_type|
837
- describe "with checksum '#{checksum_type}'" do
838
- before do
839
- @file[:checksum] = checksum_type
840
- end
841
893
 
842
- it 'should validate' do
894
+ it "should pass its recursion value to the search" do
895
+ file[:recurse] = true
896
+ Puppet::FileServing::Metadata.indirection.expects(:search).with { |key, options| options[:recurse] == true }
897
+ file.perform_recursion(file[:path])
898
+ end
843
899
 
844
- lambda { @file.validate }.should_not raise_error
845
- end
846
- end
900
+ it "should pass true if recursion is remote" do
901
+ file[:recurse] = :remote
902
+ Puppet::FileServing::Metadata.indirection.expects(:search).with { |key, options| options[:recurse] == true }
903
+ file.perform_recursion(file[:path])
847
904
  end
848
905
 
849
- describe "with checksum 'none'" do
850
- before do
851
- @file[:checksum] = :none
852
- end
906
+ it "should pass its recursion limit value to the search" do
907
+ file[:recurselimit] = 10
908
+ Puppet::FileServing::Metadata.indirection.expects(:search).with { |key, options| options[:recurselimit] == 10 }
909
+ file.perform_recursion(file[:path])
910
+ end
853
911
 
854
- it 'should raise an exception when validating' do
855
- lambda { @file.validate }.should raise_error(/You cannot specify source when using checksum 'none'/)
856
- end
912
+ it "should configure the search to ignore or manage links" do
913
+ file[:links] = :manage
914
+ Puppet::FileServing::Metadata.indirection.expects(:search).with { |key, options| options[:links] == :manage }
915
+ file.perform_recursion(file[:path])
916
+ end
917
+
918
+ it "should pass its 'ignore' setting to the search if it has one" do
919
+ file[:ignore] = %w{.svn CVS}
920
+ Puppet::FileServing::Metadata.indirection.expects(:search).with { |key, options| options[:ignore] == %w{.svn CVS} }
921
+ file.perform_recursion(file[:path])
857
922
  end
858
923
  end
859
924
 
860
- describe "when using content" do
861
- before do
862
- @file[:content] = 'file contents'
925
+ describe "#remove_existing" do
926
+ it "should do nothing if the file doesn't exist" do
927
+ file.remove_existing(:file).should == nil
863
928
  end
864
929
 
865
- (Puppet::Type::File::ParameterChecksum.value_collection.values - SOURCE_ONLY_CHECKSUMS).each do |checksum_type|
866
- describe "with checksum '#{checksum_type}'" do
867
- before do
868
- @file[:checksum] = checksum_type
869
- end
930
+ it "should fail if it can't backup the file" do
931
+ file.stubs(:stat).returns stub('stat')
932
+ file.stubs(:perform_backup).returns false
870
933
 
871
- it 'should validate' do
872
- lambda { @file.validate }.should_not raise_error
873
- end
874
- end
934
+ expect { file.remove_existing(:file) }.to raise_error(Puppet::Error, /Could not back up; will not replace/)
875
935
  end
876
936
 
877
- SOURCE_ONLY_CHECKSUMS.each do |checksum_type|
878
- describe "with checksum '#{checksum_type}'" do
879
- it 'should raise an exception when validating' do
880
- @file[:checksum] = checksum_type
937
+ it "should not do anything if the file is already the right type and not a link" do
938
+ file.stubs(:stat).returns stub('stat', :ftype => 'file')
881
939
 
882
- lambda { @file.validate }.should raise_error(/You cannot specify content when using checksum '#{checksum_type}'/)
883
- end
884
- end
940
+ file.remove_existing(:file).should == nil
941
+ end
942
+
943
+ it "should not remove directories and should not invalidate the stat unless force is set" do
944
+ # Actually call stat to set @needs_stat to nil
945
+ file.stat
946
+ file.stubs(:stat).returns stub('stat', :ftype => 'directory')
947
+
948
+ file.remove_existing(:file)
949
+
950
+ file.instance_variable_get(:@stat).should == nil
951
+ @logs.should be_any {|log| log.level == :notice and log.message =~ /Not removing directory; use 'force' to override/}
952
+ end
953
+
954
+ it "should remove a directory if force is set" do
955
+ file[:force] = true
956
+ file.stubs(:stat).returns stub('stat', :ftype => 'directory')
957
+
958
+ FileUtils.expects(:rmtree).with(file[:path])
959
+
960
+ file.remove_existing(:file).should == true
961
+ end
962
+
963
+ it "should remove an existing file" do
964
+ file.stubs(:perform_backup).returns true
965
+ FileUtils.touch(path)
966
+
967
+ file.remove_existing(:directory).should == true
968
+
969
+ File.exists?(file[:path]).should == false
970
+ end
971
+
972
+ it "should remove an existing link", :unless => Puppet.features.microsoft_windows? do
973
+ file.stubs(:perform_backup).returns true
974
+
975
+ target = tmpfile('link_target')
976
+ FileUtils.touch(target)
977
+ FileUtils.symlink(target, path)
978
+ file[:target] = target
979
+
980
+ file.remove_existing(:directory).should == true
981
+
982
+ File.exists?(file[:path]).should == false
983
+ end
984
+
985
+ it "should fail if the file is not a file, link, or directory" do
986
+ file.stubs(:stat).returns stub('stat', :ftype => 'socket')
987
+
988
+ expect { file.remove_existing(:file) }.to raise_error(Puppet::Error, /Could not back up files of type socket/)
989
+ end
990
+
991
+ it "should invalidate the existing stat of the file" do
992
+ # Actually call stat to set @needs_stat to nil
993
+ file.stat
994
+ file.stubs(:stat).returns stub('stat', :ftype => 'file')
995
+
996
+ File.stubs(:unlink)
997
+
998
+ file.remove_existing(:directory).should == true
999
+ file.instance_variable_get(:@stat).should == :needs_stat
885
1000
  end
886
1001
  end
887
1002
 
888
- describe "when returning resources with :eval_generate" do
889
- before do
890
- @graph = stub 'graph', :add_edge => nil
891
- @catalog.stubs(:relationship_graph).returns @graph
1003
+ describe "#retrieve" do
1004
+ it "should copy the source values if the 'source' parameter is set" do
1005
+ file[:source] = File.expand_path('/foo/bar')
1006
+ file.parameter(:source).expects(:copy_source_values)
1007
+ file.retrieve
1008
+ end
1009
+ end
892
1010
 
893
- @file.catalog = @catalog
894
- @file[:recurse] = true
1011
+ describe "#should_be_file?" do
1012
+ it "should have a method for determining if the file should be a normal file" do
1013
+ file.must respond_to(:should_be_file?)
895
1014
  end
896
1015
 
897
- it "should recurse if recursion is enabled" do
898
- resource = stub('resource', :[] => "resource")
899
- @file.expects(:recurse?).returns true
900
- @file.expects(:recurse).returns [resource]
901
- @file.eval_generate.should == [resource]
1016
+ it "should be a file if :ensure is set to :file" do
1017
+ file[:ensure] = :file
1018
+ file.must be_should_be_file
902
1019
  end
903
1020
 
904
- it "should not recurse if recursion is disabled" do
905
- @file.expects(:recurse?).returns false
906
- @file.expects(:recurse).never
907
- @file.eval_generate.should == []
1021
+ it "should be a file if :ensure is set to :present and the file exists as a normal file" do
1022
+ file.stubs(:stat).returns(mock('stat', :ftype => "file"))
1023
+ file[:ensure] = :present
1024
+ file.must be_should_be_file
1025
+ end
1026
+
1027
+ it "should not be a file if :ensure is set to something other than :file" do
1028
+ file[:ensure] = :directory
1029
+ file.must_not be_should_be_file
1030
+ end
1031
+
1032
+ it "should not be a file if :ensure is set to :present and the file exists but is not a normal file" do
1033
+ file.stubs(:stat).returns(mock('stat', :ftype => "directory"))
1034
+ file[:ensure] = :present
1035
+ file.must_not be_should_be_file
908
1036
  end
909
1037
 
910
- it "should return each resource found through recursion" do
911
- foo = stub 'foo', :[] => "/foo"
912
- bar = stub 'bar', :[] => "/bar"
913
- bar2 = stub 'bar2', :[] => "/bar"
1038
+ it "should be a file if :ensure is not set and :content is" do
1039
+ file[:content] = "foo"
1040
+ file.must be_should_be_file
1041
+ end
914
1042
 
915
- @file.expects(:recurse).returns [foo, bar]
1043
+ it "should be a file if neither :ensure nor :content is set but the file exists as a normal file" do
1044
+ file.stubs(:stat).returns(mock("stat", :ftype => "file"))
1045
+ file.must be_should_be_file
1046
+ end
916
1047
 
917
- @file.eval_generate.should == [foo, bar]
1048
+ it "should not be a file if neither :ensure nor :content is set but the file exists but not as a normal file" do
1049
+ file.stubs(:stat).returns(mock("stat", :ftype => "directory"))
1050
+ file.must_not be_should_be_file
918
1051
  end
919
1052
  end
920
1053
 
921
- describe "when recursing" do
1054
+ describe "#stat", :unless => Puppet.features.microsoft_windows? do
922
1055
  before do
923
- @file[:recurse] = true
924
- @metadata = Puppet::FileServing::Metadata
1056
+ target = tmpfile('link_target')
1057
+ FileUtils.touch(target)
1058
+ FileUtils.symlink(target, path)
1059
+
1060
+ file[:target] = target
1061
+ file[:links] = :manage # so we always use :lstat
925
1062
  end
926
1063
 
927
- describe "and a source is set" do
928
- before { @file[:source] = "/my/source" }
1064
+ it "should stat the target if it is following links" do
1065
+ file[:links] = :follow
929
1066
 
930
- it "should pass the already-discovered resources to recurse_remote" do
931
- @file.stubs(:recurse_local).returns(:foo => "bar")
932
- @file.expects(:recurse_remote).with(:foo => "bar").returns []
933
- @file.recurse
934
- end
1067
+ file.stat.ftype.should == 'file'
935
1068
  end
936
1069
 
937
- describe "and a target is set" do
938
- before { @file[:target] = "/link/target" }
1070
+ it "should stat the link if is it not following links" do
1071
+ file[:links] = :manage
939
1072
 
940
- it "should use recurse_link" do
941
- @file.stubs(:recurse_local).returns(:foo => "bar")
942
- @file.expects(:recurse_link).with(:foo => "bar").returns []
943
- @file.recurse
944
- end
1073
+ file.stat.ftype.should == 'link'
945
1074
  end
946
1075
 
947
- it "should use recurse_local if recurse is not remote" do
948
- @file.expects(:recurse_local).returns({})
949
- @file.recurse
950
- end
1076
+ it "should return nil if the file does not exist" do
1077
+ file[:path] = '/foo/bar/baz/non-existent'
951
1078
 
952
- it "should not use recurse_local if recurse remote" do
953
- @file[:recurse] = :remote
954
- @file.expects(:recurse_local).never
955
- @file.recurse
1079
+ file.stat.should be_nil
956
1080
  end
957
1081
 
958
- it "should return the generated resources as an array sorted by file path" do
959
- one = stub 'one', :[] => "/one"
960
- two = stub 'two', :[] => "/one/two"
961
- three = stub 'three', :[] => "/three"
962
- @file.expects(:recurse_local).returns(:one => one, :two => two, :three => three)
963
- @file.recurse.should == [one, two, three]
1082
+ it "should return nil if the file cannot be stat'ed" do
1083
+ dir = tmpfile('link_test_dir')
1084
+ child = File.join(dir, 'some_file')
1085
+ Dir.mkdir(dir)
1086
+ File.chmod(0, dir)
1087
+
1088
+ file[:path] = child
1089
+
1090
+ file.stat.should be_nil
1091
+
1092
+ # chmod it back so we can clean it up
1093
+ File.chmod(0777, dir)
964
1094
  end
965
1095
 
966
- describe "and purging is enabled" do
967
- before do
968
- @file[:purge] = true
969
- end
1096
+ it "should return the stat instance" do
1097
+ file.stat.should be_a(File::Stat)
1098
+ end
970
1099
 
971
- it "should configure each file to be removed" do
972
- local = stub 'local'
973
- local.stubs(:[]).with(:source).returns nil # Thus, a local file
974
- local.stubs(:[]).with(:path).returns "foo"
975
- @file.expects(:recurse_local).returns("local" => local)
976
- local.expects(:[]=).with(:ensure, :absent)
1100
+ it "should cache the stat instance" do
1101
+ file.stat.should equal(file.stat)
1102
+ end
1103
+ end
977
1104
 
978
- @file.recurse
979
- end
1105
+ describe "#write" do
1106
+ it "should propagate failures encountered when renaming the temporary file" do
1107
+ File.stubs(:open)
1108
+ File.expects(:rename).raises ArgumentError
980
1109
 
981
- it "should not remove files that exist in the remote repository" do
982
- @file["source"] = "/my/file"
983
- @file.expects(:recurse_local).returns({})
1110
+ file[:backup] = 'puppet'
984
1111
 
985
- remote = stub 'remote'
986
- remote.stubs(:[]).with(:source).returns "/whatever" # Thus, a remote file
987
- remote.stubs(:[]).with(:path).returns "foo"
1112
+ file.stubs(:validate_checksum?).returns(false)
988
1113
 
989
- @file.expects(:recurse_remote).with { |hash| hash["remote"] = remote }
990
- remote.expects(:[]=).with(:ensure, :absent).never
1114
+ property = stub('content_property', :actual_content => "something", :length => "something".length)
1115
+ file.stubs(:property).with(:content).returns(property)
991
1116
 
992
- @file.recurse
993
- end
1117
+ lambda { file.write(:content) }.should raise_error(Puppet::Error)
994
1118
  end
995
1119
 
996
- describe "and making a new child resource" do
997
- it "should not copy the parent resource's parent" do
998
- Puppet::Type.type(:file).expects(:new).with { |options| ! options.include?(:parent) }
999
- @file.newchild("my/path")
1000
- end
1120
+ it "should delegate writing to the content property" do
1121
+ filehandle = stub_everything 'fh'
1122
+ File.stubs(:open).yields(filehandle)
1123
+ File.stubs(:rename)
1124
+ property = stub('content_property', :actual_content => "something", :length => "something".length)
1125
+ file[:backup] = 'puppet'
1001
1126
 
1002
- {:recurse => true, :target => "/foo/bar", :ensure => :present, :alias => "yay", :source => "/foo/bar"}.each do |param, value|
1003
- it "should not pass on #{param} to the sub resource" do
1004
- @file = Puppet::Type::File.new(:name => @path, param => value, :catalog => @catalog)
1127
+ file.stubs(:validate_checksum?).returns(false)
1128
+ file.stubs(:property).with(:content).returns(property)
1005
1129
 
1006
- @file.class.expects(:new).with { |params| params[param].nil? }
1130
+ property.expects(:write).with(filehandle)
1007
1131
 
1008
- @file.newchild("sub/file")
1009
- end
1010
- end
1132
+ file.write(:content)
1133
+ end
1011
1134
 
1012
- it "should copy all of the parent resource's 'should' values that were set at initialization" do
1013
- file = @file.class.new(:path => "/foo/bar", :owner => "root", :group => "wheel")
1014
- @catalog.add_resource(file)
1015
- file.class.expects(:new).with { |options| options[:owner] == "root" and options[:group] == "wheel" }
1016
- file.newchild("my/path")
1017
- end
1135
+ describe "when validating the checksum" do
1136
+ before { file.stubs(:validate_checksum?).returns(true) }
1137
+
1138
+ it "should fail if the checksum parameter and content checksums do not match" do
1139
+ checksum = stub('checksum_parameter', :sum => 'checksum_b', :sum_file => 'checksum_b')
1140
+ file.stubs(:parameter).with(:checksum).returns(checksum)
1018
1141
 
1019
- it "should not copy default values to the new child" do
1020
- @file.class.expects(:new).with { |params| params[:backup].nil? }
1021
- @file.newchild("my/path")
1142
+ property = stub('content_property', :actual_content => "something", :length => "something".length, :write => 'checksum_a')
1143
+ file.stubs(:property).with(:content).returns(property)
1144
+
1145
+ lambda { file.write :NOTUSED }.should raise_error(Puppet::Error)
1022
1146
  end
1147
+ end
1148
+
1149
+ describe "when not validating the checksum" do
1150
+ before { file.stubs(:validate_checksum?).returns(false) }
1023
1151
 
1024
- it "should not copy values to the child which were set by the source" do
1025
- @file[:source] = "/foo/bar"
1026
- metadata = stub 'metadata', :owner => "root", :group => "root", :mode => 0755, :ftype => "file", :checksum => "{md5}whatever"
1027
- @file.parameter(:source).stubs(:metadata).returns metadata
1152
+ it "should not fail if the checksum property and content checksums do not match" do
1153
+ checksum = stub('checksum_parameter', :sum => 'checksum_b')
1154
+ file.stubs(:parameter).with(:checksum).returns(checksum)
1028
1155
 
1029
- @file.parameter(:source).copy_source_values
1156
+ property = stub('content_property', :actual_content => "something", :length => "something".length, :write => 'checksum_a')
1157
+ file.stubs(:property).with(:content).returns(property)
1030
1158
 
1031
- @file.class.expects(:new).with { |params| params[:group].nil? }
1032
- @file.newchild("my/path")
1159
+ lambda { file.write :NOTUSED }.should_not raise_error(Puppet::Error)
1033
1160
  end
1034
1161
  end
1035
1162
  end
1036
1163
 
1037
- describe "when setting the backup" do
1038
- it "should default to 'puppet'" do
1039
- Puppet::Type::File.new(:name => "/my/file")[:backup].should == "puppet"
1164
+ describe "#fail_if_checksum_is_wrong" do
1165
+ it "should fail if the checksum of the file doesn't match the expected one" do
1166
+ expect do
1167
+ file.instance_eval do
1168
+ parameter(:checksum).stubs(:sum_file).returns('wrong!!')
1169
+ fail_if_checksum_is_wrong(self[:path], 'anything!')
1170
+ end
1171
+ end.to raise_error(Puppet::Error, /File written to disk did not match checksum/)
1040
1172
  end
1041
1173
 
1042
- it "should allow setting backup to 'false'" do
1043
- (!Puppet::Type::File.new(:name => "/my/file", :backup => false)[:backup]).should be_true
1174
+ it "should not fail if the checksum is correct" do
1175
+ file.instance_eval do
1176
+ parameter(:checksum).stubs(:sum_file).returns('anything!')
1177
+ fail_if_checksum_is_wrong(self[:path], 'anything!').should == nil
1178
+ end
1044
1179
  end
1045
1180
 
1046
- it "should set the backup to '.puppet-bak' if it is set to true" do
1047
- Puppet::Type::File.new(:name => "/my/file", :backup => true)[:backup].should == ".puppet-bak"
1181
+ it "should not fail if the checksum is absent" do
1182
+ file.instance_eval do
1183
+ parameter(:checksum).stubs(:sum_file).returns(nil)
1184
+ fail_if_checksum_is_wrong(self[:path], 'anything!').should == nil
1185
+ end
1048
1186
  end
1187
+ end
1049
1188
 
1050
- it "should support any other backup extension" do
1051
- Puppet::Type::File.new(:name => "/my/file", :backup => ".bak")[:backup].should == ".bak"
1052
- end
1189
+ describe "#write_content" do
1190
+ it "should delegate writing the file to the content property" do
1191
+ io = stub('io')
1192
+ file[:content] = "some content here"
1193
+ file.property(:content).expects(:write).with(io)
1053
1194
 
1054
- it "should set the filebucket when backup is set to a string matching the name of a filebucket in the catalog" do
1055
- catalog = Puppet::Resource::Catalog.new
1056
- bucket_resource = Puppet::Type.type(:filebucket).new :name => "foo", :path => "/my/file/bucket"
1057
- catalog.add_resource bucket_resource
1195
+ file.send(:write_content, io)
1196
+ end
1197
+ end
1058
1198
 
1059
- file = Puppet::Type::File.new(:name => "/my/file")
1060
- catalog.add_resource file
1199
+ describe "#write_temporary_file?" do
1200
+ it "should be true if the file has specified content" do
1201
+ file[:content] = 'some content'
1061
1202
 
1062
- file[:backup] = "foo"
1063
- file.bucket.should == bucket_resource.bucket
1203
+ file.send(:write_temporary_file?).should be_true
1064
1204
  end
1065
1205
 
1066
- it "should find filebuckets added to the catalog after the file resource was created" do
1067
- catalog = Puppet::Resource::Catalog.new
1206
+ it "should be true if the file has specified source" do
1207
+ file[:source] = File.expand_path('/tmp/foo')
1068
1208
 
1069
- file = Puppet::Type::File.new(:name => "/my/file", :backup => "foo")
1070
- catalog.add_resource file
1209
+ file.send(:write_temporary_file?).should be_true
1210
+ end
1071
1211
 
1072
- bucket_resource = Puppet::Type.type(:filebucket).new :name => "foo", :path => "/my/file/bucket"
1073
- catalog.add_resource bucket_resource
1212
+ it "should be false if the file has neither content nor source" do
1213
+ file.send(:write_temporary_file?).should be_false
1214
+ end
1215
+ end
1074
1216
 
1075
- file.bucket.should == bucket_resource.bucket
1217
+ describe "#property_fix" do
1218
+ {
1219
+ :mode => 0777,
1220
+ :owner => 'joeuser',
1221
+ :group => 'joeusers',
1222
+ :seluser => 'seluser',
1223
+ :selrole => 'selrole',
1224
+ :seltype => 'seltype',
1225
+ :selrange => 'selrange'
1226
+ }.each do |name,value|
1227
+ it "should sync the #{name} property if it's not in sync" do
1228
+ file[name] = value
1229
+
1230
+ prop = file.property(name)
1231
+ prop.expects(:retrieve)
1232
+ prop.expects(:safe_insync?).returns false
1233
+ prop.expects(:sync)
1234
+
1235
+ file.send(:property_fix)
1236
+ end
1076
1237
  end
1238
+ end
1077
1239
 
1078
- it "should have a nil filebucket if backup is false" do
1079
- catalog = Puppet::Resource::Catalog.new
1080
- bucket_resource = Puppet::Type.type(:filebucket).new :name => "foo", :path => "/my/file/bucket"
1081
- catalog.add_resource bucket_resource
1240
+ describe "when autorequiring" do
1241
+ describe "directories" do
1242
+ it "should autorequire its parent directory" do
1243
+ dir = described_class.new(:path => File.dirname(path))
1244
+ catalog.add_resource file
1245
+ catalog.add_resource dir
1246
+ reqs = file.autorequire
1247
+ reqs[0].source.must == dir
1248
+ reqs[0].target.must == file
1249
+ end
1250
+
1251
+ it "should autorequire its nearest ancestor directory" do
1252
+ dir = described_class.new(:path => File.dirname(path))
1253
+ grandparent = described_class.new(:path => File.dirname(File.dirname(path)))
1254
+ catalog.add_resource file
1255
+ catalog.add_resource dir
1256
+ catalog.add_resource grandparent
1257
+ reqs = file.autorequire
1258
+ reqs.length.must == 1
1259
+ reqs[0].source.must == dir
1260
+ reqs[0].target.must == file
1261
+ end
1262
+
1263
+ it "should not autorequire anything when there is no nearest ancestor directory" do
1264
+ catalog.add_resource file
1265
+ file.autorequire.should be_empty
1266
+ end
1082
1267
 
1083
- file = Puppet::Type::File.new(:name => "/my/file", :backup => false)
1084
- catalog.add_resource file
1268
+ it "should not autorequire its parent dir if its parent dir is itself" do
1269
+ file[:path] = File.expand_path('/')
1270
+ catalog.add_resource file
1271
+ file.autorequire.should be_empty
1272
+ end
1085
1273
 
1086
- file.bucket.should be_nil
1274
+ describe "on Windows systems", :if => Puppet.features.microsoft_windows? do
1275
+ describe "when using UNC filenames" do
1276
+ it "should autorequire its parent directory" do
1277
+ file[:path] = '//server/foo/bar/baz'
1278
+ dir = described_class.new(:path => "//server/foo/bar")
1279
+ catalog.add_resource file
1280
+ catalog.add_resource dir
1281
+ reqs = file.autorequire
1282
+ reqs[0].source.must == dir
1283
+ reqs[0].target.must == file
1284
+ end
1285
+
1286
+ it "should autorequire its nearest ancestor directory" do
1287
+ file = described_class.new(:path => "//server/foo/bar/baz/qux")
1288
+ dir = described_class.new(:path => "//server/foo/bar/baz")
1289
+ grandparent = described_class.new(:path => "//server/foo/bar")
1290
+ catalog.add_resource file
1291
+ catalog.add_resource dir
1292
+ catalog.add_resource grandparent
1293
+ reqs = file.autorequire
1294
+ reqs.length.must == 1
1295
+ reqs[0].source.must == dir
1296
+ reqs[0].target.must == file
1297
+ end
1298
+
1299
+ it "should not autorequire anything when there is no nearest ancestor directory" do
1300
+ file = described_class.new(:path => "//server/foo/bar/baz/qux")
1301
+ catalog.add_resource file
1302
+ file.autorequire.should be_empty
1303
+ end
1304
+
1305
+ it "should not autorequire its parent dir if its parent dir is itself" do
1306
+ file = described_class.new(:path => "//server/foo")
1307
+ catalog.add_resource file
1308
+ puts file.autorequire
1309
+ file.autorequire.should be_empty
1310
+ end
1311
+ end
1312
+ end
1087
1313
  end
1314
+ end
1315
+
1316
+ describe "when managing links" do
1317
+ require 'tempfile'
1088
1318
 
1089
- it "should have a nil filebucket if backup is set to a string starting with '.'" do
1090
- catalog = Puppet::Resource::Catalog.new
1091
- bucket_resource = Puppet::Type.type(:filebucket).new :name => "foo", :path => "/my/file/bucket"
1092
- catalog.add_resource bucket_resource
1319
+ if @real_posix
1320
+ describe "on POSIX systems" do
1321
+ before do
1322
+ Dir.mkdir(path)
1323
+ @target = File.join(path, "target")
1324
+ @link = File.join(path, "link")
1093
1325
 
1094
- file = Puppet::Type::File.new(:name => "/my/file", :backup => ".foo")
1095
- catalog.add_resource file
1326
+ File.open(@target, "w", 0644) { |f| f.puts "yayness" }
1327
+ File.symlink(@target, @link)
1096
1328
 
1097
- file.bucket.should be_nil
1098
- end
1329
+ file[:path] = @link
1330
+ file[:mode] = 0755
1099
1331
 
1100
- it "should fail if there's no catalog and backup is not false" do
1101
- file = Puppet::Type::File.new(:name => "/my/file", :backup => "foo")
1332
+ catalog.add_resource file
1333
+ end
1334
+
1335
+ it "should default to managing the link" do
1336
+ catalog.apply
1337
+ # I convert them to strings so they display correctly if there's an error.
1338
+ (File.stat(@target).mode & 007777).to_s(8).should == '644'
1339
+ end
1340
+
1341
+ it "should be able to follow links" do
1342
+ file[:links] = :follow
1343
+ catalog.apply
1102
1344
 
1103
- lambda { file.bucket }.should raise_error(Puppet::Error)
1345
+ (File.stat(@target).mode & 007777).to_s(8).should == '755'
1346
+ end
1347
+ end
1348
+ else # @real_posix
1349
+ # should recode tests using expectations instead of using the filesystem
1104
1350
  end
1105
1351
 
1106
- it "should fail if a non-existent catalog is specified" do
1107
- file = Puppet::Type::File.new(:name => "/my/file", :backup => "foo")
1108
- catalog = Puppet::Resource::Catalog.new
1109
- catalog.add_resource file
1352
+ describe "on Microsoft Windows systems" do
1353
+ before do
1354
+ Puppet.features.stubs(:posix?).returns(false)
1355
+ Puppet.features.stubs(:microsoft_windows?).returns(true)
1356
+ end
1110
1357
 
1111
- lambda { file.bucket }.should raise_error(Puppet::Error)
1358
+ it "should refuse to work with links"
1112
1359
  end
1360
+ end
1113
1361
 
1114
- it "should be able to use the default filebucket without a catalog" do
1115
- file = Puppet::Type::File.new(:name => "/my/file", :backup => "puppet")
1116
- file.bucket.should be_instance_of(Puppet::FileBucket::Dipper)
1362
+ describe "when using source" do
1363
+ before do
1364
+ file[:source] = File.expand_path('/one')
1117
1365
  end
1366
+ Puppet::Type::File::ParameterChecksum.value_collection.values.reject {|v| v == :none}.each do |checksum_type|
1367
+ describe "with checksum '#{checksum_type}'" do
1368
+ before do
1369
+ file[:checksum] = checksum_type
1370
+ end
1118
1371
 
1119
- it "should look up the filebucket during finish()" do
1120
- file = Puppet::Type::File.new(:name => "/my/file", :backup => ".foo")
1121
- file.expects(:bucket)
1122
- file.finish
1372
+ it 'should validate' do
1373
+
1374
+ lambda { file.validate }.should_not raise_error
1375
+ end
1376
+ end
1123
1377
  end
1124
- end
1125
1378
 
1126
- describe "when retrieving the current file state" do
1127
- it "should copy the source values if the 'source' parameter is set" do
1128
- file = Puppet::Type::File.new(:name => "/my/file", :source => "/foo/bar")
1129
- file.parameter(:source).expects(:copy_source_values)
1130
- file.retrieve
1379
+ describe "with checksum 'none'" do
1380
+ before do
1381
+ file[:checksum] = :none
1382
+ end
1383
+
1384
+ it 'should raise an exception when validating' do
1385
+ lambda { file.validate }.should raise_error(/You cannot specify source when using checksum 'none'/)
1386
+ end
1131
1387
  end
1132
1388
  end
1133
1389
 
1134
- describe ".title_patterns" do
1390
+ describe "when using content" do
1135
1391
  before do
1136
- @type_class = Puppet::Type.type(:file)
1392
+ file[:content] = 'file contents'
1393
+ end
1394
+
1395
+ (Puppet::Type::File::ParameterChecksum.value_collection.values - SOURCE_ONLY_CHECKSUMS).each do |checksum_type|
1396
+ describe "with checksum '#{checksum_type}'" do
1397
+ before do
1398
+ file[:checksum] = checksum_type
1399
+ end
1400
+
1401
+ it 'should validate' do
1402
+ lambda { file.validate }.should_not raise_error
1403
+ end
1404
+ end
1137
1405
  end
1138
1406
 
1139
- it "should have a regexp that captures the entire string, except for a terminating slash" do
1140
- patterns = @type_class.title_patterns
1141
- string = "abc/\n\tdef/"
1142
- patterns[0][0] =~ string
1143
- $1.should == "abc/\n\tdef"
1407
+ SOURCE_ONLY_CHECKSUMS.each do |checksum_type|
1408
+ describe "with checksum '#{checksum_type}'" do
1409
+ it 'should raise an exception when validating' do
1410
+ file[:checksum] = checksum_type
1411
+
1412
+ lambda { file.validate }.should raise_error(/You cannot specify content when using checksum '#{checksum_type}'/)
1413
+ end
1414
+ end
1144
1415
  end
1145
1416
  end
1146
1417
 
1147
1418
  describe "when auditing" do
1419
+ before :each do
1420
+ # to prevent the catalog from trying to write state.yaml
1421
+ Puppet::Util::Storage.stubs(:store)
1422
+ end
1423
+
1148
1424
  it "should not fail if creating a new file if group is not set" do
1149
- File.exists?(@path).should == false
1150
- file = Puppet::Type::File.new(:name => @path, :audit => "all", :content => "content")
1151
- catalog = Puppet::Resource::Catalog.new
1425
+ file = described_class.new(:path => path, :audit => 'all', :content => 'content')
1152
1426
  catalog.add_resource(file)
1153
1427
 
1154
- Puppet::Util::Storage.stubs(:store) # to prevent the catalog from trying to write state.yaml
1155
- transaction = catalog.apply
1428
+ report = catalog.apply.report
1156
1429
 
1157
- transaction.report.resource_statuses["File[#{@path}]"].failed.should == false
1158
- File.exists?(@path).should == true
1430
+ report.resource_statuses["File[#{path}]"].should_not be_failed
1431
+ File.read(path).should == 'content'
1159
1432
  end
1160
1433
 
1161
1434
  it "should not log errors if creating a new file with ensure present and no content" do
1162
- File.exists?(@path).should == false
1163
- file = Puppet::Type::File.new(:name => @path, :audit => "content", :ensure => "present")
1164
- catalog = Puppet::Resource::Catalog.new
1435
+ file[:audit] = 'content'
1436
+ file[:ensure] = 'present'
1165
1437
  catalog.add_resource(file)
1166
1438
 
1167
- Puppet::Util::Storage.stubs(:store) # to prevent the catalog from trying to write state.yaml
1168
-
1169
1439
  catalog.apply
1170
- @logs.reject {|l| l.level == :notice }.should be_empty
1440
+
1441
+ File.should be_exist(path)
1442
+ @logs.should_not be_any {|l| l.level != :notice }
1171
1443
  end
1172
1444
  end
1173
1445
 
1174
1446
  describe "when specifying both source and checksum" do
1175
1447
  it 'should use the specified checksum when source is first' do
1176
- @file[:source] = '/foo'
1177
- @file[:checksum] = :md5lite
1448
+ file[:source] = File.expand_path('/foo')
1449
+ file[:checksum] = :md5lite
1178
1450
 
1179
- @file[:checksum].should be :md5lite
1451
+ file[:checksum].should == :md5lite
1180
1452
  end
1453
+
1181
1454
  it 'should use the specified checksum when source is last' do
1182
- @file[:checksum] = :md5lite
1183
- @file[:source] = '/foo'
1455
+ file[:checksum] = :md5lite
1456
+ file[:source] = File.expand_path('/foo')
1184
1457
 
1185
- @file[:checksum].should be :md5lite
1458
+ file[:checksum].should == :md5lite
1186
1459
  end
1187
1460
  end
1188
1461
 
1189
- describe ".instances" do
1190
- it 'should return an empty array' do
1191
- Puppet::Type::File.instances.should == []
1462
+ describe "when validating" do
1463
+ [[:source, :target], [:source, :content], [:target, :content]].each do |prop1,prop2|
1464
+ it "should fail if both #{prop1} and #{prop2} are specified" do
1465
+ file[prop1] = prop1 == :source ? File.expand_path("prop1 value") : "prop1 value"
1466
+ file[prop2] = "prop2 value"
1467
+ expect do
1468
+ file.validate
1469
+ end.to raise_error(Puppet::Error, /You cannot specify more than one of/)
1470
+ end
1192
1471
  end
1193
1472
  end
1473
+
1194
1474
  end