chef 12.9.41 → 12.10.24

Sign up to get free protection for your applications and to get access to all the features.
Files changed (132) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +52 -13
  3. data/README.md +145 -0
  4. data/Rakefile +4 -14
  5. data/VERSION +1 -1
  6. data/acceptance/.gitignore +0 -1
  7. data/acceptance/Gemfile +2 -2
  8. data/acceptance/Gemfile.lock +235 -0
  9. data/acceptance/fips/.kitchen.yml +5 -1
  10. data/acceptance/fips/test/integration/{fips → fips-integration}/serverspec/Gemfile +0 -0
  11. data/acceptance/fips/test/integration/fips-integration/serverspec/fips-integration_spec.rb +51 -0
  12. data/acceptance/fips/test/integration/fips-unit-functional/serverspec/Gemfile +3 -0
  13. data/acceptance/fips/test/integration/fips-unit-functional/serverspec/fips-unit-functional_spec.rb +56 -0
  14. data/{chef-windows.gemspec → chef-universal-mingw32.gemspec} +0 -0
  15. data/chef.gemspec +0 -6
  16. data/{lib → lib-backcompat}/chef/chef_fs/file_system/already_exists_error.rb +0 -0
  17. data/{lib → lib-backcompat}/chef/chef_fs/file_system/cookbook_frozen_error.rb +0 -0
  18. data/{lib → lib-backcompat}/chef/chef_fs/file_system/default_environment_cannot_be_modified_error.rb +0 -0
  19. data/{lib → lib-backcompat}/chef/chef_fs/file_system/file_system_error.rb +0 -0
  20. data/{lib → lib-backcompat}/chef/chef_fs/file_system/must_delete_recursively_error.rb +0 -0
  21. data/{lib → lib-backcompat}/chef/chef_fs/file_system/not_found_error.rb +0 -0
  22. data/{lib → lib-backcompat}/chef/chef_fs/file_system/operation_failed_error.rb +0 -0
  23. data/{lib → lib-backcompat}/chef/chef_fs/file_system/operation_not_allowed_error.rb +0 -0
  24. data/lib-backcompat/chef/chef_fs/file_system/repository/chef_repository_file_system_acls_dir.rb +5 -0
  25. data/lib-backcompat/chef/chef_fs/file_system/repository/chef_repository_file_system_client_keys_dir.rb +5 -0
  26. data/lib-backcompat/chef/chef_fs/file_system/repository/chef_repository_file_system_entry.rb +6 -0
  27. data/lib-backcompat/chef/chef_fs/file_system/repository/chef_repository_file_system_policies_dir.rb +5 -0
  28. data/{lib → lib-backcompat}/chef/chef_fs/file_system/repository/file_system_root_dir.rb +1 -0
  29. data/lib/chef/chef_fs/file_system/repository/acl.rb +38 -0
  30. data/lib/chef/chef_fs/file_system/repository/{chef_repository_file_system_acls_dir.rb → acls_dir.rb} +14 -5
  31. data/lib/chef/chef_fs/file_system/repository/acls_sub_dir.rb +42 -0
  32. data/lib/chef/chef_fs/file_system/repository/base_file.rb +120 -0
  33. data/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_cookbook_entry.rb +1 -1
  34. data/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_root_dir.rb +36 -32
  35. data/lib/chef/chef_fs/file_system/repository/client.rb +38 -0
  36. data/lib/chef/chef_fs/file_system/repository/client_key.rb +38 -0
  37. data/lib/chef/chef_fs/file_system/repository/{chef_repository_file_system_client_keys_dir.rb → client_keys_dir.rb} +9 -5
  38. data/lib/chef/chef_fs/file_system/repository/client_keys_sub_dir.rb +42 -0
  39. data/lib/chef/chef_fs/file_system/repository/clients_dir.rb +40 -0
  40. data/lib/chef/chef_fs/file_system/repository/container.rb +38 -0
  41. data/lib/chef/chef_fs/file_system/repository/containers_dir.rb +41 -0
  42. data/lib/chef/chef_fs/file_system/repository/cookbooks_dir.rb +0 -1
  43. data/lib/chef/chef_fs/file_system/repository/data_bag_item.rb +3 -79
  44. data/lib/chef/chef_fs/file_system/repository/directory.rb +15 -2
  45. data/lib/chef/chef_fs/file_system/repository/environment.rb +38 -0
  46. data/lib/chef/chef_fs/file_system/repository/environments_dir.rb +41 -0
  47. data/lib/chef/chef_fs/file_system/repository/file_system_entry.rb +66 -30
  48. data/lib/chef/chef_fs/file_system/repository/group.rb +38 -0
  49. data/lib/chef/chef_fs/file_system/repository/groups_dir.rb +41 -0
  50. data/lib/chef/chef_fs/file_system/repository/node.rb +38 -0
  51. data/lib/chef/chef_fs/file_system/repository/nodes_dir.rb +41 -0
  52. data/lib/chef/chef_fs/file_system/repository/{chef_repository_file_system_policies_dir.rb → policies_dir.rb} +9 -5
  53. data/lib/chef/chef_fs/file_system/repository/policy.rb +38 -0
  54. data/lib/chef/chef_fs/file_system/repository/policy_group.rb +38 -0
  55. data/lib/chef/chef_fs/file_system/repository/policy_groups_dir.rb +41 -0
  56. data/lib/chef/chef_fs/file_system/repository/role.rb +38 -0
  57. data/lib/chef/chef_fs/file_system/repository/roles_dir.rb +41 -0
  58. data/lib/chef/chef_fs/file_system/repository/user.rb +38 -0
  59. data/lib/chef/chef_fs/file_system/repository/users_dir.rb +41 -0
  60. data/lib/chef/dsl/declare_resource.rb +182 -7
  61. data/lib/chef/http/json_input.rb +2 -2
  62. data/lib/chef/knife.rb +1 -1
  63. data/lib/chef/mixin/shell_out.rb +10 -21
  64. data/lib/chef/property.rb +9 -2
  65. data/lib/chef/provider.rb +8 -7
  66. data/lib/chef/provider/apt_repository.rb +8 -6
  67. data/lib/chef/provider/directory.rb +15 -1
  68. data/lib/chef/provider/env/windows.rb +1 -1
  69. data/lib/chef/provider/mdadm.rb +1 -0
  70. data/lib/chef/provider/package/easy_install.rb +2 -0
  71. data/lib/chef/provider/package/rubygems.rb +4 -1
  72. data/lib/chef/provider/package/windows.rb +1 -1
  73. data/lib/chef/recipe.rb +1 -2
  74. data/lib/chef/resource/apt_repository.rb +6 -6
  75. data/lib/chef/resource/mdadm.rb +9 -0
  76. data/lib/chef/resource_collection.rb +5 -0
  77. data/lib/chef/resource_collection/resource_list.rb +10 -0
  78. data/lib/chef/resource_collection/resource_set.rb +14 -11
  79. data/lib/chef/version.rb +1 -1
  80. data/spec/functional/resource/git_spec.rb +1 -3
  81. data/spec/functional/resource/group_spec.rb +5 -5
  82. data/spec/functional/tiny_server_spec.rb +1 -1
  83. data/spec/functional/util/powershell/cmdlet_spec.rb +1 -1
  84. data/spec/functional/win32/registry_spec.rb +3 -3
  85. data/spec/integration/solo/solo_spec.rb +2 -2
  86. data/spec/support/shared/functional/securable_resource.rb +1 -1
  87. data/spec/support/shared/unit/provider/file.rb +3 -3
  88. data/spec/support/shared/unit/windows_script_resource.rb +1 -1
  89. data/spec/unit/application/apply_spec.rb +1 -0
  90. data/spec/unit/chef_fs/file_system/repository/base_file_spec.rb +128 -0
  91. data/spec/unit/chef_fs/file_system/repository/directory_spec.rb +174 -0
  92. data/spec/unit/cookbook/metadata_spec.rb +1 -1
  93. data/spec/unit/dsl/declare_resource_spec.rb +335 -0
  94. data/spec/unit/knife/bootstrap_spec.rb +2 -2
  95. data/spec/unit/mixin/shell_out_spec.rb +4 -0
  96. data/spec/unit/node/attribute_spec.rb +1 -1
  97. data/spec/unit/node/immutable_collections_spec.rb +2 -2
  98. data/spec/unit/node_map_spec.rb +1 -1
  99. data/spec/unit/property/validation_spec.rb +23 -7
  100. data/spec/unit/provider/apt_repository_spec.rb +5 -0
  101. data/spec/unit/provider/apt_update_spec.rb +1 -0
  102. data/spec/unit/provider/directory_spec.rb +0 -7
  103. data/spec/unit/provider/file/content_spec.rb +1 -1
  104. data/spec/unit/provider/mdadm_spec.rb +9 -0
  105. data/spec/unit/provider/package/easy_install_spec.rb +6 -0
  106. data/spec/unit/provider/package/rubygems_spec.rb +8 -4
  107. data/spec/unit/provider/package/yum_spec.rb +1 -1
  108. data/spec/unit/provider/powershell_script_spec.rb +1 -1
  109. data/spec/unit/provider/user/dscl_spec.rb +6 -6
  110. data/spec/unit/recipe_spec.rb +1 -0
  111. data/spec/unit/resource/apt_repository_spec.rb +4 -0
  112. data/spec/unit/resource/file/verification_spec.rb +1 -1
  113. data/spec/unit/resource/file_spec.rb +2 -2
  114. data/spec/unit/resource/mdadm_spec.rb +7 -2
  115. data/spec/unit/resource_collection_spec.rb +30 -0
  116. data/spec/unit/resource_spec.rb +1 -1
  117. data/tasks/bin/bundle-platform +15 -0
  118. data/tasks/bin/bundle-platform.bat +2 -0
  119. data/tasks/bin/create-override-gemfile +110 -0
  120. data/tasks/bin/run_chef_tests +17 -0
  121. data/tasks/bin/run_external_test +47 -0
  122. data/tasks/bundle.rb +97 -0
  123. data/tasks/bundle_util.rb +94 -0
  124. data/tasks/changelog.rb +12 -0
  125. data/tasks/dependencies.rb +147 -0
  126. data/tasks/gemfile_util.rb +390 -0
  127. data/tasks/maintainers.rb +2 -1
  128. data/tasks/rspec.rb +2 -1
  129. metadata +61 -83
  130. data/acceptance/fips/test/integration/fips/serverspec/fips_spec.rb +0 -39
  131. data/lib/chef/chef_fs/file_system/repository/chef_repository_file_system_entry.rb +0 -83
  132. data/tasks/external_tests.rb +0 -64
