chef 17.4.38 → 17.5.22

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/chef.gemspec +2 -0
  3. data/lib/chef/application/base.rb +11 -1
  4. data/lib/chef/client.rb +1 -2
  5. data/lib/chef/compliance/input.rb +115 -0
  6. data/lib/chef/compliance/input_collection.rb +139 -0
  7. data/lib/chef/compliance/profile.rb +122 -0
  8. data/lib/chef/compliance/profile_collection.rb +109 -0
  9. data/lib/chef/compliance/runner.rb +47 -5
  10. data/lib/chef/compliance/waiver.rb +115 -0
  11. data/lib/chef/compliance/waiver_collection.rb +143 -0
  12. data/lib/chef/dsl/compliance.rb +38 -0
  13. data/lib/chef/dsl/reader_helpers.rb +51 -0
  14. data/lib/chef/dsl/recipe.rb +4 -2
  15. data/lib/chef/dsl/secret.rb +2 -4
  16. data/lib/chef/dsl/universal.rb +2 -0
  17. data/lib/chef/event_dispatch/base.rb +44 -2
  18. data/lib/chef/formatters/doc.rb +46 -0
  19. data/lib/chef/http/basic_client.rb +15 -7
  20. data/lib/chef/http.rb +7 -3
  21. data/lib/chef/provider/file.rb +2 -0
  22. data/lib/chef/provider/link.rb +2 -2
  23. data/lib/chef/provider/registry_key.rb +3 -2
  24. data/lib/chef/provider/remote_file/http.rb +1 -1
  25. data/lib/chef/provider/template.rb +1 -1
  26. data/lib/chef/resource/archive_file.rb +17 -14
  27. data/lib/chef/resource/chef_client_scheduled_task.rb +45 -2
  28. data/lib/chef/resource/chocolatey_config.rb +13 -13
  29. data/lib/chef/resource/file/verification/json.rb +50 -0
  30. data/lib/chef/resource/file/verification/yaml.rb +52 -0
  31. data/lib/chef/resource/inspec_input.rb +128 -0
  32. data/lib/chef/resource/inspec_waiver.rb +185 -0
  33. data/lib/chef/resource/mount.rb +1 -1
  34. data/lib/chef/resource/registry_key.rb +36 -48
  35. data/lib/chef/resource/remote_file.rb +98 -2
  36. data/lib/chef/resource/timezone.rb +2 -2
  37. data/lib/chef/resource/user_ulimit.rb +1 -0
  38. data/lib/chef/resource/windows_printer.rb +1 -1
  39. data/lib/chef/resource/windows_uac.rb +3 -1
  40. data/lib/chef/resource/windows_user_privilege.rb +1 -1
  41. data/lib/chef/resources.rb +2 -0
  42. data/lib/chef/run_context/cookbook_compiler.rb +112 -28
  43. data/lib/chef/run_context.rb +31 -1
  44. data/lib/chef/secret_fetcher/akeyless_vault.rb +57 -0
  45. data/lib/chef/secret_fetcher/aws_secrets_manager.rb +1 -1
  46. data/lib/chef/secret_fetcher/azure_key_vault.rb +1 -1
  47. data/lib/chef/secret_fetcher/base.rb +1 -1
  48. data/lib/chef/secret_fetcher/hashi_vault.rb +100 -0
  49. data/lib/chef/secret_fetcher.rb +8 -2
  50. data/lib/chef/version.rb +1 -1
  51. data/spec/data/archive_file/test_archive.tar.gz +0 -0
  52. data/spec/functional/resource/archive_file_spec.rb +87 -0
  53. data/spec/functional/resource/group_spec.rb +5 -1
  54. data/spec/functional/resource/link_spec.rb +8 -0
  55. data/spec/integration/compliance/compliance_spec.rb +60 -0
  56. data/spec/spec_helper.rb +3 -0
  57. data/spec/support/platform_helpers.rb +4 -0
  58. data/spec/support/ruby_installer.rb +51 -0
  59. data/spec/unit/compliance/input_spec.rb +104 -0
  60. data/spec/unit/compliance/profile_spec.rb +120 -0
  61. data/spec/unit/compliance/waiver_spec.rb +104 -0
  62. data/spec/unit/http/basic_client_spec.rb +30 -0
  63. data/spec/unit/http_spec.rb +8 -2
  64. data/spec/unit/provider/link_spec.rb +13 -7
  65. data/spec/unit/provider/remote_file/http_spec.rb +10 -0
  66. data/spec/unit/provider/template_spec.rb +2 -2
  67. data/spec/unit/resource/archive_file_spec.rb +414 -3
  68. data/spec/unit/resource/chef_client_scheduled_task_spec.rb +69 -0
  69. data/spec/unit/resource/file/verification/json_spec.rb +72 -0
  70. data/spec/unit/resource/file/verification/yaml_spec.rb +67 -0
  71. data/spec/unit/resource/inspec_input_spec.rb +300 -0
  72. data/spec/unit/resource/inspec_waiver_spec.rb +312 -0
  73. data/spec/unit/resource/mount_spec.rb +10 -0
  74. data/spec/unit/resource/user_ulimit_spec.rb +14 -1
  75. data/spec/unit/secret_fetcher/akeyless_vault_spec.rb +37 -0
  76. data/spec/unit/secret_fetcher/hashi_vault_spec.rb +80 -0
  77. data/tasks/rspec.rb +2 -1
  78. metadata +60 -6
