chef 15.3.14 → 15.4.45
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/chef.gemspec +2 -2
- data/lib/chef/application/solo.rb +1 -1
- data/lib/chef/event_dispatch/dispatcher.rb +9 -2
- data/lib/chef/formatters/doc.rb +3 -3
- data/lib/chef/knife.rb +13 -3
- data/lib/chef/knife/bootstrap.rb +28 -4
- data/lib/chef/knife/bootstrap/templates/chef-full.erb +7 -8
- data/lib/chef/knife/data_bag_secret_options.rb +11 -4
- data/lib/chef/knife/download.rb +2 -2
- data/lib/chef/knife/exec.rb +9 -1
- data/lib/chef/knife/ssh.rb +1 -1
- data/lib/chef/knife/ssl_check.rb +1 -1
- data/lib/chef/knife/supermarket_list.rb +19 -7
- data/lib/chef/knife/supermarket_search.rb +3 -2
- data/lib/chef/node/attribute.rb +2 -0
- data/lib/chef/node/attribute_collections.rb +8 -0
- data/lib/chef/node/immutable_collections.rb +12 -0
- data/lib/chef/node/mixin/immutablize_array.rb +1 -0
- data/lib/chef/node/mixin/immutablize_hash.rb +1 -0
- data/lib/chef/provider.rb +14 -8
- data/lib/chef/provider/package/chocolatey.rb +11 -3
- data/lib/chef/provider/package/dnf/python_helper.rb +8 -3
- data/lib/chef/provider/package/windows/exe.rb +2 -2
- data/lib/chef/provider/package/windows/msi.rb +3 -3
- data/lib/chef/provider/package/yum/python_helper.rb +8 -3
- data/lib/chef/provider/service/windows.rb +1 -1
- data/lib/chef/resource/apt_repository.rb +19 -13
- data/lib/chef/resource/apt_update.rb +15 -1
- data/lib/chef/resource/archive_file.rb +10 -1
- data/lib/chef/resource/build_essential.rb +14 -1
- data/lib/chef/resource/chocolatey_config.rb +17 -1
- data/lib/chef/resource/chocolatey_feature.rb +15 -0
- data/lib/chef/resource/chocolatey_package.rb +31 -1
- data/lib/chef/resource/chocolatey_source.rb +17 -1
- data/lib/chef/resource/cookbook_file.rb +1 -1
- data/lib/chef/resource/cron_access.rb +22 -1
- data/lib/chef/resource/cron_d.rb +46 -1
- data/lib/chef/resource/dmg_package.rb +28 -0
- data/lib/chef/resource/kernel_module.rb +61 -0
- data/lib/chef/resource/sudo.rb +2 -2
- data/lib/chef/resource/windows_ad_join.rb +72 -3
- data/lib/chef/resource/windows_service.rb +1 -1
- data/lib/chef/resource/windows_share.rb +2 -1
- data/lib/chef/shell.rb +4 -4
- data/lib/chef/shell/ext.rb +2 -2
- data/lib/chef/train_transport.rb +1 -1
- data/lib/chef/version.rb +1 -1
- data/spec/functional/resource/ifconfig_spec.rb +0 -2
- data/spec/functional/resource/mount_spec.rb +0 -4
- data/spec/functional/util/powershell/cmdlet_spec.rb +2 -2
- data/spec/integration/knife/chef_repo_path_spec.rb +4 -2
- data/spec/integration/recipes/resource_converge_if_changed_spec.rb +19 -19
- data/spec/spec_helper.rb +2 -0
- data/spec/unit/formatters/doc_spec.rb +18 -0
- data/spec/unit/knife/bootstrap_spec.rb +46 -10
- data/spec/unit/knife/supermarket_list_spec.rb +70 -0
- data/spec/unit/knife/supermarket_search_spec.rb +85 -0
- data/spec/unit/node/attribute_spec.rb +22 -0
- data/spec/unit/node/immutable_collections_spec.rb +72 -144
- data/spec/unit/provider/package/chocolatey_spec.rb +50 -35
- data/spec/unit/provider/package/windows/exe_spec.rb +1 -1
- data/spec/unit/provider/service/windows_spec.rb +23 -3
- data/spec/unit/resource/chocolatey_package_spec.rb +17 -2
- data/spec/unit/resource/windows_ad_join_spec.rb +4 -0
- data/spec/unit/resource/windows_service_spec.rb +5 -0
- data/spec/unit/resource/windows_share_spec.rb +7 -0
- data/tasks/docs.rb +4 -1
- metadata +10 -8
data/spec/spec_helper.rb
CHANGED
@@ -141,6 +141,8 @@ RSpec.configure do |config|
|
|
141
141
|
config.filter_run_excluding skip_appveyor: true if ENV["APPVEYOR"]
|
142
142
|
config.filter_run_excluding appveyor_only: true unless ENV["APPVEYOR"]
|
143
143
|
|
144
|
+
config.filter_run_excluding skip_buildkite: true if ENV["BUILDKITE"]
|
145
|
+
|
144
146
|
config.filter_run_excluding windows_only: true unless windows?
|
145
147
|
config.filter_run_excluding not_supported_on_windows: true if windows?
|
146
148
|
config.filter_run_excluding not_supported_on_macos: true if mac_osx?
|
@@ -76,6 +76,24 @@ describe Chef::Formatters::Base do
|
|
76
76
|
expect(formatter.pretty_elapsed_time).to include("10 hours 10 minutes 10 seconds")
|
77
77
|
end
|
78
78
|
|
79
|
+
it "shows nothing if total is nil" do
|
80
|
+
res = Chef::Resource::RemoteFile.new("canteloupe")
|
81
|
+
formatter.resource_update_progress(res, 35, nil, 10)
|
82
|
+
expect(out.string).to eq("")
|
83
|
+
end
|
84
|
+
|
85
|
+
it "shows nothing if total is 0" do
|
86
|
+
res = Chef::Resource::RemoteFile.new("canteloupe")
|
87
|
+
formatter.resource_update_progress(res, 35, 0, 10)
|
88
|
+
expect(out.string).to eq("")
|
89
|
+
end
|
90
|
+
|
91
|
+
it "shows nothing if current and total are 0" do
|
92
|
+
res = Chef::Resource::RemoteFile.new("canteloupe")
|
93
|
+
formatter.resource_update_progress(res, 0, 0, 10)
|
94
|
+
expect(out.string).to eq("")
|
95
|
+
end
|
96
|
+
|
79
97
|
it "shows the percentage completion of an action" do
|
80
98
|
res = Chef::Resource::RemoteFile.new("canteloupe")
|
81
99
|
formatter.resource_update_progress(res, 35, 50, 10)
|
@@ -1839,6 +1839,20 @@ describe Chef::Knife::Bootstrap do
|
|
1839
1839
|
e
|
1840
1840
|
end
|
1841
1841
|
|
1842
|
+
let(:expected_error_password_prompt) do
|
1843
|
+
e = Train::ClientError.new
|
1844
|
+
reason = :no_ssh_password_or_key_available
|
1845
|
+
allow(e).to receive(:reason).and_return(reason)
|
1846
|
+
e
|
1847
|
+
end
|
1848
|
+
|
1849
|
+
let(:expected_error_password_prompt_winrm) do
|
1850
|
+
e = RuntimeError.new
|
1851
|
+
message = "password is a required option"
|
1852
|
+
allow(e).to receive(:message).and_return(message)
|
1853
|
+
e
|
1854
|
+
end
|
1855
|
+
|
1842
1856
|
context "and password auth was used" do
|
1843
1857
|
before do
|
1844
1858
|
allow(connection).to receive(:password_auth?).and_return true
|
@@ -1854,19 +1868,41 @@ describe Chef::Knife::Bootstrap do
|
|
1854
1868
|
before do
|
1855
1869
|
allow(connection).to receive(:password_auth?).and_return false
|
1856
1870
|
allow(connection).to receive(:user).and_return "testuser"
|
1871
|
+
allow(knife).to receive(:connection_protocol).and_return connection_protocol
|
1857
1872
|
end
|
1858
1873
|
|
1859
|
-
|
1860
|
-
|
1861
|
-
|
1862
|
-
|
1863
|
-
|
1864
|
-
|
1865
|
-
|
1866
|
-
|
1867
|
-
|
1874
|
+
context "when using ssh" do
|
1875
|
+
let(:connection_protocol) { "ssh" }
|
1876
|
+
|
1877
|
+
it "warns, prompts for password, then reconnects with a password-enabled configuration using the new password" do
|
1878
|
+
question_mock = double("question")
|
1879
|
+
expect(knife).to receive(:do_connect).and_raise(expected_error_password_prompt)
|
1880
|
+
expect(knife.ui).to receive(:warn).with(/Failed to auth.*/)
|
1881
|
+
expect(knife.ui).to receive(:ask).and_yield(question_mock).and_return("newpassword")
|
1882
|
+
# Ensure that we set echo off to prevent showing password on the screen
|
1883
|
+
expect(question_mock).to receive(:echo=).with false
|
1884
|
+
expect(knife).to receive(:do_connect) do |opts|
|
1885
|
+
expect(opts[:password]).to eq "newpassword"
|
1886
|
+
end
|
1887
|
+
knife.connect!
|
1888
|
+
end
|
1889
|
+
end
|
1890
|
+
|
1891
|
+
context "when using winrm" do
|
1892
|
+
let(:connection_protocol) { "winrm" }
|
1893
|
+
|
1894
|
+
it "warns, prompts for password, then reconnects with a password-enabled configuration using the new password for" do
|
1895
|
+
question_mock = double("question")
|
1896
|
+
expect(knife).to receive(:do_connect).and_raise(expected_error_password_prompt_winrm)
|
1897
|
+
expect(knife.ui).to receive(:warn).with(/Failed to auth.*/)
|
1898
|
+
expect(knife.ui).to receive(:ask).and_yield(question_mock).and_return("newpassword")
|
1899
|
+
# Ensure that we set echo off to prevent showing password on the screen
|
1900
|
+
expect(question_mock).to receive(:echo=).with false
|
1901
|
+
expect(knife).to receive(:do_connect) do |opts|
|
1902
|
+
expect(opts[:password]).to eq "newpassword"
|
1903
|
+
end
|
1904
|
+
knife.connect!
|
1868
1905
|
end
|
1869
|
-
knife.connect!
|
1870
1906
|
end
|
1871
1907
|
end
|
1872
1908
|
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Vivek Singh (<vivek.singh@msystechnologies.com>)
|
3
|
+
# Copyright:: Copyright 2018-2019, 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 "chef/knife/supermarket_list"
|
20
|
+
require "spec_helper"
|
21
|
+
|
22
|
+
describe Chef::Knife::SupermarketList do
|
23
|
+
let(:knife) { described_class.new }
|
24
|
+
let(:noauth_rest) { double("no auth rest") }
|
25
|
+
let(:stdout) { StringIO.new }
|
26
|
+
let(:cookbooks_data) {
|
27
|
+
[
|
28
|
+
{ "cookbook_name" => "1password", "cookbook_maintainer" => "jtimberman", "cookbook_description" => "Installs 1password", "cookbook" => "https://supermarket.chef.io/api/v1/cookbooks/1password" },
|
29
|
+
{ "cookbook_name" => "301", "cookbook_maintainer" => "markhuge", "cookbook_description" => "Installs/Configures 301", "cookbook" => "https://supermarket.chef.io/api/v1/cookbooks/301" },
|
30
|
+
{ "cookbook_name" => "3cx", "cookbook_maintainer" => "obay", "cookbook_description" => "Installs/Configures 3cx", "cookbook" => "https://supermarket.chef.io/api/v1/cookbooks/3cx" },
|
31
|
+
{ "cookbook_name" => "7dtd", "cookbook_maintainer" => "gregf", "cookbook_description" => "Installs/Configures the 7 Days To Die server", "cookbook" => "https://supermarket.chef.io/api/v1/cookbooks/7dtd" },
|
32
|
+
{ "cookbook_name" => "7-zip", "cookbook_maintainer" => "sneal", "cookbook_description" => "Installs/Configures the 7-zip file archiver", "cookbook" => "https://supermarket.chef.io/api/v1/cookbooks/7-zip" },
|
33
|
+
]
|
34
|
+
}
|
35
|
+
|
36
|
+
let(:response_text) {
|
37
|
+
{
|
38
|
+
"start" => 0,
|
39
|
+
"total" => 5,
|
40
|
+
"items" => cookbooks_data,
|
41
|
+
}
|
42
|
+
}
|
43
|
+
|
44
|
+
describe "run" do
|
45
|
+
before do
|
46
|
+
allow(knife.ui).to receive(:stdout).and_return(stdout)
|
47
|
+
allow(knife).to receive(:noauth_rest).and_return(noauth_rest)
|
48
|
+
expect(noauth_rest).to receive(:get).and_return(response_text)
|
49
|
+
knife.configure_chef
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should display all supermarket cookbooks" do
|
53
|
+
knife.run
|
54
|
+
cookbooks_data.each do |item|
|
55
|
+
expect(stdout.string).to match /#{item["cookbook_name"]}\s/
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "with -w or --with-uri" do
|
60
|
+
it "should display the cookbook uris" do
|
61
|
+
knife.config[:with_uri] = true
|
62
|
+
knife.run
|
63
|
+
cookbooks_data.each do |item|
|
64
|
+
expect(stdout.string).to match /#{item["cookbook_name"]}\s/
|
65
|
+
expect(stdout.string).to match /#{item["cookbook"]}\s/
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Vivek Singh (<vivek.singh@msystechnologies.com>)
|
3
|
+
# Copyright:: Copyright 2018-2019, 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 "chef/knife/supermarket_search"
|
20
|
+
require "spec_helper"
|
21
|
+
|
22
|
+
describe Chef::Knife::SupermarketSearch do
|
23
|
+
let(:knife) { described_class.new }
|
24
|
+
let(:noauth_rest) { double("no auth rest") }
|
25
|
+
let(:stdout) { StringIO.new }
|
26
|
+
let(:cookbooks_data) {
|
27
|
+
[
|
28
|
+
{ "cookbook_name" => "mysql", "cookbook_maintainer" => "sous-chefs", "cookbook_description" => "Provides mysql_service, mysql_config, and mysql_client resources", "cookbook" => "https://supermarket.chef.io/api/v1/cookbooks/mysql" },
|
29
|
+
{ "cookbook_name" => "mw_mysql", "cookbook_maintainer" => "car", "cookbook_description" => "Installs/Configures mw_mysql", "cookbook" => "https://supermarket.chef.io/api/v1/cookbooks/mw_mysql" },
|
30
|
+
{ "cookbook_name" => "L7-mysql", "cookbook_maintainer" => "szelcsanyi", "cookbook_description" => "Installs/Configures MySQL server", "cookbook" => "https://supermarket.chef.io/api/v1/cookbooks/l7-mysql" },
|
31
|
+
{ "cookbook_name" => "mysql-sys", "cookbook_maintainer" => "ovaistariq", "cookbook_description" => "Installs the mysql-sys tool. Description of the tool is available here https://github.com/MarkLeith/mysql-sys", "cookbook" => "https://supermarket.chef.io/api/v1/cookbooks/mysql-sys" },
|
32
|
+
{ "cookbook_name" => "cg_mysql", "cookbook_maintainer" => "phai", "cookbook_description" => "Installs/Configures mysql with master and slave", "cookbook" => "https://supermarket.chef.io/api/v1/cookbooks/cg_mysql" },
|
33
|
+
]
|
34
|
+
}
|
35
|
+
|
36
|
+
let(:response_text) {
|
37
|
+
{
|
38
|
+
"start" => 0,
|
39
|
+
"total" => 5,
|
40
|
+
"items" => cookbooks_data,
|
41
|
+
}
|
42
|
+
}
|
43
|
+
|
44
|
+
let(:empty_response_text) {
|
45
|
+
{
|
46
|
+
"start" => 0,
|
47
|
+
"total" => 0,
|
48
|
+
"items" => [],
|
49
|
+
}
|
50
|
+
}
|
51
|
+
|
52
|
+
describe "run" do
|
53
|
+
before do
|
54
|
+
allow(knife.ui).to receive(:stdout).and_return(stdout)
|
55
|
+
allow(knife).to receive(:noauth_rest).and_return(noauth_rest)
|
56
|
+
knife.configure_chef
|
57
|
+
end
|
58
|
+
|
59
|
+
context "when name_args is present" do
|
60
|
+
before do
|
61
|
+
expect(noauth_rest).to receive(:get).and_return(response_text)
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should display cookbooks with given name value" do
|
65
|
+
knife.name_args = ["mysql"]
|
66
|
+
knife.run
|
67
|
+
cookbooks_data.each do |item|
|
68
|
+
expect(stdout.string).to match /#{item["cookbook_name"]}\s/
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context "when name_args is empty string" do
|
74
|
+
before do
|
75
|
+
expect(noauth_rest).to receive(:get).and_return(empty_response_text)
|
76
|
+
end
|
77
|
+
|
78
|
+
it "display nothing with name arg empty string" do
|
79
|
+
knife.name_args = [""]
|
80
|
+
knife.run
|
81
|
+
expect(stdout.string).to eq("\n")
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -1297,4 +1297,26 @@ describe Chef::Node::Attribute do
|
|
1297
1297
|
expect(@attributes["foo"]).to be nil
|
1298
1298
|
end
|
1299
1299
|
end
|
1300
|
+
|
1301
|
+
describe "to_json" do
|
1302
|
+
it "should convert to a valid json string" do
|
1303
|
+
json = @attributes["hot"].to_json
|
1304
|
+
expect { JSON.parse(json) }.not_to raise_error
|
1305
|
+
end
|
1306
|
+
|
1307
|
+
it "should convert to a json based on current state" do
|
1308
|
+
expect(@attributes["hot"].to_json).to eq("{\"day\":\"sunday\"}")
|
1309
|
+
end
|
1310
|
+
end
|
1311
|
+
|
1312
|
+
describe "to_yaml" do
|
1313
|
+
it "should convert to a valid yaml format" do
|
1314
|
+
json = @attributes["hot"].to_yaml
|
1315
|
+
expect { YAML.parse(json) }.not_to raise_error
|
1316
|
+
end
|
1317
|
+
|
1318
|
+
it "should convert to a yaml based on current state" do
|
1319
|
+
expect(@attributes["hot"].to_yaml).to eq("---\nday: sunday\n")
|
1320
|
+
end
|
1321
|
+
end
|
1300
1322
|
end
|
@@ -19,6 +19,64 @@
|
|
19
19
|
require "spec_helper"
|
20
20
|
require "chef/node/immutable_collections"
|
21
21
|
|
22
|
+
shared_examples_for "ImmutableMash module" do |param|
|
23
|
+
let(:copy) { @immutable_mash.send(param) }
|
24
|
+
|
25
|
+
it "converts an immutable mash to a new mutable hash" do
|
26
|
+
expect(copy).to be_is_a(Hash)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "converts an immutable nested mash to a new mutable hash" do
|
30
|
+
expect(copy["top_level_4"]["level2"]).to be_is_a(Hash)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "converts an immutable nested array to a new mutable array" do
|
34
|
+
expect(copy["top_level_2"]).to be_instance_of(Array)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should create a mash with the same content" do
|
38
|
+
expect(copy).to eq(@immutable_mash)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should allow mutation" do
|
42
|
+
expect { copy["m"] = "m" }.not_to raise_error
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
shared_examples_for "ImmutableArray module" do |param|
|
47
|
+
let(:copy) { @immutable_nested_array.send(param) }
|
48
|
+
|
49
|
+
it "converts an immutable array to a new mutable array" do
|
50
|
+
expect(copy).to be_instance_of(Array)
|
51
|
+
end
|
52
|
+
|
53
|
+
it "converts an immutable nested array to a new mutable array" do
|
54
|
+
expect(copy[1]).to be_instance_of(Array)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "converts an immutable nested mash to a new mutable hash" do
|
58
|
+
expect(copy[2]).to be_is_a(Hash)
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should create an array with the same content" do
|
62
|
+
expect(copy).to eq(@immutable_nested_array)
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should allow mutation" do
|
66
|
+
expect { copy << "m" }.not_to raise_error
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
shared_examples_for "Immutable#to_yaml" do
|
71
|
+
it "converts an immutable array to a new valid YAML mutable string" do
|
72
|
+
expect { YAML.parse(copy) }.not_to raise_error
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should create a YAML string with content" do
|
76
|
+
expect(copy).to eq(parsed_yaml)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
22
80
|
describe Chef::Node::ImmutableMash do
|
23
81
|
before do
|
24
82
|
@data_in = { "top" => { "second_level" => "some value" },
|
@@ -67,82 +125,17 @@ describe Chef::Node::ImmutableMash do
|
|
67
125
|
expect(@mash["test2"]).to eql("bar")
|
68
126
|
end
|
69
127
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
end
|
74
|
-
|
75
|
-
it "converts an immutable mash to a new mutable hash" do
|
76
|
-
expect(@copy).to be_instance_of(Hash)
|
77
|
-
end
|
78
|
-
|
79
|
-
it "converts an immutable nested mash to a new mutable hash" do
|
80
|
-
expect(@copy["top_level_4"]["level2"]).to be_instance_of(Hash)
|
81
|
-
end
|
82
|
-
|
83
|
-
it "converts an immutable nested array to a new mutable array" do
|
84
|
-
expect(@copy["top_level_2"]).to be_instance_of(Array)
|
85
|
-
end
|
86
|
-
|
87
|
-
it "should create a mash with the same content" do
|
88
|
-
expect(@copy).to eq(@immutable_mash)
|
89
|
-
end
|
90
|
-
|
91
|
-
it "should allow mutation" do
|
92
|
-
expect { @copy["m"] = "m" }.not_to raise_error
|
128
|
+
%w{to_h to_hash dup}.each do |immutable_meth|
|
129
|
+
describe "#{immutable_meth}" do
|
130
|
+
include_examples "ImmutableMash module", description
|
93
131
|
end
|
94
132
|
end
|
95
133
|
|
96
|
-
describe "
|
97
|
-
|
98
|
-
|
99
|
-
end
|
100
|
-
|
101
|
-
it "converts an immutable mash to a new mutable hash" do
|
102
|
-
expect(@copy).to be_instance_of(Mash)
|
103
|
-
end
|
104
|
-
|
105
|
-
it "converts an immutable nested mash to a new mutable hash" do
|
106
|
-
expect(@copy["top_level_4"]["level2"]).to be_instance_of(Mash)
|
107
|
-
end
|
108
|
-
|
109
|
-
it "converts an immutable nested array to a new mutable array" do
|
110
|
-
expect(@copy["top_level_2"]).to be_instance_of(Array)
|
111
|
-
end
|
112
|
-
|
113
|
-
it "should create a mash with the same content" do
|
114
|
-
expect(@copy).to eq(@immutable_mash)
|
115
|
-
end
|
134
|
+
describe "to_yaml" do
|
135
|
+
let(:copy) { @immutable_mash.to_yaml }
|
136
|
+
let(:parsed_yaml) { "---\ntop:\n second_level: some value\ntop_level_2:\n- array\n- of\n- values\ntop_level_3:\n- hash_array: 1\n hash_array_b: 2\ntop_level_4:\n level2:\n key: value\n" }
|
116
137
|
|
117
|
-
|
118
|
-
expect { @copy["m"] = "m" }.not_to raise_error
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
describe "to_h" do
|
123
|
-
before do
|
124
|
-
@copy = @immutable_mash.to_h
|
125
|
-
end
|
126
|
-
|
127
|
-
it "converts an immutable mash to a new mutable hash" do
|
128
|
-
expect(@copy).to be_instance_of(Hash)
|
129
|
-
end
|
130
|
-
|
131
|
-
it "converts an immutable nested mash to a new mutable hash" do
|
132
|
-
expect(@copy["top_level_4"]["level2"]).to be_instance_of(Hash)
|
133
|
-
end
|
134
|
-
|
135
|
-
it "converts an immutable nested array to a new mutable array" do
|
136
|
-
expect(@copy["top_level_2"]).to be_instance_of(Array)
|
137
|
-
end
|
138
|
-
|
139
|
-
it "should create a mash with the same content" do
|
140
|
-
expect(@copy).to eq(@immutable_mash)
|
141
|
-
end
|
142
|
-
|
143
|
-
it "should allow mutation" do
|
144
|
-
expect { @copy["m"] = "m" }.not_to raise_error
|
145
|
-
end
|
138
|
+
include_examples "Immutable#to_yaml"
|
146
139
|
end
|
147
140
|
|
148
141
|
%i{
|
@@ -240,82 +233,17 @@ describe Chef::Node::ImmutableArray do
|
|
240
233
|
expect(mutable[0]).to eq(:value)
|
241
234
|
end
|
242
235
|
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
end
|
247
|
-
|
248
|
-
it "converts an immutable array to a new mutable array" do
|
249
|
-
expect(@copy).to be_instance_of(Array)
|
250
|
-
end
|
251
|
-
|
252
|
-
it "converts an immutable nested array to a new mutable array" do
|
253
|
-
expect(@copy[1]).to be_instance_of(Array)
|
254
|
-
end
|
255
|
-
|
256
|
-
it "converts an immutable nested mash to a new mutable hash" do
|
257
|
-
expect(@copy[2]).to be_instance_of(Hash)
|
258
|
-
end
|
259
|
-
|
260
|
-
it "should create an array with the same content" do
|
261
|
-
expect(@copy).to eq(@immutable_nested_array)
|
262
|
-
end
|
263
|
-
|
264
|
-
it "should allow mutation" do
|
265
|
-
expect { @copy << "m" }.not_to raise_error
|
236
|
+
%w{to_a to_array dup}.each do |immutable_meth|
|
237
|
+
describe "#{immutable_meth}" do
|
238
|
+
include_examples "ImmutableArray module", description
|
266
239
|
end
|
267
240
|
end
|
268
241
|
|
269
|
-
describe "
|
270
|
-
|
271
|
-
|
272
|
-
end
|
273
|
-
|
274
|
-
it "converts an immutable array to a new mutable array" do
|
275
|
-
expect(@copy).to be_instance_of(Array)
|
276
|
-
end
|
277
|
-
|
278
|
-
it "converts an immutable nested array to a new mutable array" do
|
279
|
-
expect(@copy[1]).to be_instance_of(Array)
|
280
|
-
end
|
281
|
-
|
282
|
-
it "converts an immutable nested mash to a new mutable hash" do
|
283
|
-
expect(@copy[2]).to be_instance_of(Mash)
|
284
|
-
end
|
285
|
-
|
286
|
-
it "should create an array with the same content" do
|
287
|
-
expect(@copy).to eq(@immutable_nested_array)
|
288
|
-
end
|
289
|
-
|
290
|
-
it "should allow mutation" do
|
291
|
-
expect { @copy << "m" }.not_to raise_error
|
292
|
-
end
|
293
|
-
end
|
242
|
+
describe "to_yaml" do
|
243
|
+
let(:copy) { @immutable_nested_array.to_yaml }
|
244
|
+
let(:parsed_yaml) { "---\n- level1\n- - foo\n - bar\n - baz\n - 1\n - 2\n - 3\n - \n - true\n - false\n - - el\n - 0\n - \n- m: m\n" }
|
294
245
|
|
295
|
-
|
296
|
-
before do
|
297
|
-
@copy = @immutable_nested_array.to_array
|
298
|
-
end
|
299
|
-
|
300
|
-
it "converts an immutable array to a new mutable array" do
|
301
|
-
expect(@copy).to be_instance_of(Array)
|
302
|
-
end
|
303
|
-
|
304
|
-
it "converts an immutable nested array to a new mutable array" do
|
305
|
-
expect(@copy[1]).to be_instance_of(Array)
|
306
|
-
end
|
307
|
-
|
308
|
-
it "converts an immutable nested mash to a new mutable hash" do
|
309
|
-
expect(@copy[2]).to be_instance_of(Hash)
|
310
|
-
end
|
311
|
-
|
312
|
-
it "should create an array with the same content" do
|
313
|
-
expect(@copy).to eq(@immutable_nested_array)
|
314
|
-
end
|
315
|
-
|
316
|
-
it "should allow mutation" do
|
317
|
-
expect { @copy << "m" }.not_to raise_error
|
318
|
-
end
|
246
|
+
include_examples "Immutable#to_yaml"
|
319
247
|
end
|
320
248
|
|
321
249
|
describe "#[]" do
|