chef 17.4.38-universal-mingw32 → 17.7.22-universal-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (138) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +5 -0
  3. data/chef.gemspec +3 -0
  4. data/lib/chef/application/base.rb +11 -1
  5. data/lib/chef/chef_fs/file_pattern.rb +1 -1
  6. data/lib/chef/chef_fs/path_utils.rb +1 -1
  7. data/lib/chef/client.rb +1 -2
  8. data/lib/chef/compliance/input.rb +115 -0
  9. data/lib/chef/compliance/input_collection.rb +139 -0
  10. data/lib/chef/compliance/profile.rb +122 -0
  11. data/lib/chef/compliance/profile_collection.rb +109 -0
  12. data/lib/chef/compliance/runner.rb +47 -5
  13. data/lib/chef/compliance/waiver.rb +115 -0
  14. data/lib/chef/compliance/waiver_collection.rb +143 -0
  15. data/lib/chef/data_collector/run_end_message.rb +1 -1
  16. data/lib/chef/dsl/compliance.rb +38 -0
  17. data/lib/chef/dsl/reader_helpers.rb +51 -0
  18. data/lib/chef/dsl/reboot_pending.rb +1 -1
  19. data/lib/chef/dsl/recipe.rb +4 -2
  20. data/lib/chef/dsl/secret.rb +2 -4
  21. data/lib/chef/dsl/universal.rb +2 -0
  22. data/lib/chef/event_dispatch/base.rb +44 -2
  23. data/lib/chef/exceptions.rb +10 -0
  24. data/lib/chef/formatters/doc.rb +46 -0
  25. data/lib/chef/http/basic_client.rb +15 -7
  26. data/lib/chef/http.rb +7 -3
  27. data/lib/chef/provider/cron.rb +4 -1
  28. data/lib/chef/provider/file.rb +2 -0
  29. data/lib/chef/provider/git.rb +1 -1
  30. data/lib/chef/provider/ifconfig/debian.rb +1 -1
  31. data/lib/chef/provider/link.rb +2 -2
  32. data/lib/chef/provider/registry_key.rb +3 -2
  33. data/lib/chef/provider/remote_file/http.rb +1 -1
  34. data/lib/chef/provider/subversion.rb +5 -5
  35. data/lib/chef/provider/template.rb +1 -1
  36. data/lib/chef/resource/archive_file.rb +17 -14
  37. data/lib/chef/resource/chef_client_scheduled_task.rb +45 -2
  38. data/lib/chef/resource/chocolatey_config.rb +14 -14
  39. data/lib/chef/resource/chocolatey_feature.rb +1 -1
  40. data/lib/chef/resource/chocolatey_source.rb +24 -2
  41. data/lib/chef/resource/directory.rb +1 -1
  42. data/lib/chef/resource/file/verification/json.rb +50 -0
  43. data/lib/chef/resource/file/verification/yaml.rb +52 -0
  44. data/lib/chef/resource/habitat_install.rb +3 -3
  45. data/lib/chef/resource/inspec_input.rb +127 -0
  46. data/lib/chef/resource/inspec_waiver.rb +184 -0
  47. data/lib/chef/resource/inspec_waiver_file_entry.rb +1 -1
  48. data/lib/chef/resource/kernel_module.rb +27 -2
  49. data/lib/chef/resource/macos_userdefaults.rb +43 -128
  50. data/lib/chef/resource/mount.rb +1 -1
  51. data/lib/chef/resource/openssl_x509_certificate.rb +1 -1
  52. data/lib/chef/resource/powershell_package_source.rb +234 -70
  53. data/lib/chef/resource/registry_key.rb +36 -48
  54. data/lib/chef/resource/remote_file.rb +98 -2
  55. data/lib/chef/resource/timezone.rb +2 -2
  56. data/lib/chef/resource/user_ulimit.rb +1 -0
  57. data/lib/chef/resource/windows_auto_run.rb +1 -1
  58. data/lib/chef/resource/windows_dfs_namespace.rb +2 -2
  59. data/lib/chef/resource/windows_printer.rb +1 -1
  60. data/lib/chef/resource/windows_uac.rb +3 -1
  61. data/lib/chef/resource/windows_update_settings.rb +3 -3
  62. data/lib/chef/resource/windows_user_privilege.rb +1 -1
  63. data/lib/chef/resource.rb +1 -1
  64. data/lib/chef/resource_reporter.rb +1 -1
  65. data/lib/chef/resources.rb +2 -0
  66. data/lib/chef/run_context/cookbook_compiler.rb +112 -28
  67. data/lib/chef/run_context.rb +31 -1
  68. data/lib/chef/secret_fetcher/akeyless_vault.rb +57 -0
  69. data/lib/chef/secret_fetcher/aws_secrets_manager.rb +1 -1
  70. data/lib/chef/secret_fetcher/azure_key_vault.rb +63 -9
  71. data/lib/chef/secret_fetcher/base.rb +1 -1
  72. data/lib/chef/secret_fetcher/hashi_vault.rb +100 -0
  73. data/lib/chef/secret_fetcher.rb +8 -3
  74. data/lib/chef/version.rb +1 -1
  75. data/lib/chef/win32/version.rb +2 -1
  76. data/spec/data/archive_file/test_archive.tar.gz +0 -0
  77. data/spec/functional/dsl/reboot_pending_spec.rb +3 -3
  78. data/spec/functional/dsl/registry_helper_spec.rb +1 -1
  79. data/spec/functional/resource/archive_file_spec.rb +87 -0
  80. data/spec/functional/resource/dsc_script_spec.rb +2 -2
  81. data/spec/functional/resource/group_spec.rb +5 -1
  82. data/spec/functional/resource/link_spec.rb +8 -0
  83. data/spec/functional/resource/macos_userdefaults_spec.rb +119 -0
  84. data/spec/functional/resource/powershell_package_source_spec.rb +5 -6
  85. data/spec/functional/resource/registry_spec.rb +81 -81
  86. data/spec/functional/win32/registry_spec.rb +8 -8
  87. data/spec/integration/compliance/compliance_spec.rb +60 -0
  88. data/spec/spec_helper.rb +3 -0
  89. data/spec/support/platform_helpers.rb +4 -0
  90. data/spec/support/ruby_installer.rb +51 -0
  91. data/spec/unit/compliance/input_spec.rb +104 -0
  92. data/spec/unit/compliance/profile_spec.rb +120 -0
  93. data/spec/unit/compliance/waiver_spec.rb +104 -0
  94. data/spec/unit/data_collector_spec.rb +24 -1
  95. data/spec/unit/dsl/reboot_pending_spec.rb +1 -1
  96. data/spec/unit/http/basic_client_spec.rb +30 -0
  97. data/spec/unit/http_spec.rb +8 -2
  98. data/spec/unit/mixin/default_paths_spec.rb +1 -1
  99. data/spec/unit/mixin/securable_spec.rb +3 -3
  100. data/spec/unit/provider/cron_spec.rb +45 -0
  101. data/spec/unit/provider/link_spec.rb +13 -7
  102. data/spec/unit/provider/package/rubygems_spec.rb +5 -5
  103. data/spec/unit/provider/package/windows_spec.rb +1 -1
  104. data/spec/unit/provider/registry_key_spec.rb +4 -4
  105. data/spec/unit/provider/remote_file/http_spec.rb +10 -0
  106. data/spec/unit/provider/service/windows_spec.rb +5 -5
  107. data/spec/unit/provider/subversion_spec.rb +4 -4
  108. data/spec/unit/provider/template_spec.rb +2 -2
  109. data/spec/unit/provider/windows_env_spec.rb +1 -1
  110. data/spec/unit/provider/zypper_repository_spec.rb +1 -1
  111. data/spec/unit/resource/archive_file_spec.rb +414 -3
  112. data/spec/unit/resource/chef_client_scheduled_task_spec.rb +69 -0
  113. data/spec/unit/resource/chocolatey_config_spec.rb +1 -1
  114. data/spec/unit/resource/chocolatey_feature_spec.rb +1 -1
  115. data/spec/unit/resource/chocolatey_source_spec.rb +1 -1
  116. data/spec/unit/resource/file/verification/json_spec.rb +72 -0
  117. data/spec/unit/resource/file/verification/yaml_spec.rb +67 -0
  118. data/spec/unit/resource/inspec_input_spec.rb +300 -0
  119. data/spec/unit/resource/inspec_waiver_spec.rb +312 -0
  120. data/spec/unit/resource/kernel_module_spec.rb +2 -1
  121. data/spec/unit/resource/macos_user_defaults_spec.rb +36 -96
  122. data/spec/unit/resource/mount_spec.rb +10 -0
  123. data/spec/unit/resource/powershell_package_source_spec.rb +63 -62
  124. data/spec/unit/resource/registry_key_spec.rb +10 -10
  125. data/spec/unit/resource/user_ulimit_spec.rb +14 -1
  126. data/spec/unit/resource/windows_auto_run_spec.rb +1 -1
  127. data/spec/unit/resource/windows_feature_powershell_spec.rb +1 -1
  128. data/spec/unit/resource/windows_firewall_rule_spec.rb +2 -2
  129. data/spec/unit/resource/windows_task_spec.rb +3 -3
  130. data/spec/unit/resource_reporter_spec.rb +2 -2
  131. data/spec/unit/resource_spec.rb +5 -0
  132. data/spec/unit/secret_fetcher/akeyless_vault_spec.rb +37 -0
  133. data/spec/unit/secret_fetcher/azure_key_vault_spec.rb +99 -20
  134. data/spec/unit/secret_fetcher/hashi_vault_spec.rb +80 -0
  135. data/spec/unit/util/backup_spec.rb +1 -1
  136. data/spec/unit/win32/registry_spec.rb +3 -3
  137. data/tasks/rspec.rb +2 -1
  138. metadata +75 -6