@@ -17,19 +17,60 @@
17
17
 
18
18
  require "spec_helper"
19
19
 
20
- describe Chef::Resource::ArchiveFile do
20
+ begin
21
+ require "ffi-libarchive"
22
+ rescue LoadError
23
+ module Archive
24
+ class Reader
25
+ def close; end
26
+ def each_entry; end
27
+ def extract(entry, flags = 0, destination: nil); end
28
+ end
29
+ end
30
+ end
31
+
32
+ # Exclude this test on platforms where ffi-libarchive loading is broken
33
+ describe Chef::Resource::ArchiveFile, :libarchive_loading_broken do
21
34
  let(:node) { Chef::Node.new }
22
35
  let(:events) { Chef::EventDispatch::Dispatcher.new }
23
36
  let(:run_context) { Chef::RunContext.new(node, {}, events) }
24
- let(:resource) { Chef::Resource::ArchiveFile.new("foo", run_context) }
37
+ let(:destination) { Dir.mktmpdir }
38
+ let(:path) { File.expand_path("/tmp/foo.zip") }
39
+ let(:resource) do
40
+ r = Chef::Resource::ArchiveFile.new(path, run_context)
41
+ r.destination = destination
42
+ r
43
+ end
25
44
  let(:provider) { resource.provider_for_action(:extract) }
45
+ let(:entry_time) { Time.new(2021, 5, 25, 2, 2, 0, "-05:00") }
46
+ let(:older_time) { entry_time - 100 }
47
+ let(:newer_time) { entry_time + 100 }
48
+
49
+ let(:archive_reader) { instance_double("Archive::Reader", close: nil) }
50
+ let(:archive_entry_1) { instance_double("Archive::Entry", pathname: "folder-1/", mtime: entry_time) }
51
+ let(:archive_entry_2) { instance_double("Archive::Entry", pathname: "folder-1/file-1.txt", mtime: entry_time) }
52
+ let(:archive_entry_3) { instance_double("Archive::Entry", pathname: "folder-1/folder-2/", mtime: entry_time) }
53
+ let(:archive_entry_4) { instance_double("Archive::Entry", pathname: "folder-1/folder-2/file-2.txt", mtime: entry_time) }
54
+
55
+ let(:archive_reader_with_strip_components_1) { instance_double("Archive::Reader", close: nil) }
56
+ let(:archive_entry_2_s1) { instance_double("Archive::Entry", pathname: "file-1.txt", mtime: entry_time) }
57
+ let(:archive_entry_3_s1) { instance_double("Archive::Entry", pathname: "folder-2/", mtime: entry_time) }
58
+ let(:archive_entry_4_s1) { instance_double("Archive::Entry", pathname: "folder-2/file-2.txt", mtime: entry_time) }
59
+
60
+ let(:archive_reader_with_strip_components_2) { instance_double("Archive::Reader", close: nil) }
61
+ let(:archive_entry_4_s2) { instance_double("Archive::Entry", pathname: "file-2.txt", mtime: entry_time) }
62
+
63
+ before do
64
+ allow(resource).to receive(:provider_for_action).with(:extract).and_return(provider)
65
+ end
26
66
 
27
67
  it "has a resource name of :archive_file" do
28
68
  expect(resource.resource_name).to eql(:archive_file)
29
69
  end
30
70
 
31
71
  it "has a name property of path" do
32
- expect(resource.path).to match(/.*foo$/)
72
+ r = Chef::Resource::ArchiveFile.new("my-name", run_context)
73
+ expect(r.path).to match("my-name")
33
74
  end
34
75
 
35
76
  it "sets the default action as :extract" do
@@ -44,6 +85,376 @@ describe Chef::Resource::ArchiveFile do
44
85
  expect(resource.mode).to eql("755")
45
86
  end
46
87
 
