chef 17.4.38-universal-mingw32 → 17.5.22-universal-mingw32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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