@@ -39,7 +39,7 @@ describe Chef::Provider::Package::Windows, :windows_only do
39
39
  new_resource
40
40
  end
41
41
  let(:provider) { Chef::Provider::Package::Windows.new(new_resource, run_context) }
42
- let(:cache_path) { 'c:\\cache\\' }
42
+ let(:cache_path) { "c:\\cache\\" }
43
43
 
44
44
  before(:each) do
45
45
  allow(::File).to receive(:exist?).with(new_resource.source).and_return(true)
@@ -274,7 +274,7 @@ describe Chef::Provider::RegistryKey do
274
274
  end
275
275
 
276
276
  context "when the key data is safe" do
277
- let(:keyname) { 'HKLM\Software\Opscode\Testing\Safe' }
277
+ let(:keyname) { "HKLM\\Software\\Opscode\\Testing\\Safe" }
278
278
  let(:testval1) { { name: "one", type: :string, data: "1" } }
279
279
  let(:testval1_wrong_type) { { name: "one", type: :multi_string, data: "1" } }
280
280
  let(:testval1_wrong_data) { { name: "one", type: :string, data: "2" } }
@@ -295,7 +295,7 @@ describe Chef::Provider::RegistryKey do
295
295
 
296
296
  describe "action_create" do
297
297
  context "when key exists and type matches" do