88
+ it "strip_components property defaults to 0" do
89
+ expect(resource.strip_components).to eql(0)
90
+ end
91
+
92
+ describe "#action_extract" do
93
+ before do
94
+ allow(FileUtils).to receive(:mkdir_p)
95
+ allow(File).to receive(:exist?).and_call_original
96
+ allow(File).to receive(:exist?).with(path).and_return(true)
97
+ allow(File).to receive(:exist?).with(destination).and_return(true)
98
+
99
+ allow(Archive::Reader).to receive(:open_filename).with(path, nil, strip_components: 0).and_return(archive_reader)
100
+ allow(archive_reader).to receive(:each_entry)
101
+ .and_yield(archive_entry_1)
102
+ .and_yield(archive_entry_2)
103
+ .and_yield(archive_entry_3)
104
+ .and_yield(archive_entry_4)
105
+ allow(archive_reader).to receive(:extract).with(archive_entry_1, any_args)
106
+ allow(archive_reader).to receive(:extract).with(archive_entry_2, any_args)
107
+ allow(archive_reader).to receive(:extract).with(archive_entry_3, any_args)
108
+ allow(archive_reader).to receive(:extract).with(archive_entry_4, any_args)
109
+
110
+ allow(Archive::Reader).to receive(:open_filename).with(path, nil, strip_components: 1).and_return(archive_reader_with_strip_components_1)
111
+ allow(archive_reader_with_strip_components_1).to receive(:each_entry)
112
+ .and_yield(archive_entry_2_s1)
113
+ .and_yield(archive_entry_3_s1)
114
+ .and_yield(archive_entry_4_s1)
115
+ allow(archive_reader_with_strip_components_1).to receive(:extract).with(archive_entry_2_s1, any_args)
116
+ allow(archive_reader_with_strip_components_1).to receive(:extract).with(archive_entry_3_s1, any_args)
117
+ allow(archive_reader_with_strip_components_1).to receive(:extract).with(archive_entry_4_s1, any_args)
118
+
119
+ allow(Archive::Reader).to receive(:open_filename).with(path, nil, strip_components: 2).and_return(archive_reader_with_strip_components_2)
120
+ allow(archive_reader_with_strip_components_2).to receive(:each_entry)
121
+ .and_yield(archive_entry_4_s2)
122
+ allow(archive_reader_with_strip_components_2).to receive(:extract).with(archive_entry_4_s2, any_args)
123
+
124
+ allow(File).to receive(:exist?).with("#{destination}/folder-1").and_return(true)
125
+ allow(File).to receive(:exist?).with("#{destination}/folder-1/file-1.txt").and_return(true)
126
+ allow(File).to receive(:exist?).with("#{destination}/folder-1/folder-2").and_return(true)
127
+ allow(File).to receive(:exist?).with("#{destination}/folder-1/folder-2/file-2.txt").and_return(true)
128
+
129
+ allow(File).to receive(:mtime).with("#{destination}/folder-1").and_return(entry_time)
130
+ allow(File).to receive(:mtime).with("#{destination}/folder-1/file-1.txt").and_return(entry_time)
131
+ allow(File).to receive(:mtime).with("#{destination}/folder-1/folder-2").and_return(entry_time)
132
+ allow(File).to receive(:mtime).with("#{destination}/folder-1/folder-2/file-2.txt").and_return(entry_time)
133
+
134
+ resource.overwrite(true) # Force it to converge
135
+ end
136
+
137
+ context "when destination directory does not exist" do
138
+ before do
139
+ allow(File).to receive(:exist?).with(destination).and_return(false)
140
+ end
141
+
142
+ it "creates destination directory" do
143
+ expect(FileUtils).to receive(:mkdir_p).with(destination, { mode: 493 })
144
+ resource.run_action(:extract)
145
+ end
146
+ end
147
+
148
+ context "when destination directory exists" do
149
+ before do
150
+ allow(File).to receive(:exist?).with(destination).and_return(true)
151
+ end
152
+
153
+ it "does not create destination directory" do
154
+ expect(FileUtils).not_to receive(:mkdir_p)
155
+ resource.run_action(:extract)
156
+ end
157
+
158
+ context "when overwrite is set to false" do
159
+ before do
160
+ resource.overwrite(false)
161
+ end
162
+
163
+ context "when files on disk have identical modified times than what is in the archive" do
164
+ before do
165
+ allow(File).to receive(:mtime).with("#{destination}/folder-1").and_return(entry_time)
166
+ allow(File).to receive(:mtime).with("#{destination}/folder-1/file-1.txt").and_return(entry_time)
167
+ allow(File).to receive(:mtime).with("#{destination}/folder-1/folder-2").and_return(entry_time)
168
+ allow(File).to receive(:mtime).with("#{destination}/folder-1/folder-2/file-2.txt").and_return(entry_time)
169
+ end
170
+
171
+ it "does not extract archive" do
172
+ expect(provider).not_to receive(:extract)
173
+ resource.run_action(:extract)
174
+ end
175
+ end
176
+
177
+ context "when files on disk have newer modified times than what is in the archive" do
178
+ before do
179
+ allow(File).to receive(:mtime).with("#{destination}/folder-1").and_return(newer_time)
180
+ allow(File).to receive(:mtime).with("#{destination}/folder-1/file-1.txt").and_return(newer_time)
181
+ allow(File).to receive(:mtime).with("#{destination}/folder-1/folder-2").and_return(newer_time)
182
+ allow(File).to receive(:mtime).with("#{destination}/folder-1/folder-2/file-2.txt").and_return(newer_time)
183
+ end
184
+
185
+ it "does not extract archive" do
186
+ expect(provider).not_to receive(:extract)
187
+ resource.run_action(:extract)
188
+ end
189
+ end
190
+
191
+ context "when files on disk have older modified times than what is in the archive" do
192
+ before do
193
+ allow(File).to receive(:mtime).with("#{destination}/folder-1").and_return(older_time)
194
+ allow(File).to receive(:mtime).with("#{destination}/folder-1/file-1.txt").and_return(older_time)
195
+ allow(File).to receive(:mtime).with("#{destination}/folder-1/folder-2").and_return(older_time)
196
+ allow(File).to receive(:mtime).with("#{destination}/folder-1/folder-2/file-2.txt").and_return(older_time)
197
+ end
198
+
199
+ it "does not extract archive" do
200
+ expect(provider).not_to receive(:extract)
201
+ resource.run_action(:extract)
202
+ end
203
+ end
204
+ end
205
+
206
+ context "when overwrite is set to true" do
207
+ before do
208
+ resource.overwrite(true)
209
+ end
210
+
211
+ context "when files on disk have identical modified times than what is in the archive" do
212
+ before do
213
+ allow(File).to receive(:mtime).with("#{destination}/folder-1").and_return(entry_time)
214
+ allow(File).to receive(:mtime).with("#{destination}/folder-1/file-1.txt").and_return(entry_time)
215
+ allow(File).to receive(:mtime).with("#{destination}/folder-1/folder-2").and_return(entry_time)
216
+ allow(File).to receive(:mtime).with("#{destination}/folder-1/folder-2/file-2.txt").and_return(entry_time)
217
+ end
218
+
219
+ it "extracts archive" do
220
+ expect(provider).to receive(:extract)
221
+ resource.run_action(:extract)
222
+ end
223
+ end
224
+
225
+ context "when files on disk have newer modified times than what is in the archive" do
226
+ before do
227
+ allow(File).to receive(:mtime).with("#{destination}/folder-1").and_return(newer_time)
228
+ allow(File).to receive(:mtime).with("#{destination}/folder-1/file-1.txt").and_return(newer_time)
229
+ allow(File).to receive(:mtime).with("#{destination}/folder-1/folder-2").and_return(newer_time)
230
+ allow(File).to receive(:mtime).with("#{destination}/folder-1/folder-2/file-2.txt").and_return(newer_time)
231
+ end
232
+
233
+ it "extracts archive" do
234
+ expect(provider).to receive(:extract)
235
+ resource.run_action(:extract)
236
+ end
237
+ end
238
+
239
+ context "when files on disk have older modified times than what is in the archive" do
240
+ before do
241
+ allow(File).to receive(:mtime).with("#{destination}/folder-1").and_return(older_time)
242
+ allow(File).to receive(:mtime).with("#{destination}/folder-1/file-1.txt").and_return(older_time)
243
+ allow(File).to receive(:mtime).with("#{destination}/folder-1/folder-2").and_return(older_time)
244
+ allow(File).to receive(:mtime).with("#{destination}/folder-1/folder-2/file-2.txt").and_return(older_time)
245
+ end
246
+
247
+ it "extracts archive" do
248
+ expect(provider).to receive(:extract)
249
+ resource.run_action(:extract)
250
+ end
251
+ end
252
+ end
253
+
254
+ context "when overwrite is set to :auto" do
255
+ before do
256
+ resource.overwrite(:auto)
257
+ end
258
+
259
+ context "when strip_components is set to 0" do
260
+ before do
261
+ resource.strip_components(0)
262
+ end
263
+
264
+ context "when files on disk have identical modified times than what is in the archive" do
265
+ before do
266
+ allow(File).to receive(:mtime).with("#{destination}/folder-1").and_return(entry_time)
267
+ allow(File).to receive(:mtime).with("#{destination}/folder-1/file-1.txt").and_return(entry_time)
268
+ allow(File).to receive(:mtime).with("#{destination}/folder-1/folder-2").and_return(entry_time)
269
+ allow(File).to receive(:mtime).with("#{destination}/folder-1/folder-2/file-2.txt").and_return(entry_time)
270
+ end
271
+
272
+ context "when there is at least one missing files on disk" do
273
+ before do
274
+ expect(File).to receive(:exist?).with("#{destination}/folder-1").and_return(false)
275
+ expect(File).to receive(:exist?).with("#{destination}/folder-1/file-1.txt").and_return(true)
276
+ expect(File).to receive(:exist?).with("#{destination}/folder-1/folder-2").and_return(true)
277
+ expect(File).to receive(:exist?).with("#{destination}/folder-1/folder-2/file-2.txt").and_return(true)
278
+ end
279
+
280
+ it "extracts archive" do
281
+ expect(provider).to receive(:extract)
282
+ resource.run_action(:extract)
283
+ end
284
+ end
285
+
286
+ context "when there are no missing files on disk" do
287
+ before do
288
+ expect(File).to receive(:exist?).with("#{destination}/folder-1").and_return(true)
289
+ expect(File).to receive(:exist?).with("#{destination}/folder-1/file-1.txt").and_return(true)
290
+ expect(File).to receive(:exist?).with("#{destination}/folder-1/folder-2").and_return(true)
291
+ expect(File).to receive(:exist?).with("#{destination}/folder-1/folder-2/file-2.txt").and_return(true)
292
+ end
293
+
294
+ it "does not extract archive" do
295
+ expect(provider).not_to receive(:extract)
296
+ resource.run_action(:extract)
297
+ end
298
+ end
299
+ end
300
+ end
301
+
302
+ context "when strip_components is set to 1" do
303
+ before do
304
+ resource.strip_components(1)
305
+ end
306
+
307
+ context "when files on disk have identical modified times than what is in the archive" do
308
+ before do
309
+ allow(File).to receive(:mtime).with("#{destination}/file-1.txt").and_return(entry_time)
310
+ allow(File).to receive(:mtime).with("#{destination}/folder-2").and_return(entry_time)
311
+ allow(File).to receive(:mtime).with("#{destination}/folder-2/file-2.txt").and_return(entry_time)
312
+ end
313
+
314
+ context "when there is at least one missing files on disk" do
315
+ before do
316
+ expect(File).not_to receive(:exist?).with("#{destination}/folder-1")
317
+ expect(File).not_to receive(:exist?).with("#{destination}/folder-1/file-1.txt")
318
+ expect(File).not_to receive(:exist?).with("#{destination}/folder-1/folder-2")
319
+ expect(File).not_to receive(:exist?).with("#{destination}/folder-1/folder-2/file-2.txt")
320
+ expect(File).to receive(:exist?).with("#{destination}/file-1.txt").and_return(false)
321
+ expect(File).to receive(:exist?).with("#{destination}/folder-2").and_return(true)
322
+ expect(File).to receive(:exist?).with("#{destination}/folder-2/file-2.txt").and_return(true)
323
+ end
324
+
325
+ it "extracts archive" do
326
+ expect(provider).to receive(:extract)
327
+ resource.run_action(:extract)
328
+ end
329
+ end
330
+
331
+ context "when there are no missing files on disk" do
332
+ before do
333
+ expect(File).not_to receive(:exist?).with("#{destination}/folder-1")
334
+ expect(File).not_to receive(:exist?).with("#{destination}/folder-1/file-1.txt")
335
+ expect(File).not_to receive(:exist?).with("#{destination}/folder-1/folder-2")
336
+ expect(File).not_to receive(:exist?).with("#{destination}/folder-1/folder-2/file-2.txt")
337
+ expect(File).to receive(:exist?).with("#{destination}/file-1.txt").and_return(true)
338
+ expect(File).to receive(:exist?).with("#{destination}/folder-2").and_return(true)
339
+ expect(File).to receive(:exist?).with("#{destination}/folder-2/file-2.txt").and_return(true)
340
+ end
341
+
342
+ it "does not extract archive" do
343
+ expect(provider).not_to receive(:extract)
344
+ resource.run_action(:extract)
345
+ end
346
+ end
347
+ end
348
+ end
349
+
350
+ context "when files on disk have newer modified times than what is in the archive" do
351
+ before do
352
+ allow(File).to receive(:mtime).with("#{destination}/folder-1").and_return(newer_time)
353
+ allow(File).to receive(:mtime).with("#{destination}/folder-1/file-1.txt").and_return(newer_time)
354
+ allow(File).to receive(:mtime).with("#{destination}/folder-1/folder-2").and_return(newer_time)
355
+ allow(File).to receive(:mtime).with("#{destination}/folder-1/folder-2/file-2.txt").and_return(newer_time)
356
+ end
357
+
358
+ it "extracts archive" do
359
+ expect(provider).to receive(:extract)
360
+ resource.run_action(:extract)
361
+ end
362
+ end
363
+
364
+ context "when files on disk have older modified times than what is in the archive" do
365
+ before do
366
+ allow(File).to receive(:mtime).with("#{destination}/folder-1").and_return(older_time)
367
+ allow(File).to receive(:mtime).with("#{destination}/folder-1/file-1.txt").and_return(older_time)
368
+ allow(File).to receive(:mtime).with("#{destination}/folder-1/folder-2").and_return(older_time)
369
+ allow(File).to receive(:mtime).with("#{destination}/folder-1/folder-2/file-2.txt").and_return(older_time)
370
+ end
371
+
372
+ it "extracts archive" do
373
+ expect(provider).to receive(:extract)
374
+ resource.run_action(:extract)
375
+ end
376
+ end
377
+ end
378
+ end
379
+
380
+ context "when strip_components is set to 0" do
381
+ before do
382
+ resource.strip_components(0)
383
+ end
384
+
385
+ it "does not strip any paths" do
386
+ expect(archive_reader).to receive(:extract).with(archive_entry_1, 4)
387
+ expect(archive_reader).to receive(:extract).with(archive_entry_2, 4)
388
+ expect(archive_reader).to receive(:extract).with(archive_entry_3, 4)
389
+ expect(archive_reader).to receive(:extract).with(archive_entry_4, 4)
390
+ resource.run_action(:extract)
391
+ end
392
+ end
393
+
394
+ context "when strip_components is set to 1" do
395
+ before do
396
+ resource.strip_components(1)
397
+ end
398
+
399
+ it "strips leading number of paths specified in strip_components" do
400
+ expect(archive_reader_with_strip_components_1).to receive(:extract).with(archive_entry_2_s1, 4)
401
+ expect(archive_reader_with_strip_components_1).to receive(:extract).with(archive_entry_3_s1, 4)
402
+ expect(archive_reader_with_strip_components_1).to receive(:extract).with(archive_entry_4_s1, 4)
403
+ resource.run_action(:extract)
404
+ end
405
+ end
406
+
407
+ context "when strip_components is set to 2" do
408
+ before do
409
+ resource.strip_components(2)
410
+ end
411
+
412
+ it "strips leading number of paths specified in strip_components" do
413
+ expect(archive_reader_with_strip_components_2).to receive(:extract).with(archive_entry_4_s2, 4)
414
+ resource.run_action(:extract)
415
+ end
416
+ end
417
+
418
+ context "when owner property is set" do
419
+ before { resource.owner "root" }
420
+
421
+ it "chowns all archive file/directory paths" do
422
+ expect(FileUtils).to receive(:chown).with("root", nil, "#{destination}/folder-1/")
423
+ expect(FileUtils).to receive(:chown).with("root", nil, "#{destination}/folder-1/file-1.txt")
424
+ expect(FileUtils).to receive(:chown).with("root", nil, "#{destination}/folder-1/folder-2/")
425
+ expect(FileUtils).to receive(:chown).with("root", nil, "#{destination}/folder-1/folder-2/file-2.txt")
426
+ resource.run_action(:extract)
427
+ end
428
+ end
429
+
430
+ context "when group property is set" do
431
+ before { resource.group "root" }
432
+
433
+ it "chowns all archive file/directory paths" do
434
+ expect(FileUtils).to receive(:chown).with(nil, "root", "#{destination}/folder-1/")
435
+ expect(FileUtils).to receive(:chown).with(nil, "root", "#{destination}/folder-1/file-1.txt")
436
+ expect(FileUtils).to receive(:chown).with(nil, "root", "#{destination}/folder-1/folder-2/")
437
+ expect(FileUtils).to receive(:chown).with(nil, "root", "#{destination}/folder-1/folder-2/file-2.txt")
438
+ resource.run_action(:extract)
439
+ end
440
+ end
441
+
442
+ context "when owner and group properties are set" do
443
+ before do
444
+ resource.owner "root"
445
+ resource.group "root"
446
+ end
447
+
448
+ it "chowns all archive file/directory paths" do
449
+ expect(FileUtils).to receive(:chown).with("root", "root", "#{destination}/folder-1/")
450
+ expect(FileUtils).to receive(:chown).with("root", "root", "#{destination}/folder-1/file-1.txt")
451
+ expect(FileUtils).to receive(:chown).with("root", "root", "#{destination}/folder-1/folder-2/")
452
+ expect(FileUtils).to receive(:chown).with("root", "root", "#{destination}/folder-1/folder-2/file-2.txt")
453
+ resource.run_action(:extract)
454
+ end
455
+ end
456
+ end
457
+
47
458
  it "mode property throws a deprecation warning if Integers are passed" do