@@ -26,7 +26,7 @@ describe TinyServer::API do
26
26
  end
27
27
 
28
28
  it "is a Singleton" do
29
- expect { TinyServer::API.new }.to raise_error
29
+ expect { TinyServer::API.new }.to raise_error NoMethodError
30
30
  end
31
31
 
32
32
  it "clears the router" do
@@ -105,7 +105,7 @@ describe Chef::Util::Powershell::Cmdlet, :windows_powershell_dsc_only do
105
105
  context "when constructor is given invalid arguments" do
106
106
  let(:cmd_output_format) { :invalid }
107
107
  it "throws an exception if an invalid format is passed to the constructor" do
108
- expect(lambda { simple_cmdlet }).to raise_error
108
+ expect(lambda { simple_cmdlet }).to raise_error(ArgumentError)
109
109
  end
110
110
  end
111
111
  end
@@ -243,7 +243,7 @@ describe "Chef::Win32::Registry", :windows_only do
243
243
  end
244
244
 
245
245
  it "throws an exception when trying to cast an array to an int for a dword" do
246
- expect { @registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", { :name => "ShouldThrow", :type => :dword, :data => %w{one two} }) }.to raise_error
246
+ expect { @registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", { :name => "ShouldThrow", :type => :dword, :data => %w{one two} }) }.to raise_error NoMethodError
247
247
  end
248
248
 
249
249
  # we are validating that the data gets .to_s called on it when type is a :string
@@ -261,11 +261,11 @@ describe "Chef::Win32::Registry", :windows_only do
261
261
  # we are validating that the data gets .to_a called on it when type is a :multi_string
262
262
 
263
263
  it "throws an exception when a multi-string is passed a number" do
264
- expect { @registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", { :name => "ShouldThrow", :type => :multi_string, :data => 65535 }) }.to raise_error
264
+ expect { @registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", { :name => "ShouldThrow", :type => :multi_string, :data => 65535 }) }.to raise_error NoMethodError
265
265
  end
266
266
 
267
267
  it "throws an exception when a multi-string is passed a string" do
268
- expect { @registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", { :name => "ShouldBeWat", :type => :multi_string, :data => "foo" }) }.to raise_error
268
+ expect { @registry.set_value("HKCU\\Software\\Root\\Branch\\Flower", { :name => "ShouldBeWat", :type => :multi_string, :data => "foo" }) }.to raise_error NoMethodError
269
269
  end
270
270
  end
271
271
 
@@ -112,7 +112,7 @@ EOM
112
112
  file "cookbooks/x/recipes/default.rb", <<EOM
113
113
  ruby_block "sleeping" do
114
114
  block do
115
- sleep 5
115
+ sleep 10
116
116
  end
117
117
  end
118
118
  EOM
@@ -134,7 +134,7 @@ EOM
134
134
  -l debug -L #{path_to('logs/runs.log')}", :chdir => chef_dir)
135
135
 
136
136
  # Give it some time to progress
137
- sleep 1
137
+ sleep 5
138
138
 
139
139
  # Instantiate the second chef-solo run
140
140
  s2 = Process.spawn("#{chef_solo} -c \"#{path_to('config/solo.rb')}\" -o 'x::default' \
@@ -309,7 +309,7 @@ shared_examples_for "a securable resource without existing target" do
309
309
  end
310
310
 
311
311
  it "fails to set owner when owner has invalid characters" do
312
- expect { resource.owner 'Lance "The Nose" Glindenberry III' }.to raise_error#(Chef::Exceptions::ValidationFailed)
312
+ expect { resource.owner 'Lance "The Nose" Glindenberry III' }.to raise_error(Chef::Exceptions::ValidationFailed)
313
313
  end
314
314
 
315
315
  it "sets owner when owner is specified with a \\" do
@@ -586,14 +586,14 @@ shared_examples_for Chef::Provider::File do
586
586
  it "raises an exception when the content object returns a tempfile with a nil path" do
587
587
  tempfile = double("Tempfile", :path => nil)
588
588
  expect(provider.send(:content)).to receive(:tempfile).at_least(:once).and_return(tempfile)
589
- expect { provider.send(:do_contents_changes) }.to raise_error
589
+ expect { provider.send(:do_contents_changes) }.to raise_error(RuntimeError)
590
590
  end
591
591
 
592
592
  it "raises an exception when the content object returns a tempfile that does not exist" do
593
593
  tempfile = double("Tempfile", :path => "/tmp/foo-bar-baz")
594
594
  expect(provider.send(:content)).to receive(:tempfile).at_least(:once).and_return(tempfile)
595
595
  expect(File).to receive(:exists?).with("/tmp/foo-bar-baz").and_return(false)
596
- expect { provider.send(:do_contents_changes) }.to raise_error
596
+ expect { provider.send(:do_contents_changes) }.to raise_error(RuntimeError)
597
597
  end
598
598
  end
599
599
 
@@ -712,7 +712,7 @@ shared_examples_for Chef::Provider::File do
712
712
  it "should not try to backup or delete the file, and should not be updated by last action" do
713
713
  expect(provider).not_to receive(:do_backup)
714
714
  expect(File).not_to receive(:delete)
715
- expect { provider.run_action(:delete) }.to raise_error()
715
+ expect { provider.run_action(:delete) }.to raise_error(Chef::Exceptions::InsufficientPermissions)
716
716
  expect(resource).not_to be_updated_by_last_action
717
717
  end
718
718
  end
@@ -64,7 +64,7 @@ shared_examples_for "a Windows script resource" do
64
64
  it "should raise an exception if the guard_interpreter is overridden from its default value" do
65
65
  @resource.guard_interpreter :bash
66
66
  @resource.only_if { true }
67
- expect { @resource.should_skip?(:run) }.to raise_error
67
+ expect { @resource.should_skip?(:run) }.to raise_error(ArgumentError)
68
68
  end
69
69
  end
70
70
  end
@@ -22,6 +22,7 @@ describe Chef::Application::Apply do
22
22
  before do
23
23
  @app = Chef::Application::Apply.new
24
24
  allow(@app).to receive(:configure_logging).and_return(true)
25
+ allow(Chef::Log).to receive(:debug).with("FIPS mode is enabled.")
25
26
  @recipe_text = "package 'nyancat'"
26
27
  Chef::Config[:solo] = true
27
28
  end
@@ -0,0 +1,128 @@
1
+ #
2
+ # Copyright:: Copyright 2012-2016, Chef Software Inc.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ require "spec_helper"
19
+ require "chef/chef_fs/file_system/repository/base_file"
20
+ require "chef/chef_fs/file_system/repository/directory"
21
+ require "chef/chef_fs/file_system/base_fs_object"
22
+ require "chef/chef_fs/file_system/exceptions"
23
+ require "chef/chef_fs/file_system/nonexistent_fs_object"
24
+
25
+ describe Chef::ChefFS::FileSystem::Repository::BaseFile do
26
+ let(:root) do
27
+ Chef::ChefFS::FileSystem::BaseFSDir.new("", nil)
28
+ end
29
+
30
+ let(:tmp_dir) { Dir.mktmpdir }
31
+
32
+ let(:parent) do
33
+ Chef::ChefFS::FileSystem::Repository::Directory.new("test", root, tmp_dir)
34
+ end
35
+
36
+ let(:file) do
37
+ file = described_class.new("test_file.json", parent)
38
+ file.write_pretty_json = false
39
+ file
40
+ end
41
+
42
+ let(:content) { '"name": "canteloup"' }
43
+ let(:file_path) { File.join(tmp_dir, "test_file.json") }
44
+
45
+ after do
46
+ FileUtils.rm_f(file_path)
47
+ end
48
+
49
+ context "#is_json_file?" do
50
+ it "returns false when the file is not json" do
51
+ file = described_class.new("test_file.dpkg", parent)
52
+ expect(file.is_json_file?).to be_falsey
53
+ end
54
+
55
+ it "returns true when the file is json" do
56
+ expect(file.is_json_file?).to be_truthy
57
+ end
58
+ end
59
+
60
+ context "#name_valid?" do
61
+ it "rejects dotfiles" do
62
+ file = described_class.new(".test_file.json", parent)
63
+ expect(file.name_valid?).to be_falsey
64
+ end
65
+
66
+ it "rejects non json files" do
67
+ file = described_class.new("test_file.dpkg", parent)
68
+ expect(file.name_valid?).to be_falsey
69
+ end
70
+
71
+ it "allows correctly named files" do
72
+ expect(file.name_valid?).to be_truthy
73
+ end
74
+ end
75
+
76
+ context "#fs_entry_valid?" do
77
+ it "rejects invalid names" do
78
+ file = described_class.new("test_file.dpkg", parent)
79
+ expect(file.fs_entry_valid?).to be_falsey
80
+ end
81
+
82
+ it "rejects missing files" do
83
+ FileUtils.rm_f(file_path)
84
+ expect(file.fs_entry_valid?).to be_falsey
85
+ end
86
+
87
+ it "allows present and properly named files" do
88
+ FileUtils.touch(file_path)
89
+ expect(file.fs_entry_valid?).to be_truthy
90
+ end
91
+ end
92
+
93
+ context "#create" do
94
+ it "doesn't create an existing file" do
95
+ FileUtils.touch(file_path)
96
+ expect { file.create('"name": "canteloup"') }.to raise_error(Chef::ChefFS::FileSystem::AlreadyExistsError)
97
+ end
98
+
99
+ it "creates a new file" do
100
+ expect(file).to receive(:write).with(content)
101
+ expect { file.create(content) }.to_not raise_error
102
+ end
103
+
104
+ end
105
+
106
+ context "#write" do
107
+ context "minimises a json object" do
108
+ it "not if pretty json is off" do
109
+ expect(file).to_not receive(:minimize)
110
+ file.write(content)
111
+ end
112
+
113
+ it "not if it's not a json file" do
114
+ file = described_class.new("test_file.dpkg", parent)
115
+ file.write_pretty_json = true
116
+ expect(file).to_not receive(:minimize)
117
+ file.write(content)
118
+ end
119
+
120
+ it "correctly" do
121
+ file = described_class.new("test_file.json", parent)
122
+ file.write_pretty_json = true
123
+ expect(file).to receive(:minimize).with(content, file).and_return(content)
124
+ file.write(content)
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,174 @@
1
+ #
2
+ # Author:: Thom May (<thom@chef.io>)
3
+ # Copyright:: Copyright 2012-2016, 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
+ require "chef/chef_fs/file_system/repository/directory"
21
+ require "chef/chef_fs/file_system/base_fs_object"
22
+ require "chef/chef_fs/file_system/exceptions"
23
+ require "chef/chef_fs/file_system/nonexistent_fs_object"
24
+
25
+ CHILD_FILES = %w{ test1.json test2.json skip test3.json skip2 test4 }
26
+
27
+ class TestDirectory < Chef::ChefFS::FileSystem::Repository::Directory
28
+ def make_child_entry(name)
29
+ TestFile.new(name, self)
30
+ end
31
+
32
+ def can_have_child?(name, is_dir)
33
+ !is_dir && File.extname(name) == ".json"
34
+ end
35
+
36
+ def dir_ls
37
+ CHILD_FILES
38
+ end
39
+ end
40
+
41
+ class TestFile < Chef::ChefFS::FileSystem::BaseFSObject
42
+ def fs_entry_valid?
43
+ name.start_with? "test"
44
+ end
45
+
46
+ def name_valid?
47
+ true
48
+ end
49
+ end
50
+
51
+ describe Chef::ChefFS::FileSystem::Repository::Directory do
52
+ let(:root) do
53
+ Chef::ChefFS::FileSystem::BaseFSDir.new("", nil)
54
+ end
55
+
56
+ let(:tmp_dir) { Dir.mktmpdir }
57
+
58
+ let(:directory) do
59
+ described_class.new("test", root, tmp_dir)
60
+ end
61
+
62
+ let(:test_directory) do
63
+ TestDirectory.new("test", root, tmp_dir)
64
+ end
65
+
66
+ let(:file_double) do
67
+ double(TestFile, create: true, exists?: false)
68
+ end
69
+
70
+ context "#make_child_entry" do
71
+ it "raises if not implemented" do
72
+ expect { directory.send(:make_child_entry, "test") }.to raise_error("Not Implemented")
73
+ end
74
+ end
75
+
76
+ context "#create_child" do
77
+ it "creates a new TestFile" do
78
+ expect(TestFile).to receive(:new).with("test_child", test_directory).and_return(file_double)
79
+ expect(file_double).to receive(:write).with("test")
80
+ test_directory.create_child("test_child", "test")
81
+ end
82
+ end
83
+
84
+ context "#child" do
85
+ it "returns a child if it's valid" do
86
+ expect(test_directory.child("test")).to be_an_instance_of(TestFile)
87
+ end
88
+
89
+ it "returns a non existent object otherwise" do
90
+ file_double = instance_double(TestFile, :name_valid? => false)
91
+ expect(TestFile).to receive(:new).with("test_child", test_directory).and_return(file_double)
92
+ expect(test_directory.child("test_child")).to be_an_instance_of(Chef::ChefFS::FileSystem::NonexistentFSObject)
93
+ end
94
+ end
95
+
96
+ context "#children" do
97
+ before do
98
+ CHILD_FILES.sort.each do |child|
99
+ expect(TestFile).to receive(:new).with(child, test_directory).and_call_original
100
+ end
101
+ end
102
+
103
+ it "creates a child for each name" do
104
+ test_directory.children
105
+ end
106
+
107
+ it "filters invalid names" do
108
+ expect(test_directory.children.map { |c| c.name }).to eql %w{ test1.json test2.json test3.json }
109
+ end
110
+ end
111
+
112
+ context "#empty?" do
113
+ it "is true if there are no children" do
114
+ expect(test_directory).to receive(:children).and_return([])
115
+ expect(test_directory.empty?).to be_truthy
116
+ end
117
+
118
+ it "is false if there are children" do
119
+ expect(test_directory.empty?).to be_falsey
120
+ end
121
+ end
122
+
123
+ describe "checks entry validity" do
124
+ it "rejects dotfiles" do
125
+ dir = described_class.new(".test", root, tmp_dir)
126
+ expect(dir.name_valid?).to be_falsey
127
+ end
128
+
129
+ it "rejects files" do
130
+ Tempfile.open("test") do |file|
131
+ dir = described_class.new("test", root, file.path)
132
+ expect(dir.name_valid?).to be_truthy
133
+ expect(dir.fs_entry_valid?).to be_falsey
134
+ end
135
+ end
136
+
137
+ it "accepts directories" do
138
+ expect(directory.name_valid?).to be_truthy
139
+ end
140
+ end
141
+
142
+ describe "creates directories" do
143
+ it "doesn't create an existing directory" do
144
+ expect { directory.create }.to raise_error(Chef::ChefFS::FileSystem::AlreadyExistsError)
145
+ end
146
+
147
+ it "creates a new directory" do
148
+ FileUtils.rmdir(tmp_dir)
149
+ expect(Dir).to receive(:mkdir).with(tmp_dir)
150
+ expect { directory.create }.to_not raise_error
151
+ end
152
+
153
+ after do
154
+ FileUtils.rmdir(tmp_dir)
155
+ end
156
+ end
157
+
158
+ describe "deletes directories" do
159
+ it "won't delete a non-existant directory" do
160
+ FileUtils.rmdir(tmp_dir)
161
+ expect { directory.delete(true) }.to raise_error(Chef::ChefFS::FileSystem::NotFoundError)
162
+ end
163
+
164
+ it "must delete recursively" do
165
+ expect { directory.delete(false) }.to raise_error(Chef::ChefFS::FileSystem::MustDeleteRecursivelyError)
166
+ end
167
+
168
+ it "deletes a directory" do
169
+ expect(FileUtils).to receive(:rm_r).with(tmp_dir)
170
+ expect { directory.delete(true) }.to_not raise_error
171
+ end
172
+ end
173
+
174
+ end
@@ -707,7 +707,7 @@ describe Chef::Cookbook::Metadata do
707
707
  }
708
708
  expect {
709
709
  metadata.attribute("test_cookbook/test", options)
710
- }.to raise_error
710
+ }.to raise_error(Chef::Exceptions::ValidationFailed)
711
711
  end
712
712
 
713
713
  it "should error if default used with calculated" do
@@ -0,0 +1,335 @@
1
+ #
2
+ # Copyright:: Copyright 2008-2016, Chef Software Inc.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ require "spec_helper"
19
+
20
+ describe Chef::ResourceCollection do
21
+ let(:run_context) do
22
+ cookbook_repo = File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "data", "cookbooks"))
23
+ cookbook_loader = Chef::CookbookLoader.new(cookbook_repo)
24
+ cookbook_loader.load_cookbooks
25
+ node = Chef::Node.new
26
+ cookbook_collection = Chef::CookbookCollection.new(cookbook_loader)
27
+ events = Chef::EventDispatch::Dispatcher.new
28
+ Chef::RunContext.new(node, cookbook_collection, events)
29
+ end
30
+
31
+ let(:recipe) do
32
+ Chef::Recipe.new("hjk", "test", run_context)
33
+ end
34
+
35
+ describe "#declare_resource" do
36
+ before do
37
+ recipe.declare_resource(:zen_master, "monkey") do
38
+ something true
39
+ end
40
+ end
41
+
42
+ it "inserts into the resource collection" do
43
+ expect(run_context.resource_collection.first.to_s).to eql("zen_master[monkey]")
44
+ end
45
+
46
+ it "sets the property from the block" do
47
+ expect(run_context.resource_collection.first.something).to be true
48
+ end
49
+ end
50
+
51
+ describe "#edit_resource!" do
52
+ it "raises if nothing is found" do
53
+ expect {
54
+ recipe.edit_resource!(:zen_master, "monkey") do
55
+ something true
56
+ end
57
+ }.to raise_error(Chef::Exceptions::ResourceNotFound)
58
+ end
59
+
60
+ it "raises if nothing is found and no block is given" do
61
+ expect {
62
+ recipe.edit_resource!(:zen_master, "monkey")
63
+ }.to raise_error(Chef::Exceptions::ResourceNotFound)
64
+ end
65
+
66
+ it "edits the resource if it finds one" do
67
+ resource = recipe.declare_resource(:zen_master, "monkey") do
68
+ something false
69
+ end
70
+ expect(
71
+ recipe.edit_resource!(:zen_master, "monkey") do
72
+ something true
73
+ end
74
+ ).to eql(resource)
75
+ expect(run_context.resource_collection.all_resources.size).to eql(1)
76
+ expect(run_context.resource_collection.first.something).to be true
77
+ end
78
+
79
+ it "acts like find_resource! if not given a block and the resource exists" do
80
+ resource = recipe.declare_resource(:zen_master, "monkey") do
81
+ something false
82
+ end
83
+ expect(
84
+ recipe.edit_resource!(:zen_master, "monkey")
85
+ ).to eql(resource)
86
+ expect(run_context.resource_collection.all_resources.size).to eql(1)
87
+ expect(run_context.resource_collection.first.something).to be false
88
+ end
89
+ end
90
+
91
+ describe "#edit_resource" do
92
+ it "inserts a resource if nothing is found" do
93
+ resource = recipe.edit_resource(:zen_master, "monkey") do
94
+ something true
95
+ end
96
+ expect(run_context.resource_collection.all_resources.size).to eql(1)
97
+ expect(run_context.resource_collection.first).to eql(resource)
98
+ expect(run_context.resource_collection.first.something).to be true
99
+ end
100
+
101
+ it "inserts a resource even if not given a block" do
102
+ resource = recipe.edit_resource(:zen_master, "monkey")
103
+ expect(run_context.resource_collection.all_resources.size).to eql(1)
104
+ expect(run_context.resource_collection.first).to eql(resource)
105
+ end
106
+
107
+ it "edits the resource if it finds one" do
108
+ resource = recipe.declare_resource(:zen_master, "monkey") do
109
+ something false
110
+ end
111
+ expect(
112
+ recipe.edit_resource(:zen_master, "monkey") do
113
+ something true
114
+ end
115
+ ).to eql(resource)
116
+ expect(run_context.resource_collection.all_resources.size).to eql(1)
117
+ expect(run_context.resource_collection.first.something).to be true
118
+ end
119
+
120
+ it "acts like find_resource if not given a block and the resource exists" do
121
+ resource = recipe.declare_resource(:zen_master, "monkey") do
122
+ something false
123
+ end
124
+ expect(
125
+ recipe.edit_resource(:zen_master, "monkey")
126
+ ).to eql(resource)
127
+ expect(run_context.resource_collection.all_resources.size).to eql(1)
128
+ expect(run_context.resource_collection.first.something).to be false
129
+ end
130
+ end
131
+
132
+ describe "#find_resource!" do
133
+ it "raises if nothing is found" do
134
+ expect {
135
+ recipe.find_resource!(:zen_master, "monkey")
136
+ }.to raise_error(Chef::Exceptions::ResourceNotFound)
137
+ end
138
+
139
+ it "raises if given a block" do
140
+ resource = recipe.declare_resource(:zen_master, "monkey") do
141
+ something false
142
+ end
143
+ expect {
144
+ recipe.find_resource!(:zen_master, "monkey") do
145
+ something false
146
+ end
147
+ }.to raise_error(ArgumentError)
148
+ end
149
+
150
+ it "returns the resource if it finds one" do
151
+ resource = recipe.declare_resource(:zen_master, "monkey") do
152
+ something false
153
+ end
154
+ expect(
155
+ recipe.find_resource!(:zen_master, "monkey")
156
+ ).to eql(resource)
157
+ expect(run_context.resource_collection.all_resources.size).to eql(1)
158
+ expect(run_context.resource_collection.first.something).to be false
159
+ end
160
+ end
161
+
162
+ describe "#find_resource without block" do
163
+ it "returns nil if nothing is found" do
164
+ expect(recipe.find_resource(:zen_master, "monkey")).to be nil
165
+ expect(run_context.resource_collection.all_resources.size).to eql(0)
166
+ end
167
+
168
+ it "returns the resource if it finds one" do
169
+ resource = recipe.declare_resource(:zen_master, "monkey") do
170
+ something false
171
+ end
172
+ expect(
173
+ recipe.find_resource(:zen_master, "monkey")
174
+ ).to eql(resource)
175
+ expect(run_context.resource_collection.all_resources.size).to eql(1)
176
+ expect(run_context.resource_collection.first.something).to be false
177
+ end
178
+ end
179
+
180
+ describe "#find_resource with block" do
181
+ it "inserts a resource if nothing is found" do
182
+ resource = recipe.find_resource(:zen_master, "monkey") do
183
+ something true
184
+ end
185
+ expect(run_context.resource_collection.all_resources.size).to eql(1)
186
+ expect(run_context.resource_collection.first).to eql(resource)
187
+ expect(run_context.resource_collection.first.something).to be true
188
+ end
189
+
190
+ it "returns the resource if it finds one" do
191
+ resource = recipe.declare_resource(:zen_master, "monkey") do
192
+ something false
193
+ end
194
+ expect(
195
+ recipe.find_resource(:zen_master, "monkey") do
196
+ something true
197
+ end
198
+ ).to eql(resource)
199
+ expect(run_context.resource_collection.all_resources.size).to eql(1)
200
+ expect(run_context.resource_collection.first.something).to be false
201
+ end
202
+ end
203
+
204
+ describe "#delete_resource" do
205
+ it "returns nil if nothing is found" do
206
+ expect(
207
+ recipe.delete_resource(:zen_master, "monkey")
208
+ ).to be nil
209
+ end
210
+
211
+ it "deletes and returns the resource if it finds one" do
212
+ resource = recipe.declare_resource(:zen_master, "monkey") do
213
+ something false
214
+ end
215
+ expect(
216
+ recipe.delete_resource(:zen_master, "monkey")
217
+ ).to eql(resource)
218
+ expect(run_context.resource_collection.all_resources.size).to eql(0)
219
+ end
220
+ end
221
+
222
+ describe "#delete_resource!" do
223
+ it "raises if nothing is found" do
224
+ expect {
225
+ recipe.delete_resource!(:zen_master, "monkey")
226
+ }.to raise_error(Chef::Exceptions::ResourceNotFound)
227
+ end
228
+
229
+ it "deletes and returns the resource if it finds one" do
230
+ resource = recipe.declare_resource(:zen_master, "monkey") do
231
+ something false
232
+ end
233
+ expect(
234
+ recipe.delete_resource!(:zen_master, "monkey")
235
+ ).to eql(resource)
236
+ expect(run_context.resource_collection.all_resources.size).to eql(0)
237
+ end
238
+ end
239
+
240
+ describe "run_context helpers" do
241
+
242
+ let(:parent_run_context) do
243
+ run_context.create_child
244
+ end
245
+
246
+ let(:child_run_context) do
247
+ parent_run_context.create_child
248
+ end
249
+
250
+ let(:parent_recipe) do
251
+ Chef::Recipe.new("hjk", "parent", parent_run_context)
252
+ end
253
+
254
+ let(:child_recipe) do
255
+ Chef::Recipe.new("hjk", "child", child_run_context)
256
+ end
257
+
258
+ before do
259
+ # wire up our outer run context to the root Chef.run_context
260
+ allow(Chef).to receive(:run_context).and_return(run_context)
261
+ end
262
+
263
+ it "our tests have correct separation" do
264
+ child_resource = child_recipe.declare_resource(:zen_master, "child") do
265
+ something false
266
+ end
267
+ parent_resource = parent_recipe.declare_resource(:zen_master, "parent") do
268
+ something false
269
+ end
270
+ root_resource = recipe.declare_resource(:zen_master, "root") do
271
+ something false
272
+ end
273
+ expect(run_context.resource_collection.first).to eql(root_resource)
274
+ expect(run_context.resource_collection.first.to_s).to eql("zen_master[root]")
275
+ expect(run_context.resource_collection.all_resources.size).to eql(1)
276
+ expect(parent_run_context.resource_collection.first).to eql(parent_resource)
277
+ expect(parent_run_context.resource_collection.first.to_s).to eql("zen_master[parent]")
278
+ expect(parent_run_context.resource_collection.all_resources.size).to eql(1)
279
+ expect(child_run_context.resource_collection.first).to eql(child_resource)
280
+ expect(child_run_context.resource_collection.first.to_s).to eql("zen_master[child]")
281
+ expect(child_run_context.resource_collection.all_resources.size).to eql(1)
282
+ end
283
+
284
+ it "with_run_context with :parent lets us build resources in the parent run_context from the child" do
285
+ child_recipe.instance_eval do
286
+ with_run_context(:parent) do
287
+ declare_resource(:zen_master, "parent") do
288
+ something false
289
+ end
290
+ end
291
+ end
292
+ expect(run_context.resource_collection.all_resources.size).to eql(0)
293
+ expect(parent_run_context.resource_collection.all_resources.size).to eql(1)
294
+ expect(parent_run_context.resource_collection.first.to_s).to eql("zen_master[parent]")
295
+ expect(child_run_context.resource_collection.all_resources.size).to eql(0)
296
+ end
297
+
298
+ it "with_run_context with :root lets us build resources in the root run_context from the child" do
299
+ child_recipe.instance_eval do
300
+ with_run_context(:root) do
301
+ declare_resource(:zen_master, "root") do
302
+ something false
303
+ end
304
+ end
305
+ end
306
+ expect(run_context.resource_collection.first.to_s).to eql("zen_master[root]")
307
+ expect(run_context.resource_collection.all_resources.size).to eql(1)
308
+ expect(parent_run_context.resource_collection.all_resources.size).to eql(0)
309
+ expect(child_run_context.resource_collection.all_resources.size).to eql(0)
310
+ end
311
+
312
+ it "with_run_context also takes a RunContext object as an argument" do
313
+ child_recipe.instance_exec(parent_run_context) do |parent_run_context|
314
+ with_run_context(parent_run_context) do
315
+ declare_resource(:zen_master, "parent") do
316
+ something false
317
+ end
318
+ end
319
+ end
320
+ expect(run_context.resource_collection.all_resources.size).to eql(0)
321
+ expect(parent_run_context.resource_collection.all_resources.size).to eql(1)
322
+ expect(parent_run_context.resource_collection.first.to_s).to eql("zen_master[parent]")
323
+ expect(child_run_context.resource_collection.all_resources.size).to eql(0)
324
+ end
325
+
326
+ it "with_run_context returns the return value of the block" do
327
+ child_recipe.instance_eval do
328
+ ret = with_run_context(:root) do
329
+ "return value"
330
+ end
331
+ raise "failed" unless ret == "return value"
332
+ end
333
+ end
334
+ end
335
+ end