298
- let(:keyname) { 'hklm\\software\\opscode\\testing\\dword' }
298
+ let(:keyname) { "hklm\\software\\opscode\\testing\\dword" }
299
299
  let(:dword_passed_as_integer) { { name: "one", type: :dword, data: 12345 } }
300
300
  let(:testval1) { { name: "one", type: :dword, data: "12345" } }
301
301
  before do
@@ -349,7 +349,7 @@ describe Chef::Provider::RegistryKey do
349
349
  end
350
350
 
351
351
  context "and key does not exist" do
352
- let(:keyname) { 'hklm\\software\\opscode\\testing\\sensitive\missing' }
352
+ let(:keyname) { "hklm\\software\\opscode\\testing\\sensitive\\missing" }
353
353
  let(:testval1) { { name: "one", type: :string, data: "first_value" } }
354
354
 
355
355
  before(:each) do
@@ -368,7 +368,7 @@ describe Chef::Provider::RegistryKey do
368
368
 
369
369
  describe "action_create_if_missing" do
370
370
  context "when sensitive is true" do
371
- let(:keyname) { 'hklm\\software\\opscode\\testing\\create_if_missing\\sensitive' }
371
+ let(:keyname) { "hklm\\software\\opscode\\testing\\create_if_missing\\sensitive" }
372
372
  let(:testval1) { { name: "one", type: :string, data: "first_value" } }