48
459
  expect(Chef::Log).to receive(:deprecation)
49
460
  resource.mode 755
@@ -25,6 +25,11 @@ describe Chef::Resource::ChefClientScheduledTask do
25
25
  let(:resource) { Chef::Resource::ChefClientScheduledTask.new("fakey_fakerton", run_context) }
26
26
  let(:provider) { resource.provider_for_action(:add) }
27
27
 
28
+ before do
29
+ allow(ENV).to receive(:[]).and_call_original
30
+ allow(ENV).to receive(:[]).with("COMSPEC").and_return("C:\\Windows\\System32\\cmd.exe")
31
+ end
32
+
28
33
  it "sets the default action as :add" do
29
34
  expect(resource.action).to eql([:add])
30
35
  end
@@ -73,11 +78,75 @@ describe Chef::Resource::ChefClientScheduledTask do
73
78
  expect(resource.chef_binary_path).to eql("C:/opscode/chef/bin/chef-client")
74
79
  end
75
80
 
81
+ context "priority" do
82
+ it "default value is 7" do
83
+ expect(resource.priority).to eq(7)
84
+ end
85
+
86
+ it "raise error when priority value less than 0" do
87
+ expect { resource.priority(-1) }.to raise_error(Chef::Exceptions::ValidationFailed, "Option priority's value -1 should be in range of 0 to 10!")
88
+ end
89
+
90
+ it "raise error when priority values is greater than 10" do
91
+ expect { resource.priority 11 }.to raise_error(Chef::Exceptions::ValidationFailed, "Option priority's value 11 should be in range of 0 to 10!")
92
+ end
93
+ end
94
+
76
95
  it "supports :add and :remove actions" do
