chef 12.4.3 → 12.5.0.alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Rakefile +1 -2
- data/lib/chef.rb +1 -1
- data/lib/chef/application/solo.rb +1 -1
- data/lib/chef/application/windows_service_manager.rb +17 -12
- data/lib/chef/chef_class.rb +7 -0
- data/lib/chef/chef_fs/config.rb +22 -24
- data/lib/chef/chef_fs/file_pattern.rb +4 -15
- data/lib/chef/chef_fs/file_system/cookbook_dir.rb +1 -0
- data/lib/chef/chef_fs/knife.rb +35 -7
- data/lib/chef/chef_fs/path_utils.rb +65 -34
- data/lib/chef/constants.rb +27 -0
- data/lib/chef/delayed_evaluator.rb +21 -0
- data/lib/chef/dsl/recipe.rb +20 -2
- data/lib/chef/event_dispatch/base.rb +40 -16
- data/lib/chef/event_dispatch/dsl.rb +64 -0
- data/lib/chef/exceptions.rb +6 -1
- data/lib/chef/formatters/doc.rb +3 -1
- data/lib/chef/guard_interpreter/resource_guard_interpreter.rb +3 -1
- data/lib/chef/http/http_request.rb +1 -1
- data/lib/chef/knife/bootstrap/templates/chef-full.erb +1 -1
- data/lib/chef/knife/ssl_check.rb +3 -2
- data/lib/chef/knife/user_edit.rb +1 -2
- data/lib/chef/mixin/params_validate.rb +362 -135
- data/lib/chef/node.rb +19 -0
- data/lib/chef/platform/handler_map.rb +0 -5
- data/lib/chef/platform/rebooter.rb +1 -1
- data/lib/chef/property.rb +539 -0
- data/lib/chef/provider.rb +129 -12
- data/lib/chef/provider/deploy.rb +3 -5
- data/lib/chef/provider/lwrp_base.rb +1 -75
- data/lib/chef/provider/package.rb +1 -1
- data/lib/chef/provider/powershell_script.rb +32 -19
- data/lib/chef/provider/registry_key.rb +5 -5
- data/lib/chef/provider/service/macosx.rb +5 -1
- data/lib/chef/recipe.rb +1 -8
- data/lib/chef/resource.rb +499 -84
- data/lib/chef/resource/file/verification.rb +7 -1
- data/lib/chef/resource/lwrp_base.rb +1 -7
- data/lib/chef/run_context.rb +404 -83
- data/lib/chef/version.rb +1 -1
- data/lib/chef/win32/registry.rb +10 -2
- data/lib/chef/workstation_config_loader.rb +3 -158
- data/spec/data/run_context/cookbooks/include/recipes/default.rb +24 -0
- data/spec/data/run_context/cookbooks/include/recipes/includee.rb +3 -0
- data/spec/functional/rebooter_spec.rb +1 -1
- data/spec/functional/resource/{powershell_spec.rb → powershell_script_spec.rb} +3 -3
- data/spec/functional/win32/registry_helper_spec.rb +12 -0
- data/spec/functional/win32/service_manager_spec.rb +2 -2
- data/spec/integration/knife/chef_repo_path_spec.rb +13 -11
- data/spec/integration/recipes/recipe_dsl_spec.rb +0 -15
- data/spec/integration/recipes/resource_action_spec.rb +343 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/support/shared/functional/win32_service.rb +2 -1
- data/spec/unit/application/solo_spec.rb +4 -3
- data/spec/unit/chef_class_spec.rb +23 -0
- data/spec/unit/chef_fs/path_util_spec.rb +108 -0
- data/spec/unit/event_dispatch/dsl_spec.rb +87 -0
- data/spec/unit/json_compat_spec.rb +4 -3
- data/spec/unit/knife/ssl_check_spec.rb +4 -0
- data/spec/unit/mixin/params_validate_spec.rb +4 -2
- data/spec/unit/node_spec.rb +7 -0
- data/spec/unit/property/state_spec.rb +506 -0
- data/spec/unit/property/validation_spec.rb +658 -0
- data/spec/unit/property_spec.rb +968 -0
- data/spec/unit/provider/{powershell_spec.rb → powershell_script_spec.rb} +0 -0
- data/spec/unit/provider/registry_key_spec.rb +12 -0
- data/spec/unit/provider/service/macosx_spec.rb +4 -4
- data/spec/unit/provider_spec.rb +1 -3
- data/spec/unit/recipe_spec.rb +0 -4
- data/spec/unit/registry_helper_spec.rb +15 -1
- data/spec/unit/resource/file/verification_spec.rb +33 -5
- data/spec/unit/resource/{powershell_spec.rb → powershell_script_spec.rb} +0 -0
- data/spec/unit/resource_spec.rb +2 -2
- data/spec/unit/run_context/child_run_context_spec.rb +133 -0
- data/spec/unit/run_context_spec.rb +7 -0
- metadata +25 -25
- data/spec/unit/workstation_config_loader_spec.rb +0 -283
@@ -0,0 +1,87 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Ranjib Dey (<ranjib@linux.com>)
|
3
|
+
#
|
4
|
+
# Copyright:: Copyright (c) 2015 Ranjib Dey
|
5
|
+
# License:: Apache License, Version 2.0
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
#
|
19
|
+
require 'spec_helper'
|
20
|
+
require 'chef/event_dispatch/dsl'
|
21
|
+
|
22
|
+
describe Chef::EventDispatch::DSL do
|
23
|
+
let(:events) do
|
24
|
+
Chef::EventDispatch::Dispatcher.new
|
25
|
+
end
|
26
|
+
|
27
|
+
let(:run_context) do
|
28
|
+
Chef::RunContext.new(Chef::Node.new, nil, events)
|
29
|
+
end
|
30
|
+
|
31
|
+
before do
|
32
|
+
Chef.set_run_context(run_context)
|
33
|
+
end
|
34
|
+
|
35
|
+
after do
|
36
|
+
Chef.reset!
|
37
|
+
end
|
38
|
+
|
39
|
+
subject{ described_class.new('test') }
|
40
|
+
|
41
|
+
it 'set handler name' do
|
42
|
+
subject.on(:run_started) {}
|
43
|
+
expect(events.subscribers.first.name).to eq('test')
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'raise error when invalid event type is supplied' do
|
47
|
+
expect do
|
48
|
+
subject.on(:foo_bar) {}
|
49
|
+
end.to raise_error(Chef::Exceptions::InvalidEventType)
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'register user hooks against valid event type' do
|
53
|
+
subject.on(:run_failed) {'testhook'}
|
54
|
+
expect(events.subscribers.first.run_failed).to eq('testhook')
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'preserve state across event hooks' do
|
58
|
+
calls = []
|
59
|
+
Chef.event_handler do
|
60
|
+
on :resource_updated do
|
61
|
+
calls << :updated
|
62
|
+
end
|
63
|
+
on :resource_action_start do
|
64
|
+
calls << :started
|
65
|
+
end
|
66
|
+
end
|
67
|
+
resource = Chef::Resource::RubyBlock.new('foo', run_context)
|
68
|
+
resource.block { }
|
69
|
+
resource.run_action(:run)
|
70
|
+
expect(calls).to eq([:started, :updated])
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'preserve instance variables across handler callbacks' do
|
74
|
+
Chef.event_handler do
|
75
|
+
on :resource_action_start do
|
76
|
+
@ivar = [1]
|
77
|
+
end
|
78
|
+
on :resource_updated do
|
79
|
+
@ivar << 2
|
80
|
+
end
|
81
|
+
end
|
82
|
+
resource = Chef::Resource::RubyBlock.new('foo', run_context)
|
83
|
+
resource.block { }
|
84
|
+
resource.run_action(:run)
|
85
|
+
expect(events.subscribers.first.instance_variable_get(:@ivar)).to eq([1, 2])
|
86
|
+
end
|
87
|
+
end
|
@@ -72,8 +72,6 @@ describe Chef::JSONCompat do
|
|
72
72
|
end
|
73
73
|
end
|
74
74
|
|
75
|
-
# On FreeBSD 10.1 i386 rspec fails with a SystemStackError loading the expect line with more that 252 entries
|
76
|
-
# https://github.com/chef/chef/issues/3101
|
77
75
|
describe "with the file with 252 or less nested entries" do
|
78
76
|
let(:json) { IO.read(File.join(CHEF_SPEC_DATA, 'nested.json')) }
|
79
77
|
let(:hash) { Chef::JSONCompat.from_json(json) }
|
@@ -84,7 +82,10 @@ describe Chef::JSONCompat do
|
|
84
82
|
end
|
85
83
|
|
86
84
|
it "should has 'test' as a 252 nested value" do
|
87
|
-
|
85
|
+
v = 252.times.inject(hash) do |memo, _|
|
86
|
+
memo['key']
|
87
|
+
end
|
88
|
+
expect(v).to eq('test')
|
88
89
|
end
|
89
90
|
end
|
90
91
|
end
|
@@ -163,6 +163,7 @@ E
|
|
163
163
|
expect(ssl_check).to receive(:verify_X509).and_return(true) # X509 valid certs (no warn)
|
164
164
|
expect(ssl_socket).to receive(:connect) # no error
|
165
165
|
expect(ssl_socket).to receive(:post_connection_check).with("foo.example.com") # no error
|
166
|
+
expect(ssl_socket).to receive(:hostname=).with("foo.example.com") # no error
|
166
167
|
end
|
167
168
|
|
168
169
|
it "prints a success message" do
|
@@ -197,6 +198,7 @@ E
|
|
197
198
|
expect(ssl_socket).to receive(:post_connection_check).
|
198
199
|
with("foo.example.com").
|
199
200
|
and_raise(OpenSSL::SSL::SSLError)
|
201
|
+
expect(ssl_socket).to receive(:hostname=).with("foo.example.com") # no error
|
200
202
|
expect(ssl_socket_for_debug).to receive(:connect)
|
201
203
|
expect(ssl_socket_for_debug).to receive(:peer_cert).and_return(self_signed_crt)
|
202
204
|
end
|
@@ -215,6 +217,8 @@ E
|
|
215
217
|
expect(ssl_check).to receive(:verify_X509).and_return(true) # X509 valid certs
|
216
218
|
expect(ssl_socket).to receive(:connect).
|
217
219
|
and_raise(OpenSSL::SSL::SSLError)
|
220
|
+
expect(ssl_socket).to receive(:hostname=).
|
221
|
+
with("foo.example.com") # no error
|
218
222
|
expect(ssl_socket_for_debug).to receive(:connect)
|
219
223
|
expect(ssl_socket_for_debug).to receive(:peer_cert).and_return(self_signed_crt)
|
220
224
|
end
|
@@ -21,6 +21,8 @@ require 'spec_helper'
|
|
21
21
|
class TinyClass
|
22
22
|
include Chef::Mixin::ParamsValidate
|
23
23
|
|
24
|
+
attr_reader :name
|
25
|
+
|
24
26
|
def music(is_good=true)
|
25
27
|
is_good
|
26
28
|
end
|
@@ -331,11 +333,11 @@ describe Chef::Mixin::ParamsValidate do
|
|
331
333
|
it "asserts that a value returns false from a predicate method" do
|
332
334
|
expect do
|
333
335
|
@vo.validate({:not_blank => "should pass"},
|
334
|
-
{:not_blank => {:cannot_be => :nil, :
|
336
|
+
{:not_blank => {:cannot_be => [ :nil, :empty ]}})
|
335
337
|
end.not_to raise_error
|
336
338
|
expect do
|
337
339
|
@vo.validate({:not_blank => ""},
|
338
|
-
{:not_blank => {:cannot_be => :nil, :
|
340
|
+
{:not_blank => {:cannot_be => [ :nil, :empty ]}})
|
339
341
|
end.to raise_error(Chef::Exceptions::ValidationFailed)
|
340
342
|
end
|
341
343
|
|
data/spec/unit/node_spec.rb
CHANGED
@@ -672,6 +672,13 @@ describe Chef::Node do
|
|
672
672
|
expect(node.run_list).to eq([ "role[base]", "recipe[chef::server]" ])
|
673
673
|
end
|
674
674
|
|
675
|
+
it "sets the node chef_environment" do
|
676
|
+
attrs = { "chef_environment" => "foo_environment", "bar" => "baz" }
|
677
|
+
expect(node.consume_chef_environment(attrs)).to eq({ "bar" => "baz" })
|
678
|
+
expect(node.chef_environment).to eq("foo_environment")
|
679
|
+
expect(node['chef_environment']).to be nil
|
680
|
+
end
|
681
|
+
|
675
682
|
it "should overwrites the run list with the run list it consumes" do
|
676
683
|
node.consume_run_list "recipes" => [ "one", "two" ]
|
677
684
|
node.consume_run_list "recipes" => [ "three" ]
|
@@ -0,0 +1,506 @@
|
|
1
|
+
require 'support/shared/integration/integration_helper'
|
2
|
+
|
3
|
+
describe "Chef::Resource#identity and #state" do
|
4
|
+
include IntegrationSupport
|
5
|
+
|
6
|
+
class NewResourceNamer
|
7
|
+
@i = 0
|
8
|
+
def self.next
|
9
|
+
"chef_resource_property_spec_#{@i += 1}"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.new_resource_name
|
14
|
+
NewResourceNamer.next
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:resource_class) do
|
18
|
+
new_resource_name = self.class.new_resource_name
|
19
|
+
Class.new(Chef::Resource) do
|
20
|
+
resource_name new_resource_name
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
let(:resource) do
|
25
|
+
resource_class.new("blah")
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.english_join(values)
|
29
|
+
return '<nothing>' if values.size == 0
|
30
|
+
return values[0].inspect if values.size == 1
|
31
|
+
"#{values[0..-2].map { |v| v.inspect }.join(", ")} and #{values[-1].inspect}"
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.with_property(*properties, &block)
|
35
|
+
tags_index = properties.find_index { |p| !p.is_a?(String)}
|
36
|
+
if tags_index
|
37
|
+
properties, tags = properties[0..tags_index-1], properties[tags_index..-1]
|
38
|
+
else
|
39
|
+
tags = []
|
40
|
+
end
|
41
|
+
properties = properties.map { |property| "property #{property}" }
|
42
|
+
context "With properties #{english_join(properties)}", *tags do
|
43
|
+
before do
|
44
|
+
properties.each do |property_str|
|
45
|
+
resource_class.class_eval(property_str, __FILE__, __LINE__)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
instance_eval(&block)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# identity
|
53
|
+
context "Chef::Resource#identity_properties" do
|
54
|
+
with_property ":x" do
|
55
|
+
it "name is the default identity" do
|
56
|
+
expect(resource_class.identity_properties).to eq [ Chef::Resource.properties[:name] ]
|
57
|
+
expect(Chef::Resource.properties[:name].identity?).to be_falsey
|
58
|
+
expect(resource.name).to eq 'blah'
|
59
|
+
expect(resource.identity).to eq 'blah'
|
60
|
+
end
|
61
|
+
|
62
|
+
it "identity_properties :x changes the identity" do
|
63
|
+
expect(resource_class.identity_properties :x).to eq [ resource_class.properties[:x] ]
|
64
|
+
expect(resource_class.identity_properties).to eq [ resource_class.properties[:x] ]
|
65
|
+
expect(Chef::Resource.properties[:name].identity?).to be_falsey
|
66
|
+
expect(resource_class.properties[:x].identity?).to be_truthy
|
67
|
+
|
68
|
+
expect(resource.x 'woo').to eq 'woo'
|
69
|
+
expect(resource.x).to eq 'woo'
|
70
|
+
|
71
|
+
expect(resource.name).to eq 'blah'
|
72
|
+
expect(resource.identity).to eq 'woo'
|
73
|
+
end
|
74
|
+
|
75
|
+
with_property ":y, identity: true" do
|
76
|
+
context "and identity_properties :x" do
|
77
|
+
before do
|
78
|
+
resource_class.class_eval do
|
79
|
+
identity_properties :x
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
it "only returns :x as identity" do
|
84
|
+
resource.x 'foo'
|
85
|
+
resource.y 'bar'
|
86
|
+
expect(resource_class.identity_properties).to eq [ resource_class.properties[:x] ]
|
87
|
+
expect(resource.identity).to eq 'foo'
|
88
|
+
end
|
89
|
+
it "does not flip y.desired_state off" do
|
90
|
+
resource.x 'foo'
|
91
|
+
resource.y 'bar'
|
92
|
+
expect(resource_class.state_properties).to eq [
|
93
|
+
resource_class.properties[:x],
|
94
|
+
resource_class.properties[:y]
|
95
|
+
]
|
96
|
+
expect(resource.state_for_resource_reporter).to eq(x: 'foo', y: 'bar')
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
context "With a subclass" do
|
102
|
+
let(:subresource_class) do
|
103
|
+
new_resource_name = self.class.new_resource_name
|
104
|
+
Class.new(resource_class) do
|
105
|
+
resource_name new_resource_name
|
106
|
+
end
|
107
|
+
end
|
108
|
+
let(:subresource) do
|
109
|
+
subresource_class.new('sub')
|
110
|
+
end
|
111
|
+
|
112
|
+
it "name is the default identity on the subclass" do
|
113
|
+
expect(subresource_class.identity_properties).to eq [ Chef::Resource.properties[:name] ]
|
114
|
+
expect(Chef::Resource.properties[:name].identity?).to be_falsey
|
115
|
+
expect(subresource.name).to eq 'sub'
|
116
|
+
expect(subresource.identity).to eq 'sub'
|
117
|
+
end
|
118
|
+
|
119
|
+
context "With identity_properties :x on the superclass" do
|
120
|
+
before do
|
121
|
+
resource_class.class_eval do
|
122
|
+
identity_properties :x
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
it "The subclass inherits :x as identity" do
|
127
|
+
expect(subresource_class.identity_properties).to eq [ subresource_class.properties[:x] ]
|
128
|
+
expect(Chef::Resource.properties[:name].identity?).to be_falsey
|
129
|
+
expect(subresource_class.properties[:x].identity?).to be_truthy
|
130
|
+
|
131
|
+
subresource.x 'foo'
|
132
|
+
expect(subresource.identity).to eq 'foo'
|
133
|
+
end
|
134
|
+
|
135
|
+
context "With property :y, identity: true on the subclass" do
|
136
|
+
before do
|
137
|
+
subresource_class.class_eval do
|
138
|
+
property :y, identity: true
|
139
|
+
end
|
140
|
+
end
|
141
|
+
it "The subclass's identity includes both x and y" do
|
142
|
+
expect(subresource_class.identity_properties).to eq [
|
143
|
+
subresource_class.properties[:x],
|
144
|
+
subresource_class.properties[:y]
|
145
|
+
]
|
146
|
+
subresource.x 'foo'
|
147
|
+
subresource.y 'bar'
|
148
|
+
expect(subresource.identity).to eq(x: 'foo', y: 'bar')
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
with_property ":y, String" do
|
153
|
+
context "With identity_properties :y on the subclass" do
|
154
|
+
before do
|
155
|
+
subresource_class.class_eval do
|
156
|
+
identity_properties :y
|
157
|
+
end
|
158
|
+
end
|
159
|
+
it "y is part of state" do
|
160
|
+
subresource.x 'foo'
|
161
|
+
subresource.y 'bar'
|
162
|
+
expect(subresource.state_for_resource_reporter).to eq(x: 'foo', y: 'bar')
|
163
|
+
expect(subresource_class.state_properties).to eq [
|
164
|
+
subresource_class.properties[:x],
|
165
|
+
subresource_class.properties[:y]
|
166
|
+
]
|
167
|
+
end
|
168
|
+
it "y is the identity" do
|
169
|
+
expect(subresource_class.identity_properties).to eq [ subresource_class.properties[:y] ]
|
170
|
+
subresource.x 'foo'
|
171
|
+
subresource.y 'bar'
|
172
|
+
expect(subresource.identity).to eq 'bar'
|
173
|
+
end
|
174
|
+
it "y still has validation" do
|
175
|
+
expect { subresource.y 12 }.to raise_error Chef::Exceptions::ValidationFailed
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
with_property ":string_only, String, identity: true", ":string_only2, String" do
|
184
|
+
it "identity_properties does not change validation" do
|
185
|
+
resource_class.identity_properties :string_only
|
186
|
+
expect { resource.string_only 12 }.to raise_error Chef::Exceptions::ValidationFailed
|
187
|
+
expect { resource.string_only2 12 }.to raise_error Chef::Exceptions::ValidationFailed
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
with_property ":x, desired_state: false" do
|
192
|
+
it "identity_properties does not change desired_state" do
|
193
|
+
resource_class.identity_properties :x
|
194
|
+
resource.x 'hi'
|
195
|
+
expect(resource.identity).to eq 'hi'
|
196
|
+
expect(resource_class.properties[:x].desired_state?).to be_falsey
|
197
|
+
expect(resource_class.state_properties).to eq []
|
198
|
+
expect(resource.state_for_resource_reporter).to eq({})
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
context "With custom property custom_property defined only as methods, using different variables for storage" do
|
203
|
+
before do
|
204
|
+
resource_class.class_eval do
|
205
|
+
def custom_property
|
206
|
+
@blarghle ? @blarghle*3 : nil
|
207
|
+
end
|
208
|
+
def custom_property=(x)
|
209
|
+
@blarghle = x*2
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
context "And identity_properties :custom_property" do
|
215
|
+
before do
|
216
|
+
resource_class.class_eval do
|
217
|
+
identity_properties :custom_property
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
it "identity_properties comes back as :custom_property" do
|
222
|
+
expect(resource_class.properties[:custom_property].identity?).to be_truthy
|
223
|
+
expect(resource_class.identity_properties).to eq [ resource_class.properties[:custom_property] ]
|
224
|
+
end
|
225
|
+
it "custom_property becomes part of desired_state" do
|
226
|
+
resource.custom_property = 1
|
227
|
+
expect(resource.state_for_resource_reporter).to eq(custom_property: 6)
|
228
|
+
expect(resource_class.properties[:custom_property].desired_state?).to be_truthy
|
229
|
+
expect(resource_class.state_properties).to eq [
|
230
|
+
resource_class.properties[:custom_property]
|
231
|
+
]
|
232
|
+
end
|
233
|
+
it "identity_properties does not change custom_property's getter or setter" do
|
234
|
+
resource.custom_property = 1
|
235
|
+
expect(resource.custom_property).to eq 6
|
236
|
+
end
|
237
|
+
it "custom_property is returned as the identity" do
|
238
|
+
expect(resource.identity).to be_nil
|
239
|
+
resource.custom_property = 1
|
240
|
+
expect(resource.identity).to eq 6
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
context "Property#identity" do
|
247
|
+
with_property ":x, identity: true" do
|
248
|
+
it "name is only part of the identity if an identity attribute is defined" do
|
249
|
+
expect(resource_class.identity_properties).to eq [ resource_class.properties[:x] ]
|
250
|
+
resource.x 'woo'
|
251
|
+
expect(resource.identity).to eq 'woo'
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
with_property ":x, identity: true, default: 'xxx'",
|
256
|
+
":y, identity: true, default: 'yyy'",
|
257
|
+
":z, identity: true, default: 'zzz'" do
|
258
|
+
it "identity_property raises an error if multiple identity values are defined" do
|
259
|
+
expect { resource_class.identity_property }.to raise_error Chef::Exceptions::MultipleIdentityError
|
260
|
+
end
|
261
|
+
it "identity_attr raises an error if multiple identity values are defined" do
|
262
|
+
expect { resource_class.identity_attr }.to raise_error Chef::Exceptions::MultipleIdentityError
|
263
|
+
end
|
264
|
+
it "identity returns all identity values in a hash if multiple are defined" do
|
265
|
+
resource.x 'foo'
|
266
|
+
resource.y 'bar'
|
267
|
+
resource.z 'baz'
|
268
|
+
expect(resource.identity).to eq(x: 'foo', y: 'bar', z: 'baz')
|
269
|
+
end
|
270
|
+
it "identity returns all values whether any value is set or not" do
|
271
|
+
expect(resource.identity).to eq(x: 'xxx', y: 'yyy', z: 'zzz')
|
272
|
+
end
|
273
|
+
it "identity_properties wipes out any other identity attributes if multiple are defined" do
|
274
|
+
resource_class.identity_properties :y
|
275
|
+
resource.x 'foo'
|
276
|
+
resource.y 'bar'
|
277
|
+
resource.z 'baz'
|
278
|
+
expect(resource.identity).to eq 'bar'
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
with_property ":x, identity: true, name_property: true" do
|
283
|
+
it "identity when x is not defined returns the value of x" do
|
284
|
+
expect(resource.identity).to eq 'blah'
|
285
|
+
end
|
286
|
+
it "state when x is not defined returns the value of x" do
|
287
|
+
expect(resource.state_for_resource_reporter).to eq(x: 'blah')
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
# state_properties
|
293
|
+
context "Chef::Resource#state_properties" do
|
294
|
+
it "state_properties is empty by default" do
|
295
|
+
expect(Chef::Resource.state_properties).to eq []
|
296
|
+
expect(resource.state_for_resource_reporter).to eq({})
|
297
|
+
end
|
298
|
+
|
299
|
+
with_property ":x", ":y", ":z" do
|
300
|
+
it "x, y and z are state attributes" do
|
301
|
+
resource.x 1
|
302
|
+
resource.y 2
|
303
|
+
resource.z 3
|
304
|
+
expect(resource_class.state_properties).to eq [
|
305
|
+
resource_class.properties[:x],
|
306
|
+
resource_class.properties[:y],
|
307
|
+
resource_class.properties[:z]
|
308
|
+
]
|
309
|
+
expect(resource.state_for_resource_reporter).to eq(x: 1, y: 2, z: 3)
|
310
|
+
end
|
311
|
+
it "values that are not set are not included in state" do
|
312
|
+
resource.x 1
|
313
|
+
expect(resource.state_for_resource_reporter).to eq(x: 1)
|
314
|
+
end
|
315
|
+
it "when no values are set, nothing is included in state" do
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
with_property ":x", ":y, desired_state: false", ":z, desired_state: true" do
|
320
|
+
it "x and z are state attributes, and y is not" do
|
321
|
+
resource.x 1
|
322
|
+
resource.y 2
|
323
|
+
resource.z 3
|
324
|
+
expect(resource_class.state_properties).to eq [
|
325
|
+
resource_class.properties[:x],
|
326
|
+
resource_class.properties[:z]
|
327
|
+
]
|
328
|
+
expect(resource.state_for_resource_reporter).to eq(x: 1, z: 3)
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
with_property ":x, name_property: true" do
|
333
|
+
# it "Unset values with name_property are included in state" do
|
334
|
+
# expect(resource.state_for_resource_reporter).to eq({ x: 'blah' })
|
335
|
+
# end
|
336
|
+
it "Set values with name_property are included in state" do
|
337
|
+
resource.x 1
|
338
|
+
expect(resource.state_for_resource_reporter).to eq(x: 1)
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
with_property ":x, default: 1" do
|
343
|
+
it "Unset values with defaults are not included in state" do
|
344
|
+
expect(resource.state_for_resource_reporter).to eq({})
|
345
|
+
end
|
346
|
+
it "Set values with defaults are included in state" do
|
347
|
+
resource.x 1
|
348
|
+
expect(resource.state_for_resource_reporter).to eq(x: 1)
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
context "With a class with a normal getter and setter" do
|
353
|
+
before do
|
354
|
+
resource_class.class_eval do
|
355
|
+
def x
|
356
|
+
@blah*3
|
357
|
+
end
|
358
|
+
def x=(value)
|
359
|
+
@blah = value*2
|
360
|
+
end
|
361
|
+
end
|
362
|
+
end
|
363
|
+
it "state_properties(:x) causes the value to be included in properties" do
|
364
|
+
resource_class.state_properties(:x)
|
365
|
+
resource.x = 1
|
366
|
+
|
367
|
+
expect(resource.x).to eq 6
|
368
|
+
expect(resource.state_for_resource_reporter).to eq(x: 6)
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
context "When state_properties happens before properties are declared" do
|
373
|
+
before do
|
374
|
+
resource_class.class_eval do
|
375
|
+
state_properties :x
|
376
|
+
property :x
|
377
|
+
end
|
378
|
+
end
|
379
|
+
it "the property works and is in state_properties" do
|
380
|
+
expect(resource_class.state_properties).to include(resource_class.properties[:x])
|
381
|
+
resource.x = 1
|
382
|
+
expect(resource.x).to eq 1
|
383
|
+
expect(resource.state_for_resource_reporter).to eq(x: 1)
|
384
|
+
end
|
385
|
+
end
|
386
|
+
|
387
|
+
with_property ":x, Integer, identity: true" do
|
388
|
+
it "state_properties(:x) leaves the property in desired_state" do
|
389
|
+
resource_class.state_properties(:x)
|
390
|
+
resource.x 10
|
391
|
+
|
392
|
+
expect(resource_class.properties[:x].desired_state?).to be_truthy
|
393
|
+
expect(resource_class.state_properties).to eq [
|
394
|
+
resource_class.properties[:x]
|
395
|
+
]
|
396
|
+
expect(resource.state_for_resource_reporter).to eq(x: 10)
|
397
|
+
end
|
398
|
+
it "state_properties(:x) does not turn off validation" do
|
399
|
+
resource_class.state_properties(:x)
|
400
|
+
expect { resource.x 'ouch' }.to raise_error Chef::Exceptions::ValidationFailed
|
401
|
+
end
|
402
|
+
it "state_properties(:x) does not turn off identity" do
|
403
|
+
resource_class.state_properties(:x)
|
404
|
+
resource.x 10
|
405
|
+
|
406
|
+
expect(resource_class.identity_properties).to eq [ resource_class.properties[:x] ]
|
407
|
+
expect(resource_class.properties[:x].identity?).to be_truthy
|
408
|
+
expect(resource.identity).to eq 10
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
with_property ":x, Integer, identity: true, desired_state: false" do
|
413
|
+
before do
|
414
|
+
resource_class.class_eval do
|
415
|
+
def y
|
416
|
+
20
|
417
|
+
end
|
418
|
+
end
|
419
|
+
end
|
420
|
+
|
421
|
+
it "state_properties(:x) leaves x identical" do
|
422
|
+
old_value = resource_class.properties[:y]
|
423
|
+
resource_class.state_properties(:x)
|
424
|
+
resource.x 10
|
425
|
+
|
426
|
+
expect(resource_class.properties[:y].object_id).to eq old_value.object_id
|
427
|
+
|
428
|
+
expect(resource_class.properties[:x].desired_state?).to be_truthy
|
429
|
+
expect(resource_class.properties[:x].identity?).to be_truthy
|
430
|
+
expect(resource_class.identity_properties).to eq [
|
431
|
+
resource_class.properties[:x]
|
432
|
+
]
|
433
|
+
expect(resource.identity).to eq(10)
|
434
|
+
expect(resource_class.state_properties).to eq [
|
435
|
+
resource_class.properties[:x]
|
436
|
+
]
|
437
|
+
expect(resource.state_for_resource_reporter).to eq(x: 10)
|
438
|
+
end
|
439
|
+
|
440
|
+
it "state_properties(:y) adds y to desired state" do
|
441
|
+
old_value = resource_class.properties[:x]
|
442
|
+
resource_class.state_properties(:y)
|
443
|
+
resource.x 10
|
444
|
+
|
445
|
+
expect(resource_class.properties[:x].object_id).to eq old_value.object_id
|
446
|
+
expect(resource_class.properties[:x].desired_state?).to be_falsey
|
447
|
+
expect(resource_class.properties[:y].desired_state?).to be_truthy
|
448
|
+
expect(resource_class.state_properties).to eq [
|
449
|
+
resource_class.properties[:y]
|
450
|
+
]
|
451
|
+
expect(resource.state_for_resource_reporter).to eq(y: 20)
|
452
|
+
end
|
453
|
+
|
454
|
+
context "With a subclassed resource" do
|
455
|
+
let(:subresource_class) do
|
456
|
+
new_resource_name = self.class.new_resource_name
|
457
|
+
Class.new(resource_class) do
|
458
|
+
resource_name new_resource_name
|
459
|
+
end
|
460
|
+
end
|
461
|
+
let(:subresource) do
|
462
|
+
subresource_class.new('blah')
|
463
|
+
end
|
464
|
+
|
465
|
+
it "state_properties(:x) adds x to desired state" do
|
466
|
+
old_value = resource_class.properties[:y]
|
467
|
+
subresource_class.state_properties(:x)
|
468
|
+
subresource.x 10
|
469
|
+
|
470
|
+
expect(subresource_class.properties[:y].object_id).to eq old_value.object_id
|
471
|
+
|
472
|
+
expect(subresource_class.properties[:x].desired_state?).to be_truthy
|
473
|
+
expect(subresource_class.properties[:x].identity?).to be_truthy
|
474
|
+
expect(subresource_class.identity_properties).to eq [
|
475
|
+
subresource_class.properties[:x]
|
476
|
+
]
|
477
|
+
expect(subresource.identity).to eq(10)
|
478
|
+
expect(subresource_class.state_properties).to eq [
|
479
|
+
subresource_class.properties[:x]
|
480
|
+
]
|
481
|
+
expect(subresource.state_for_resource_reporter).to eq(x: 10)
|
482
|
+
end
|
483
|
+
|
484
|
+
it "state_properties(:y) adds y to desired state" do
|
485
|
+
old_value = resource_class.properties[:x]
|
486
|
+
subresource_class.state_properties(:y)
|
487
|
+
subresource.x 10
|
488
|
+
|
489
|
+
expect(subresource_class.properties[:x].object_id).to eq old_value.object_id
|
490
|
+
expect(subresource_class.properties[:y].desired_state?).to be_truthy
|
491
|
+
expect(subresource_class.state_properties).to eq [
|
492
|
+
subresource_class.properties[:y]
|
493
|
+
]
|
494
|
+
expect(subresource.state_for_resource_reporter).to eq(y: 20)
|
495
|
+
|
496
|
+
expect(subresource_class.properties[:x].identity?).to be_truthy
|
497
|
+
expect(subresource_class.identity_properties).to eq [
|
498
|
+
subresource_class.properties[:x]
|
499
|
+
]
|
500
|
+
expect(subresource.identity).to eq(10)
|
501
|
+
end
|
502
|
+
end
|
503
|
+
end
|
504
|
+
end
|
505
|
+
|
506
|
+
end
|