373
373
 
374
374
  before(:each) do
@@ -321,4 +321,14 @@ describe Chef::Provider::RemoteFile::HTTP do
321
321
 
322
322
  end
323
323
 
324
+ describe "#http_client_opts" do
325
+ before do
326
+ new_resource.http_options({ retries: 2, retry_delay: 3 })
327
+ end
328
+
329
+ it "should set http client options" do
330
+ expect(fetcher.send(:http_client_opts)).to eq({ retries: 2, retry_delay: 3 })
331
+ end
332
+ end
333
+
324
334
  end
@@ -33,7 +33,7 @@ describe Chef::Provider::Service::Windows, "load_current_resource" do
33
33
 
34
34
  # Actual response from Win32::Service.config_info('chef-client')
35
35
  let(:chef_service_binary_path_name) do
36
- 'C:\\opscode\\chef\\embedded\\bin\\ruby.exe C:\\opscode\\chef\\bin\\chef-windows-service'
36
+ "C:\\opscode\\chef\\embedded\\bin\\ruby.exe C:\\opscode\\chef\\bin\\chef-windows-service"
37
37
  end
38
38
  let(:chef_service_config_info) do
39
39
  double("Struct::ServiceConfigInfo",
@@ -153,11 +153,11 @@ describe Chef::Provider::Service::Windows, "load_current_resource" do
153
153
  service_type: "share process",
154
154
  start_type: "demand start",
155
155
  error_control: "normal",
156
- binary_path_name: 'C:\\Windows\\system32\\svchost.exe -k LocalServiceNetworkRestricted',
156
+ binary_path_name: "C:\\Windows\\system32\\svchost.exe -k LocalServiceNetworkRestricted",
157
157
  load_order_group: "TDI",
158
158
  tag_id: 0,
159
159
  dependencies: %w{NSI Tdx Afd},
160
- service_start_name: 'NT Authority\\LocalService',
160
+ service_start_name: "NT Authority\\LocalService",
161
161
  display_name: "DHCP Client")
162
162
  )
163
163
  end
@@ -169,11 +169,11 @@ describe Chef::Provider::Service::Windows, "load_current_resource" do
169
169
  service_type: "share process",
170
170
  start_type: "demand start",
171
171
  error_control: "normal",
172
- binary_path_name: 'C:\\Windows\\system32\\svchost.exe -k LocalServiceNetworkRestricted',
172
+ binary_path_name: "C:\\Windows\\system32\\svchost.exe -k LocalServiceNetworkRestricted",
173
173
  load_order_group: "TDI",
174
174
  tag_id: 0,
175
175
  dependencies: %w{NSI Tdx Afd},
176
- service_start_name: 'NT Authority\\LocalService',
176
+ service_start_name: "NT Authority\\LocalService",
177
177
  display_name: "DHCP Client")
178
178
  )
179
179
  end
@@ -190,7 +190,7 @@ describe Chef::Provider::Subversion do
190
190
  it "runs an export with the --force option" do
191
191
  allow(::File).to receive(:directory?).with("/my/deploy").and_return(true)
192
192
  expected_cmd = "svn export --force -q -r12345 http://svn.example.org/trunk/ /my/deploy/dir"
193
- expect(@provider).to receive(:shell_out!).with(expected_cmd, {})
193
+ expect(@provider).to receive(:shell_out!).with(expected_cmd)
194
194
  @provider.run_action(:force_export)