77
96
  expect { resource.action :add }.not_to raise_error
78
97
  expect { resource.action :remove }.not_to raise_error
79
98
  end
80
99
 
100
+ it "expects use_consistent_splay to be true when set" do
101
+ resource.use_consistent_splay = true
102
+ expect(resource.use_consistent_splay).to eql(true)
103
+ end
104
+
105
+ context "when configured to use a consistent splay" do
106
+ before do
107
+ node.automatic_attrs[:shard_seed] = nil
108
+ allow(node).to receive(:name).and_return("test_node")
109
+ resource.config_directory = "C:/chef" # Allows local unit testing on nix flavors
110
+ resource.use_consistent_splay = true
111
+ end
112
+
113
+ it "sleeps the same amount each time based on splay before running the task" do
114
+ expect(provider.full_command).to eql("C:\\Windows\\System32\\cmd.exe /c \"C:/windows/system32/windowspowershell/v1.0/powershell.exe Start-Sleep -s 272 && C:/opscode/chef/bin/chef-client -L C:/chef/log/client.log -c C:/chef/client.rb\"")
115
+ end
116
+ end
117
+
118
+ describe "#consistent_splay_command" do
119
+ context "when use_consistent_splay is false" do
120
+ it "returns nil" do
121
+ expect(provider.consistent_splay_command).to eql(nil)
122
+ end
123
+ end
124
+
125
+ context "when use_consistent_splay is true" do
126
+ before do
127
+ resource.use_consistent_splay true
128
+ allow(provider).to receive(:splay_sleep_time).and_return(222)
129
+ end
130
+
131
+ it "returns a powershell sleep command to be appended to the chef client run command" do
132
+ expect(provider.consistent_splay_command).to eql("C:/windows/system32/windowspowershell/v1.0/powershell.exe Start-Sleep -s 222 && ")
133
+ end
134
+ end
135
+ end
136
+
137
+ describe "#splay_sleep_time" do
138
+ it "uses shard_seed attribute if present" do
139
+ node.automatic_attrs[:shard_seed] = "73399073"
140
+ expect(provider.splay_sleep_time(300)).to satisfy { |v| v >= 0 && v <= 300 }
141
+ end
142
+
143
+ it "uses a hex conversion of a md5 hash of the splay if present" do
144
+ node.automatic_attrs[:shard_seed] = nil
145
+ allow(node).to receive(:name).and_return("test_node")
146
+ expect(provider.splay_sleep_time(300)).to satisfy { |v| v >= 0 && v <= 300 }
147
+ end
148
+ end
149
+
81
150
  describe "#client_cmd" do