195
195
  expect(@resource).to be_updated
196
196
  end
@@ -198,7 +198,7 @@ describe Chef::Provider::Subversion do
198
198
  it "runs the checkout command for action_checkout" do
199
199
  allow(::File).to receive(:directory?).with("/my/deploy").and_return(true)
200
200
  expected_cmd = "svn checkout -q -r12345 http://svn.example.org/trunk/ /my/deploy/dir"
201
- expect(@provider).to receive(:shell_out!).with(expected_cmd, {})
201
+ expect(@provider).to receive(:shell_out!).with(expected_cmd)
202
202
  @provider.run_action(:checkout)
203
203
  expect(@resource).to be_updated
204
204
  end
@@ -248,7 +248,7 @@ describe Chef::Provider::Subversion do
248
248
  allow(@provider).to receive(:find_current_revision).and_return("11410")
249
249
  allow(@provider).to receive(:current_revision_matches_target_revision?).and_return(false)
250
250
  expected_cmd = "svn update -q -r12345 /my/deploy/dir"
251
- expect(@provider).to receive(:shell_out!).with(expected_cmd, {})
251
+ expect(@provider).to receive(:shell_out!).with(expected_cmd)
252
252
  @provider.run_action(:sync)
253
253
  expect(@resource).to be_updated
254
254
  end
@@ -265,7 +265,7 @@ describe Chef::Provider::Subversion do
265
265
  it "runs the export_command on action_export" do
266
266
  allow(::File).to receive(:directory?).with("/my/deploy").and_return(true)
267
267
  expected_cmd = "svn export --force -q -r12345 http://svn.example.org/trunk/ /my/deploy/dir"
268
- expect(@provider).to receive(:shell_out!).with(expected_cmd, {})
268
+ expect(@provider).to receive(:shell_out!).with(expected_cmd)
269
269
  @provider.run_action(:export)
270
270
  expect(@resource).to be_updated
271
271
  end
@@ -50,7 +50,7 @@ describe Chef::Provider::Template do
50
50
 
51
51
  let(:content) do
52
52
  content = double("Chef::Provider::File::Content::Template", template_location: "/foo/bar/baz")
53
- allow(File).to receive(:exists?).with("/foo/bar/baz").and_return(true)
53
+ allow(File).to receive(:exist?).with("/foo/bar/baz").and_return(true)
54
54
  content
55
55
  end
56
56
 
@@ -76,7 +76,7 @@ describe Chef::Provider::Template do
76
76
  it "stops executing when the local template source can't be found" do
77
77
  setup_normal_file
78
78
  allow(content).to receive(:template_location).and_return("/baz/bar/foo")
79
- allow(File).to receive(:exists?).with("/baz/bar/foo").and_return(false)
79
+ allow(File).to receive(:exist?).with("/baz/bar/foo").and_return(false)
80
80
  expect { provider.run_action(:create) }.to raise_error Chef::Mixin::WhyRun::ResourceRequirements::Assertion::AssertionFailure
81
81
  end
82
82
 
@@ -358,7 +358,7 @@ describe "windows_env provider", :windows_only do
358
358
  context "when environment is PATH" do
359
359
  describe "for PATH" do
360
360
  let(:system_root) { "%SystemRoot%" }
361
- let(:system_root_value) { 'D:\Windows' }
361
+ let(:system_root_value) { "D:\\Windows" }
362
362
  let(:new_resource) do
363
363
  new_resource = Chef::Resource::WindowsEnv.new("PATH", run_context)
364
364
  new_resource.value(system_root)
@@ -103,7 +103,7 @@ describe Chef::Provider::ZypperRepository do
103
103
 
104
104
  describe "#escaped_repo_name" do
105
105
  it "returns an escaped repo name" do
106
- expect(provider.escaped_repo_name).to eq('Nginx\\ Repository')
106
+ expect(provider.escaped_repo_name).to eq("Nginx\\ Repository")
107
107
  end
108
108
  end
109
109
 
@@ -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