82
151
  it "creates a valid command if using all default properties" do
83
152
  expect(provider.client_cmd).to eql("C:/opscode/chef/bin/chef-client -L /etc/chef/log/client.log -c /etc/chef/client.rb") | eql("C:/opscode/chef/bin/chef-client -L C:\\chef/log/client.log -c C:\\chef/client.rb")
@@ -0,0 +1,72 @@
1
+ #
2
+ # Author:: Antony Thomas (<antonydeepak@gmail.com>)
3
+ # Copyright:: Copyright (c) Facebook, Inc. and its affiliates.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require "spec_helper"
20
+
21
+ describe Chef::Resource::File::Verification::Json do
22
+ let(:parent_resource) { Chef::Resource.new("llama") }
23
+
24
+ before(:all) do
25
+ @valid_json = "valid-#{Time.now.to_i}.json"
26
+ f = File.new(@valid_json, "w")
27
+ f.write('{
28
+ "foo": "bar"
29
+ }')
30
+ f.close
31
+
32
+ @invalid_json = "invalid-#{Time.now.to_i}.json"
33
+ f = File.new(@invalid_json, "w")
34
+ f.write("{
35
+ 'foo': 'bar'
36
+ }")
37
+ f.close
38
+
39
+ @empty_json = "empty-#{Time.now.to_i}.json"
40
+ File.new(@empty_json, "w").close
41
+ end
42
+
43
+ context "verify" do
44
+ it "returns true for valid json" do
45
+ v = Chef::Resource::File::Verification::Json.new(parent_resource, :json, {})
46
+ expect(v.verify(@valid_json)).to eq(true)
47
+ end
48
+
49
+ it "returns false for invalid json" do
50
+ v = Chef::Resource::File::Verification::Json.new(parent_resource, :json, {})
51
+ expect(v.verify(@invalid_json)).to eq(false)
52
+ end
53
+
54
+ it "returns true for empty file" do
55
+ # Expectation here is different from that of default JSON parser included in ruby 2.4+.
56
+ # The default parser considers empty string as invalid JSON
57
+ # https://stackoverflow.com/questions/30621802/why-does-json-parse-fail-with-the-empty-string,
58
+ # however JSONCompat parses an empty string to `nil`.
59
+ # We are retaining the behavior of JSONCompat for two reasons
60
+ # - It is universal inside Chef codebase
61
+ # - It can be helpful to not throw an error when a `file` or `template` is empty
62
+ v = Chef::Resource::File::Verification::Json.new(parent_resource, :json, {})
63
+ expect(v.verify(@empty_json)).to eq(true)
64
+ end
65
+ end
66
+
67
+ after(:all) do
68
+ File.delete(@valid_json)
69
+ File.delete(@invalid_json)
70
+ File.delete(@empty_json)
71
+ end
72
+ end
@@ -0,0 +1,67 @@
1
+ #
2
+ # Author:: Antony Thomas (<antonydeepak@gmail.com>)
3
+ # Copyright:: Copyright (c) Chef Software Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require "spec_helper"
20
+
21
+ describe Chef::Resource::File::Verification::Yaml do
22
+ let(:parent_resource) { Chef::Resource.new("llama") }
23
+
24
+ before(:all) do
25
+ @valid_yaml = "valid-#{Time.now.to_i}.yaml"
26
+ f = File.new(@valid_yaml, "w")
27
+ f.write("# comment
28
+ svc:
29
+ mysqlPassword: sepppasswd
30
+ ")
31
+ f.close
32
+
33
+ @invalid_yaml = "invalid-#{Time.now.to_i}.yaml"
34
+ f = File.new(@invalid_yaml, "w")
35
+ f.write("# comment
36
+ svc:
37
+ mysqlPassword: 'sepppasswd
38
+ ")
39
+ f.close
40
+
41
+ @empty_yaml = "empty-#{Time.now.to_i}.yaml"
42
+ File.new(@empty_yaml, "w").close
43
+ end
44
+
45
+ context "verify" do
46
+ it "returns true for valid yaml" do
47
+ v = Chef::Resource::File::Verification::Yaml.new(parent_resource, :yaml, {})
48
+ expect(v.verify(@valid_yaml)).to eq(true)
49
+ end
50
+
51
+ it "returns false for invalid yaml" do
52
+ v = Chef::Resource::File::Verification::Yaml.new(parent_resource, :yaml, {})
53
+ expect(v.verify(@invalid_yaml)).to eq(false)
54
+ end
55
+
56
+ it "returns true for empty file" do
57
+ v = Chef::Resource::File::Verification::Yaml.new(parent_resource, :yaml, {})
58
+ expect(v.verify(@empty_yaml)).to eq(true)
59
+ end
60
+ end
61
+
62
+ after(:all) do
63
+ File.delete(@valid_yaml)
64
+ File.delete(@invalid_yaml)
65
+ File.delete(@empty_yaml)
66
+ end
67
+ end