chef 15.2.20-universal-mingw32 → 15.3.14-universal-mingw32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -2
  3. data/chef.gemspec +3 -2
  4. data/lib/chef/application.rb +1 -1
  5. data/lib/chef/application/base.rb +7 -0
  6. data/lib/chef/application/client.rb +6 -2
  7. data/lib/chef/application/solo.rb +7 -1
  8. data/lib/chef/cookbook/gem_installer.rb +7 -2
  9. data/lib/chef/exceptions.rb +12 -0
  10. data/lib/chef/knife/bootstrap.rb +8 -1
  11. data/lib/chef/knife/bootstrap/templates/chef-full.erb +1 -1
  12. data/lib/chef/knife/bootstrap/train_connector.rb +3 -3
  13. data/lib/chef/knife/cookbook_metadata_from_file.rb +1 -1
  14. data/lib/chef/node.rb +0 -2
  15. data/lib/chef/policy_builder/expand_node_object.rb +1 -1
  16. data/lib/chef/policy_builder/policyfile.rb +4 -3
  17. data/lib/chef/provider.rb +4 -2
  18. data/lib/chef/provider/ifconfig.rb +5 -3
  19. data/lib/chef/provider/package/chocolatey.rb +12 -22
  20. data/lib/chef/provider/user.rb +1 -1
  21. data/lib/chef/provider/user/dscl.rb +2 -2
  22. data/lib/chef/provider/user/mac.rb +628 -0
  23. data/lib/chef/providers.rb +1 -0
  24. data/lib/chef/resource.rb +28 -20
  25. data/lib/chef/resource/chocolatey_feature.rb +1 -1
  26. data/lib/chef/resource/chocolatey_package.rb +2 -2
  27. data/lib/chef/resource/cron_d.rb +1 -1
  28. data/lib/chef/resource/ohai.rb +1 -1
  29. data/lib/chef/resource/resource_notification.rb +17 -13
  30. data/lib/chef/resource/ruby_block.rb +1 -1
  31. data/lib/chef/resource/service.rb +1 -1
  32. data/lib/chef/resource/user.rb +1 -0
  33. data/lib/chef/resource/user/dscl_user.rb +1 -1
  34. data/lib/chef/resource/user/mac_user.rb +119 -0
  35. data/lib/chef/resource/windows_ad_join.rb +1 -1
  36. data/lib/chef/resource_collection.rb +6 -0
  37. data/lib/chef/resources.rb +1 -0
  38. data/lib/chef/run_context.rb +61 -27
  39. data/lib/chef/runner.rb +50 -12
  40. data/lib/chef/version.rb +1 -1
  41. data/spec/functional/resource/chocolatey_package_spec.rb +19 -1
  42. data/spec/functional/resource/user/mac_user_spec.rb +207 -0
  43. data/spec/integration/client/client_spec.rb +22 -0
  44. data/spec/integration/knife/raw_spec.rb +39 -19
  45. data/spec/integration/knife/redirection_spec.rb +22 -13
  46. data/spec/integration/knife/serve_spec.rb +1 -2
  47. data/spec/integration/recipes/unified_mode_spec.rb +876 -0
  48. data/spec/spec_helper.rb +1 -0
  49. data/spec/support/platform_helpers.rb +10 -0
  50. data/spec/support/shared/integration/integration_helper.rb +1 -2
  51. data/spec/unit/application/client_spec.rb +5 -6
  52. data/spec/unit/application/solo_spec.rb +3 -8
  53. data/spec/unit/application_spec.rb +1 -1
  54. data/spec/unit/cookbook/gem_installer_spec.rb +22 -1
  55. data/spec/unit/knife/bootstrap/train_connector_spec.rb +20 -7
  56. data/spec/unit/knife/bootstrap_spec.rb +13 -5
  57. data/spec/unit/provider/ifconfig_spec.rb +11 -0
  58. data/spec/unit/provider/package/chocolatey_spec.rb +34 -30
  59. data/spec/unit/provider/user/dscl_spec.rb +1 -0
  60. data/spec/unit/provider/user/mac_spec.rb +38 -0
  61. data/spec/unit/provider/user_spec.rb +38 -22
  62. data/tasks/docs.rb +14 -10
  63. metadata +25 -13
  64. data/spec/support/shared/integration/app_server_support.rb +0 -39
@@ -0,0 +1,207 @@
1
+ #
2
+ # Copyright:: Copyright 2019, 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/mixin/shell_out"
20
+
21
+ metadata = {
22
+ macos_1014: true,
23
+ requires_root: true,
24
+ }
25
+
26
+ describe "Chef::Resource::User with Chef::Provider::User::MacUser provider", metadata do
27
+ include Chef::Mixin::ShellOut
28
+
29
+ def clean_user
30
+ shell_out!("/usr/bin/dscl . -delete '/Users/#{username}'")
31
+ rescue Mixlib::ShellOut::ShellCommandFailed
32
+ # Raised when the user is already cleaned
33
+ end
34
+
35
+ def ensure_file_cache_path_exists
36
+ path = Chef::Config["file_cache_path"]
37
+ FileUtils.mkdir_p(path) unless File.directory?(path)
38
+ end
39
+
40
+ def user_should_exist
41
+ expect(shell_out("/usr/bin/dscl . -read /Users/#{username}").error?).to be(false)
42
+ end
43
+
44
+ def check_password(pass)
45
+ # In order to test the password we use dscl passwd command since
46
+ # that's the only command that gets the user password from CLI.
47
+ expect(shell_out("dscl . -passwd /Users/greatchef #{pass} new_password").exitstatus).to eq(0)
48
+ # Now reset the password back
49
+ expect(shell_out("dscl . -passwd /Users/greatchef new_password #{pass}").exitstatus).to eq(0)
50
+ end
51
+
52
+ let(:node) do
53
+ n = Chef::Node.new
54
+ n.consume_external_attrs(OHAI_SYSTEM.data.dup, {})
55
+ n
56
+ end
57
+
58
+ let(:events) do
59
+ Chef::EventDispatch::Dispatcher.new
60
+ end
61
+
62
+ let(:run_context) do
63
+ Chef::RunContext.new(node, {}, events)
64
+ end
65
+
66
+ let(:username) do
67
+ "greatchef"
68
+ end
69
+
70
+ let(:uid) { nil }
71
+ let(:gid) { 20 }
72
+ let(:home) { nil }
73
+ let(:manage_home) { false }
74
+ let(:password) { "XXXYYYZZZ" }
75
+ let(:comment) { "Great Chef" }
76
+ let(:shell) { "/bin/bash" }
77
+ let(:salt) { nil }
78
+ let(:iterations) { nil }
79
+
80
+ let(:user_resource) do
81
+ r = Chef::Resource::User::MacUser.new("TEST USER RESOURCE", run_context)
82
+ r.username(username)
83
+ r.uid(uid)
84
+ r.gid(gid)
85
+ r.home(home)
86
+ r.shell(shell)
87
+ r.comment(comment)
88
+ r.manage_home(manage_home)
89
+ r.password(password)
90
+ r.salt(salt)
91
+ r.iterations(iterations)
92
+ r
93
+ end
94
+
95
+ before do
96
+ clean_user
97
+ ensure_file_cache_path_exists
98
+ end
99
+
100
+ after(:each) do
101
+ clean_user
102
+ end
103
+
104
+ describe "action :create" do
105
+ it "should create the user" do
106
+ user_resource.run_action(:create)
107
+ user_should_exist
108
+ check_password(password)
109
+ end
110
+ end
111
+
112
+ describe "when user exists" do
113
+ before do
114
+ existing_resource = user_resource.dup
115
+ existing_resource.run_action(:create)
116
+ user_should_exist
117
+ end
118
+
119
+ describe "when password is updated" do
120
+ it "should update the password of the user" do
121
+ user_resource.password("mykitchen")
122
+ user_resource.run_action(:create)
123
+ check_password("mykitchen")
124
+ end
125
+ end
126
+ end
127
+
128
+ describe "when password is being set via shadow hash" do
129
+ let(:password) do
130
+ "c734b6e4787c3727bb35e29fdd92b97c\
131
+ 1de12df509577a045728255ec7c6c5f5\
132
+ c18efa05ed02b682ffa7ebc05119900e\
133
+ b1d4880833aa7a190afc13e2bf0936b8\
134
+ 20123e8c98f0f9bcac2a629d9163caac\
135
+ 9464a8c234f3919082400b4f939bb77b\
136
+ c5adbbac718b7eb99463a7b679571e0f\
137
+ 1c9fef2ef08d0b9e9c2bcf644eed2ffc"
138
+ end
139
+
140
+ let(:iterations) { 25000 }
141
+ let(:salt) { "9e2e7d5ee473b496fd24cf0bbfcaedfcb291ee21740e570d1e917e874f8788ca" }
142
+
143
+ it "action :create should create the user" do
144
+ user_resource.run_action(:create)
145
+ user_should_exist
146
+ check_password("soawesome")
147
+ end
148
+
149
+ describe "when user exists" do
150
+ before do
151
+ existing_resource = user_resource.dup
152
+ existing_resource.run_action(:create)
153
+ user_should_exist
154
+ end
155
+
156
+ describe "when password is updated" do
157
+ describe "without salt" do
158
+ let(:salt) { nil }
159
+
160
+ it "it sets the password" do
161
+ user_resource.password("mykitchen")
162
+ user_resource.run_action(:create)
163
+ check_password("mykitchen")
164
+ end
165
+ end
166
+
167
+ describe "with salt and plaintext password" do
168
+ it "raises Chef::Exceptions::User" do
169
+ expect do
170
+ user_resource.password("notasha512")
171
+ user_resource.run_action(:create)
172
+ end.to raise_error(Chef::Exceptions::User)
173
+ end
174
+ end
175
+ end
176
+ end
177
+ end
178
+
179
+ describe "when a user is member of some groups" do
180
+ let(:groups) { %w{staff operator} }
181
+
182
+ before do
183
+ existing_resource = user_resource.dup
184
+ existing_resource.run_action(:create)
185
+
186
+ groups.each do |group|
187
+ shell_out!("/usr/bin/dscl . -append '/Groups/#{group}' GroupMembership #{username}")
188
+ end
189
+ end
190
+
191
+ after do
192
+ groups.each do |group|
193
+ # Do not raise an error when user is correctly removed
194
+ shell_out("/usr/bin/dscl . -delete '/Groups/#{group}' GroupMembership #{username}")
195
+ end
196
+ end
197
+
198
+ it ":remove action removes the user from the groups and deletes the user" do
199
+ user_resource.run_action(:remove)
200
+ groups.each do |group|
201
+ # Do not raise an error when group is empty
202
+ expect(shell_out("dscl . read /Groups/staff GroupMembership").stdout).not_to include(group)
203
+ end
204
+ end
205
+ end
206
+
207
+ end
@@ -369,6 +369,28 @@ describe "chef-client" do
369
369
  end
370
370
  end
371
371
 
372
+ when_the_repository "has a cookbook that outputs some node attributes" do
373
+ before do
374
+ file "cookbooks/x/recipes/default.rb", <<~'EOM'
375
+ puts "COOKBOOKS: #{node[:cookbooks]}"
376
+ EOM
377
+ file "cookbooks/x/metadata.rb", <<~EOM
378
+ name 'x'
379
+ version '0.0.1'
380
+ EOM
381
+ file "config/client.rb", <<~EOM
382
+ local_mode true
383
+ cookbook_path "#{path_to("cookbooks")}"
384
+ EOM
385
+ end
386
+
387
+ it "should have a cookbook attribute" do
388
+ result = shell_out("#{chef_client} -c \"#{path_to("config/client.rb")}\" -o 'x::default' --no-fork", cwd: chef_dir)
389
+ result.error!
390
+ expect(result.stdout).to include('COOKBOOKS: {"x"=>{"version"=>"0.0.1"}}')
391
+ end
392
+ end
393
+
372
394
  when_the_repository "has a cookbook that should fail chef_version checks" do
373
395
  before do
374
396
  file "cookbooks/x/recipes/default.rb", ""
@@ -19,11 +19,11 @@ require "support/shared/integration/integration_helper"
19
19
  require "support/shared/context/config"
20
20
  require "chef/knife/raw"
21
21
  require "chef/knife/show"
22
+ require "tiny_server"
22
23
 
23
24
  describe "knife raw", :workstation do
24
25
  include IntegrationSupport
25
26
  include KnifeSupport
26
- include AppServerSupport
27
27
 
28
28
  include_context "default config options"
29
29
 
@@ -185,19 +185,29 @@ describe "knife raw", :workstation do
185
185
  end
186
186
 
187
187
  context "When a server returns raw json" do
188
- before :each do
189
- Chef::Config.chef_server_url = "http://localhost:9018"
190
- app = lambda do |env|
191
- [200, { "Content-Type" => "application/json" }, ['{ "x": "y", "a": "b" }'] ]
188
+ def start_tiny_server(server_opts = {})
189
+ @server = TinyServer::Manager.new(server_opts)
190
+ @server.start
191
+ @api = TinyServer::API.instance
192
+ @api.clear
193
+
194
+ @api.get("/blah", 200, nil, { "Content-Type" => "application/json" }) do
195
+ '{ "x": "y", "a": "b" }'
192
196
  end
193
- @raw_server_thread = start_app_server(app, 9018)
197
+ end
198
+
199
+ def stop_tiny_server
200
+ @server.stop
201
+ @server = @api = nil
202
+ end
203
+
204
+ before :each do
205
+ Chef::Config.chef_server_url = "http://localhost:9000"
206
+ start_tiny_server
194
207
  end
195
208
 
196
209
  after :each do
197
- if @raw_server_thread
198
- @raw_server_thread.kill
199
- @raw_server_thread.join(30)
200
- end
210
+ stop_tiny_server
201
211
  end
202
212
 
203
213
  it "knife raw /blah returns the prettified json" do
@@ -217,19 +227,29 @@ describe "knife raw", :workstation do
217
227
  end
218
228
 
219
229
  context "When a server returns text" do
220
- before :each do
221
- Chef::Config.chef_server_url = "http://localhost:9018"
222
- app = lambda do |env|
223
- [200, { "Content-Type" => "text" }, ['{ "x": "y", "a": "b" }'] ]
230
+ def start_tiny_server(server_opts = {})
231
+ @server = TinyServer::Manager.new(server_opts)
232
+ @server.start
233
+ @api = TinyServer::API.instance
234
+ @api.clear
235
+
236
+ @api.get("/blah", 200, nil, { "Content-Type" => "text" }) do
237
+ '{ "x": "y", "a": "b" }'
224
238
  end
225
- @raw_server_thread = start_app_server(app, 9018)
239
+ end
240
+
241
+ def stop_tiny_server
242
+ @server.stop
243
+ @server = @api = nil
244
+ end
245
+
246
+ before :each do
247
+ Chef::Config.chef_server_url = "http://localhost:9000"
248
+ start_tiny_server
226
249
  end
227
250
 
228
251
  after :each do
229
- if @raw_server_thread
230
- @raw_server_thread.kill
231
- @raw_server_thread.join(30)
232
- end
252
+ stop_tiny_server
233
253
  end
234
254
 
235
255
  it "knife raw /blah returns the raw text" do
@@ -1,6 +1,6 @@
1
1
  #
2
2
  # Author:: John Keiser (<jkeiser@chef.io>)
3
- # Copyright:: Copyright 2013-2018, Chef Software Inc.
3
+ # Copyright:: Copyright 2013-2019, Chef Software Inc.
4
4
  # License:: Apache License, Version 2.0
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,6 +15,7 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
 
18
+ require "tiny_server"
18
19
  require "support/shared/integration/integration_helper"
19
20
  require "support/shared/context/config"
20
21
  require "chef/knife/list"
@@ -22,7 +23,21 @@ require "chef/knife/list"
22
23
  describe "redirection", :workstation do
23
24
  include IntegrationSupport
24
25
  include KnifeSupport
25
- include AppServerSupport
26
+
27
+ def start_tiny_server(real_chef_server_url, server_opts = {})
28
+ @server = TinyServer::Manager.new(server_opts)
29
+ @server.start
30
+ @api = TinyServer::API.instance
31
+ @api.clear
32
+
33
+ @api.get("/roles", 302, nil, { "Content-Type" => "text", "Location" => "#{real_chef_server_url}/roles" }) do
34
+ end
35
+ end
36
+
37
+ def stop_tiny_server
38
+ @server.stop
39
+ @server = @api = nil
40
+ end
26
41
 
27
42
  include_context "default config options"
28
43
 
@@ -30,20 +45,14 @@ describe "redirection", :workstation do
30
45
  before { role "x", {} }
31
46
 
32
47
  context "and another server redirects to it with 302" do
33
- before :each do
48
+ before(:each) do
34
49
  real_chef_server_url = Chef::Config.chef_server_url
35
- Chef::Config.chef_server_url = "http://localhost:9018"
36
- app = lambda do |env|
37
- [302, { "Content-Type" => "text", "Location" => "#{real_chef_server_url}#{env["PATH_INFO"]}" }, ["302 found"] ]
38
- end
39
- @redirector_server_thread = start_app_server(app, 9018)
50
+ Chef::Config.chef_server_url = "http://localhost:9000"
51
+ start_tiny_server(real_chef_server_url)
40
52
  end
41
53
 
42
- after :each do
43
- if @redirector_thread
44
- @redirector_thread.kill
45
- @redirector_thread.join(30)
46
- end
54
+ after(:each) do
55
+ stop_tiny_server
47
56
  end
48
57
 
49
58
  it "knife list /roles returns the role" do
@@ -1,6 +1,6 @@
1
1
  #
2
2
  # Author:: John Keiser (<jkeiser@chef.io>)
3
- # Copyright:: Copyright 2013-2016, Chef Software Inc.
3
+ # Copyright:: Copyright 2013-2019, Chef Software Inc.
4
4
  # License:: Apache License, Version 2.0
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,7 +22,6 @@ require "chef/server_api"
22
22
  describe "knife serve", :workstation do
23
23
  include IntegrationSupport
24
24
  include KnifeSupport
25
- include AppServerSupport
26
25
 
27
26
  def with_knife_serve
28
27
  exception = nil
@@ -0,0 +1,876 @@
1
+ require "support/shared/integration/integration_helper"
2
+ require "chef/mixin/shell_out"
3
+
4
+ describe "Unified Mode" do
5
+ include IntegrationSupport
6
+ include Chef::Mixin::ShellOut
7
+
8
+ let(:chef_dir) { File.expand_path("../../../../bin", __FILE__) }
9
+
10
+ let(:chef_client) { "bundle exec chef-client --minimal-ohai" }
11
+
12
+ when_the_repository "has a cookbook with a unified_mode resource with a delayed notification from the second block to the first block" do
13
+ before do
14
+ directory "cookbooks/x" do
15
+
16
+ file "resources/unified_mode.rb", <<-EOM
17
+ unified_mode true
18
+ resource_name :unified_mode
19
+ provides :unified_mode
20
+
21
+ action :doit do
22
+ klass = new_resource.class
23
+ var = "foo"
24
+ ruby_block "first block" do
25
+ block do
26
+ puts "\nfirst: \#\{var\}"
27
+ end
28
+ action :nothing
29
+ end
30
+ var = "bar"
31
+ ruby_block "second block" do
32
+ block do
33
+ puts "\nsecond: \#\{var\}"
34
+ end
35
+ notifies :run, "ruby_block[first block]", :delayed
36
+ end
37
+ var = "baz"
38
+ end
39
+ EOM
40
+
41
+ file "recipes/default.rb", <<-EOM
42
+ unified_mode "whatever"
43
+ EOM
44
+
45
+ end # directory 'cookbooks/x'
46
+ end
47
+
48
+ it "should complete with success" do
49
+ file "config/client.rb", <<~EOM
50
+ local_mode true
51
+ cookbook_path "#{path_to("cookbooks")}"
52
+ log_level :warn
53
+ EOM
54
+
55
+ result = shell_out("#{chef_client} -c \"#{path_to("config/client.rb")}\" --no-color -F doc -o 'x::default'", cwd: chef_dir)
56
+ # the "second block" runs first after "bar" is set
57
+ expect(result.stdout).to include("second: bar")
58
+ # then the "first block" runs after "baz" in the delayed phase
59
+ expect(result.stdout).to include("first: baz")
60
+ # nothing else should fire
61
+ expect(result.stdout).not_to include("first: foo")
62
+ expect(result.stdout).not_to include("first: bar")
63
+ expect(result.stdout).not_to include("second: foo")
64
+ expect(result.stdout).not_to include("second: baz")
65
+ result.error!
66
+ end
67
+ end
68
+
69
+ when_the_repository "has a cookbook with a unified_mode resource with a delayed notification from the first block to the second block" do
70
+ before do
71
+ directory "cookbooks/x" do
72
+
73
+ file "resources/unified_mode.rb", <<-EOM
74
+ unified_mode true
75
+ resource_name :unified_mode
76
+ provides :unified_mode
77
+
78
+ action :doit do
79
+ klass = new_resource.class
80
+ var = "foo"
81
+ ruby_block "first block" do
82
+ block do
83
+ puts "\nfirst: \#\{var\}"
84
+ end
85
+ notifies :run, "ruby_block[second block]", :delayed
86
+ end
87
+ var = "bar"
88
+ ruby_block "second block" do
89
+ block do
90
+ puts "\nsecond: \#\{var\}"
91
+ end
92
+ action :nothing
93
+ end
94
+ var = "baz"
95
+ end
96
+ EOM
97
+
98
+ file "recipes/default.rb", <<-EOM
99
+ unified_mode "whatever"
100
+ EOM
101
+
102
+ end # directory 'cookbooks/x'
103
+ end
104
+
105
+ it "should complete with success" do
106
+ file "config/client.rb", <<~EOM
107
+ local_mode true
108
+ cookbook_path "#{path_to("cookbooks")}"
109
+ log_level :warn
110
+ EOM
111
+
112
+ result = shell_out("#{chef_client} -c \"#{path_to("config/client.rb")}\" --no-color -F doc -o 'x::default' -l debug", cwd: chef_dir)
113
+ # the first block should fire first
114
+ expect(result.stdout).to include("first: foo")
115
+ # the second block should fire in delayed phase
116
+ expect(result.stdout).to include("second: baz")
117
+ # nothing else should fire
118
+ expect(result.stdout).not_to include("first: bar")
119
+ expect(result.stdout).not_to include("first: baz")
120
+ expect(result.stdout).not_to include("second: foo")
121
+ expect(result.stdout).not_to include("second: bar")
122
+ result.error!
123
+ end
124
+ end
125
+
126
+ when_the_repository "has a cookbook with a unified_mode resource with an immediate notification from the second block to the first block" do
127
+ before do
128
+ directory "cookbooks/x" do
129
+
130
+ file "resources/unified_mode.rb", <<-EOM
131
+ unified_mode true
132
+ resource_name :unified_mode
133
+ provides :unified_mode
134
+ action :doit do
135
+ klass = new_resource.class
136
+ var = "foo"
137
+ ruby_block "first block" do
138
+ block do
139
+ puts "\nfirst: \#\{var\}"
140
+ end
141
+ action :nothing
142
+ end
143
+ var = "bar"
144
+ ruby_block "second block" do
145
+ block do
146
+ puts "\nsecond: \#\{var\}"
147
+ end
148
+ notifies :run, "ruby_block[first block]", :immediate
149
+ end
150
+ var = "baz"
151
+ end
152
+ EOM
153
+
154
+ file "recipes/default.rb", <<-EOM
155
+ unified_mode "whatever"
156
+ EOM
157
+
158
+ end # directory 'cookbooks/x'
159
+ end
160
+
161
+ it "should complete with success" do
162
+ file "config/client.rb", <<~EOM
163
+ local_mode true
164
+ cookbook_path "#{path_to("cookbooks")}"
165
+ log_level :warn
166
+ EOM
167
+
168
+ result = shell_out("#{chef_client} -c \"#{path_to("config/client.rb")}\" --no-color -F doc -o 'x::default'", cwd: chef_dir)
169
+ # the second resource should fire first when it is parsed
170
+ expect(result.stdout).to include("second: bar")
171
+ # the first resource should then immediately fire
172
+ expect(result.stdout).to include("first: bar")
173
+ # no other resources should fire
174
+ expect(result.stdout).not_to include("second: baz")
175
+ expect(result.stdout).not_to include("second: foo")
176
+ expect(result.stdout).not_to include("first: foo")
177
+ expect(result.stdout).not_to include("first: baz")
178
+ result.error!
179
+ end
180
+ end
181
+
182
+ when_the_repository "has a cookbook with a unified_mode resource with an immediate notification from the first block to the second block" do
183
+ before do
184
+ directory "cookbooks/x" do
185
+
186
+ file "resources/unified_mode.rb", <<-EOM
187
+ unified_mode true
188
+ resource_name :unified_mode
189
+ provides :unified_mode
190
+ action :doit do
191
+ klass = new_resource.class
192
+ var = "foo"
193
+ ruby_block "first block" do
194
+ block do
195
+ puts "\nfirst: \#\{var\}"
196
+ end
197
+ notifies :run, "ruby_block[second block]", :immediate
198
+ end
199
+ var = "bar"
200
+ ruby_block "second block" do
201
+ block do
202
+ puts "\nsecond: \#\{var\}"
203
+ end
204
+ action :nothing
205
+ end
206
+ var = "baz"
207
+ end
208
+ EOM
209
+
210
+ file "recipes/default.rb", <<-EOM
211
+ unified_mode "whatever"
212
+ EOM
213
+
214
+ end # directory 'cookbooks/x'
215
+ end
216
+
217
+ it "should complete with success" do
218
+ file "config/client.rb", <<~EOM
219
+ local_mode true
220
+ cookbook_path "#{path_to("cookbooks")}"
221
+ log_level :warn
222
+ EOM
223
+
224
+ result = shell_out("#{chef_client} -c \"#{path_to("config/client.rb")}\" --no-color -F doc -o 'x::default' -l debug", cwd: chef_dir)
225
+ # both blocks should run when they're declared
226
+ expect(result.stdout).to include("first: foo")
227
+ expect(result.stdout).to include("second: bar")
228
+ # nothing else should run
229
+ expect(result.stdout).not_to include("first: bar")
230
+ expect(result.stdout).not_to include("first: baz")
231
+ expect(result.stdout).not_to include("second: foo")
232
+ expect(result.stdout).not_to include("second: baz")
233
+ result.error!
234
+ end
235
+ end
236
+
237
+ when_the_repository "has a cookbook with a unified_mode resource with an immediate notification from the first block to a block that does not exist" do
238
+ before do
239
+ directory "cookbooks/x" do
240
+
241
+ file "resources/unified_mode.rb", <<-EOM
242
+ unified_mode true
243
+ resource_name :unified_mode
244
+ provides :unified_mode
245
+ action :doit do
246
+ klass = new_resource.class
247
+ var = "foo"
248
+ ruby_block "first block" do
249
+ block do
250
+ puts "\nfirst: \#\{var\}"
251
+ end
252
+ notifies :run, "ruby_block[second block]", :immediate
253
+ end
254
+ var = "bar"
255
+ var = "baz"
256
+ end
257
+ EOM
258
+
259
+ file "recipes/default.rb", <<-EOM
260
+ unified_mode "whatever"
261
+ EOM
262
+
263
+ end # directory 'cookbooks/x'
264
+ end
265
+
266
+ it "should fail the run" do
267
+ file "config/client.rb", <<~EOM
268
+ local_mode true
269
+ cookbook_path "#{path_to("cookbooks")}"
270
+ log_level :warn
271
+ EOM
272
+
273
+ result = shell_out("#{chef_client} -c \"#{path_to("config/client.rb")}\" --no-color -F doc -o 'x::default'", cwd: chef_dir)
274
+ # both blocks should run when they're declared
275
+ expect(result.stdout).to include("first: foo")
276
+ # nothing else should run
277
+ expect(result.stdout).not_to include("second: bar")
278
+ expect(result.stdout).not_to include("first: bar")
279
+ expect(result.stdout).not_to include("first: baz")
280
+ expect(result.stdout).not_to include("second: foo")
281
+ expect(result.stdout).not_to include("second: baz")
282
+ expect(result.stdout).to include("Chef::Exceptions::ResourceNotFound")
283
+ expect(result.error?).to be true
284
+ end
285
+ end
286
+
287
+ when_the_repository "has a cookbook with a normal resource with an delayed notification with global resource unified mode on" do
288
+ before do
289
+ directory "cookbooks/x" do
290
+
291
+ file "resources/unified_mode.rb", <<-EOM
292
+ resource_name :unified_mode
293
+ provides :unified_mode
294
+
295
+ action :doit do
296
+ klass = new_resource.class
297
+ var = "foo"
298
+ ruby_block "second block" do
299
+ block do
300
+ puts "\nsecond: \#\{var\}"
301
+ end
302
+ action :nothing
303
+ end
304
+ var = "bar"
305
+ ruby_block "first block" do
306
+ block do
307
+ puts "\nfirst: \#\{var\}"
308
+ end
309
+ notifies :run, "ruby_block[second block]", :delayed
310
+ end
311
+ var = "baz"
312
+ end
313
+ EOM
314
+
315
+ file "recipes/default.rb", <<-EOM
316
+ unified_mode "whatever"
317
+ EOM
318
+
319
+ end # directory 'cookbooks/x'
320
+ end
321
+
322
+ it "should complete with success" do
323
+ file "config/client.rb", <<~EOM
324
+ resource_unified_mode_default true
325
+ local_mode true
326
+ cookbook_path "#{path_to("cookbooks")}"
327
+ log_level :warn
328
+ EOM
329
+
330
+ result = shell_out("#{chef_client} -c \"#{path_to("config/client.rb")}\" --no-color -F doc -o 'x::default'", cwd: chef_dir)
331
+ # the "first block" resource runs before the assignment to baz in compile time
332
+ expect(result.stdout).to include("first: bar")
333
+ # we should not run the "first block" at compile time
334
+ expect(result.stdout).not_to include("first: baz")
335
+ # (and certainly should run it this early)
336
+ expect(result.stdout).not_to include("first: foo")
337
+ # the delayed notification should still fire and run after everything else
338
+ expect(result.stdout).to include("second: baz")
339
+ # the action :nothing should suppress any other running of the second block
340
+ expect(result.stdout).not_to include("second: foo")
341
+ expect(result.stdout).not_to include("second: bar")
342
+ result.error!
343
+ end
344
+ end
345
+
346
+ when_the_repository "has a cookbook with a normal resource with an immediate notification with global resource unified mode on" do
347
+ before do
348
+ directory "cookbooks/x" do
349
+
350
+ file "resources/unified_mode.rb", <<-EOM
351
+ resource_name :unified_mode
352
+ provides :unified_mode
353
+ action :doit do
354
+ klass = new_resource.class
355
+ var = "foo"
356
+ ruby_block "second block" do
357
+ block do
358
+ puts "\nsecond: \#\{var\}"
359
+ end
360
+ action :nothing
361
+ end
362
+ var = "bar"
363
+ ruby_block "first block" do
364
+ block do
365
+ puts "\nfirst: \#\{var\}"
366
+ end
367
+ notifies :run, "ruby_block[second block]", :immediate
368
+ end
369
+ var = "baz"
370
+ end
371
+ EOM
372
+
373
+ file "recipes/default.rb", <<-EOM
374
+ unified_mode "whatever"
375
+ EOM
376
+
377
+ end # directory 'cookbooks/x'
378
+ end
379
+
380
+ it "should complete with success" do
381
+ file "config/client.rb", <<~EOM
382
+ resource_unified_mode_default true
383
+ local_mode true
384
+ cookbook_path "#{path_to("cookbooks")}"
385
+ log_level :warn
386
+ EOM
387
+
388
+ result = shell_out("#{chef_client} -c \"#{path_to("config/client.rb")}\" --no-color -F doc -o 'x::default'", cwd: chef_dir)
389
+ # the "first block" resource runs before the assignment to baz in compile time
390
+ expect(result.stdout).to include("first: bar")
391
+ # we should not run the "first block" at compile time
392
+ expect(result.stdout).not_to include("first: baz")
393
+ # (and certainly should run it this early)
394
+ expect(result.stdout).not_to include("first: foo")
395
+ # the immediate notifiation fires immediately
396
+ expect(result.stdout).to include("second: bar")
397
+ # the action :nothing should suppress any other running of the second block
398
+ expect(result.stdout).not_to include("second: foo")
399
+ expect(result.stdout).not_to include("second: baz")
400
+ result.error!
401
+ end
402
+ end
403
+
404
+ when_the_repository "has a cookbook with a unified resource with an immediate subscribes from the second resource to the first" do
405
+ before do
406
+ directory "cookbooks/x" do
407
+
408
+ file "resources/unified_mode.rb", <<-EOM
409
+ unified_mode true
410
+ resource_name :unified_mode
411
+ provides :unified_mode
412
+ action :doit do
413
+ klass = new_resource.class
414
+ var = "foo"
415
+ ruby_block "first block" do
416
+ block do
417
+ puts "\nfirst: \#\{var\}"
418
+ end
419
+ end
420
+ var = "bar"
421
+ ruby_block "second block" do
422
+ block do
423
+ puts "\nsecond: \#\{var\}"
424
+ end
425
+ subscribes :run, "ruby_block[first block]", :immediate
426
+ action :nothing
427
+ end
428
+ var = "baz"
429
+ end
430
+ EOM
431
+
432
+ file "recipes/default.rb", <<-EOM
433
+ unified_mode "whatever"
434
+ EOM
435
+
436
+ end # directory 'cookbooks/x'
437
+ end
438
+
439
+ it "should complete with success" do
440
+ file "config/client.rb", <<~EOM
441
+ local_mode true
442
+ cookbook_path "#{path_to("cookbooks")}"
443
+ log_level :warn
444
+ EOM
445
+
446
+ result = shell_out("#{chef_client} -c \"#{path_to("config/client.rb")}\" --no-color -F doc -o 'x::default'", cwd: chef_dir)
447
+ # the first resource fires
448
+ expect(result.stdout).to include("first: foo")
449
+ # the second resource fires when it is parsed
450
+ expect(result.stdout).to include("second: bar")
451
+ # no other actions should run
452
+ expect(result.stdout).not_to include("first: bar")
453
+ expect(result.stdout).not_to include("first: baz")
454
+ expect(result.stdout).not_to include("second: foo")
455
+ expect(result.stdout).not_to include("second: baz")
456
+ result.error!
457
+ end
458
+ end
459
+
460
+ when_the_repository "has a cookbook with a unified resource with an immediate subscribes from the first resource to the second" do
461
+ before do
462
+ directory "cookbooks/x" do
463
+
464
+ file "resources/unified_mode.rb", <<-EOM
465
+ unified_mode true
466
+ resource_name :unified_mode
467
+ provides :unified_mode
468
+ action :doit do
469
+ klass = new_resource.class
470
+ var = "foo"
471
+ ruby_block "first block" do
472
+ block do
473
+ puts "\nfirst: \#\{var\}"
474
+ end
475
+ subscribes :run, "ruby_block[second block]", :immediate
476
+ action :nothing
477
+ end
478
+ var = "bar"
479
+ ruby_block "second block" do
480
+ block do
481
+ puts "\nsecond: \#\{var\}"
482
+ end
483
+ end
484
+ var = "baz"
485
+ end
486
+ EOM
487
+
488
+ file "recipes/default.rb", <<-EOM
489
+ unified_mode "whatever"
490
+ EOM
491
+
492
+ end # directory 'cookbooks/x'
493
+ end
494
+
495
+ it "should complete with success" do
496
+ file "config/client.rb", <<~EOM
497
+ local_mode true
498
+ cookbook_path "#{path_to("cookbooks")}"
499
+ log_level :warn
500
+ EOM
501
+
502
+ result = shell_out("#{chef_client} -c \"#{path_to("config/client.rb")}\" --no-color -F doc -o 'x::default'", cwd: chef_dir)
503
+ # the second resource fires first after bar is set
504
+ expect(result.stdout).to include("second: bar")
505
+ # the first resource then has its immediate subscribes fire at that location
506
+ expect(result.stdout).to include("first: bar")
507
+ # no other actions should run
508
+ expect(result.stdout).not_to include("first: baz")
509
+ expect(result.stdout).not_to include("first: foo")
510
+ expect(result.stdout).not_to include("second: foo")
511
+ expect(result.stdout).not_to include("second: baz")
512
+ result.error!
513
+ end
514
+ end
515
+
516
+ when_the_repository "has a cookbook with a unified resource with an delayed subscribes from the second resource to the first" do
517
+ before do
518
+ directory "cookbooks/x" do
519
+
520
+ file "resources/unified_mode.rb", <<-EOM
521
+ unified_mode true
522
+ resource_name :unified_mode
523
+ provides :unified_mode
524
+ action :doit do
525
+ klass = new_resource.class
526
+ var = "foo"
527
+ ruby_block "first block" do
528
+ block do
529
+ puts "\nfirst: \#\{var\}"
530
+ end
531
+ end
532
+ var = "bar"
533
+ ruby_block "second block" do
534
+ block do
535
+ puts "\nsecond: \#\{var\}"
536
+ end
537
+ subscribes :run, "ruby_block[first block]", :delayed
538
+ action :nothing
539
+ end
540
+ var = "baz"
541
+ end
542
+ EOM
543
+
544
+ file "recipes/default.rb", <<-EOM
545
+ unified_mode "whatever"
546
+ EOM
547
+
548
+ end # directory 'cookbooks/x'
549
+ end
550
+
551
+ it "should complete with success" do
552
+ file "config/client.rb", <<~EOM
553
+ local_mode true
554
+ cookbook_path "#{path_to("cookbooks")}"
555
+ log_level :warn
556
+ EOM
557
+
558
+ result = shell_out("#{chef_client} -c \"#{path_to("config/client.rb")}\" --no-color -F doc -o 'x::default'", cwd: chef_dir)
559
+ # the first resource fires as it is parsed
560
+ expect(result.stdout).to include("first: foo")
561
+ # the second resource then fires in the delayed notifications phase
562
+ expect(result.stdout).to include("second: baz")
563
+ # no other actions should run
564
+ expect(result.stdout).not_to include("first: bar")
565
+ expect(result.stdout).not_to include("first: baz")
566
+ expect(result.stdout).not_to include("second: foo")
567
+ expect(result.stdout).not_to include("second: bar")
568
+ result.error!
569
+ end
570
+ end
571
+
572
+ when_the_repository "has a cookbook with a unified resource with an delayed subscribes from the first resource to the second" do
573
+ before do
574
+ directory "cookbooks/x" do
575
+
576
+ file "resources/unified_mode.rb", <<-EOM
577
+ unified_mode true
578
+ resource_name :unified_mode
579
+ provides :unified_mode
580
+ action :doit do
581
+ klass = new_resource.class
582
+ var = "foo"
583
+ ruby_block "first block" do
584
+ block do
585
+ puts "\nfirst: \#\{var\}"
586
+ end
587
+ subscribes :run, "ruby_block[second block]", :delayed
588
+ action :nothing
589
+ end
590
+ var = "bar"
591
+ ruby_block "second block" do
592
+ block do
593
+ puts "\nsecond: \#\{var\}"
594
+ end
595
+ end
596
+ var = "baz"
597
+ end
598
+ EOM
599
+
600
+ file "recipes/default.rb", <<-EOM
601
+ unified_mode "whatever"
602
+ EOM
603
+
604
+ end # directory 'cookbooks/x'
605
+ end
606
+
607
+ it "should complete with success" do
608
+ file "config/client.rb", <<~EOM
609
+ local_mode true
610
+ cookbook_path "#{path_to("cookbooks")}"
611
+ log_level :warn
612
+ EOM
613
+
614
+ result = shell_out("#{chef_client} -c \"#{path_to("config/client.rb")}\" --no-color -F doc -o 'x::default'", cwd: chef_dir)
615
+ # the second resource fires first after bar is set
616
+ expect(result.stdout).to include("second: bar")
617
+ # the first resource then fires in the delayed notifications phase
618
+ expect(result.stdout).to include("first: baz")
619
+ # no other actions should run
620
+ expect(result.stdout).not_to include("first: foo")
621
+ expect(result.stdout).not_to include("first: bar")
622
+ expect(result.stdout).not_to include("second: foo")
623
+ expect(result.stdout).not_to include("second: baz")
624
+ result.error!
625
+ end
626
+ end
627
+
628
+ when_the_repository "has a cookbook with a unified resource with a correct before notification" do
629
+ before do
630
+ directory "cookbooks/x" do
631
+
632
+ file "resources/unified_mode.rb", <<-EOM
633
+ unified_mode true
634
+ resource_name :unified_mode
635
+ provides :unified_mode
636
+ action :doit do
637
+ klass = new_resource.class
638
+ var = "foo"
639
+ ruby_block "notified block" do
640
+ block do
641
+ puts "\nnotified: \#\{var\}"
642
+ end
643
+ action :nothing
644
+ end
645
+ var = "bar"
646
+ whyrun_safe_ruby_block "notifying block" do
647
+ block do
648
+ puts "\nnotifying: \#\{var\}"
649
+ end
650
+ notifies :run, "ruby_block[notified block]", :before
651
+ end
652
+ var = "baz"
653
+ end
654
+ EOM
655
+
656
+ file "recipes/default.rb", <<-EOM
657
+ unified_mode "whatever"
658
+ EOM
659
+
660
+ end # directory 'cookbooks/x'
661
+ end
662
+
663
+ it "should complete with success" do
664
+ file "config/client.rb", <<~EOM
665
+ local_mode true
666
+ cookbook_path "#{path_to("cookbooks")}"
667
+ log_level :warn
668
+ EOM
669
+
670
+ result = shell_out("#{chef_client} -c \"#{path_to("config/client.rb")}\" --no-color -F doc -o 'x::default'", cwd: chef_dir)
671
+ expect(result.stdout.scan(/notifying: bar/).length).to eql(2)
672
+ expect(result.stdout).to include("Would execute the whyrun_safe_ruby_block notifying block")
673
+ expect(result.stdout).to include("notified: bar")
674
+ # no other actions should run
675
+ expect(result.stdout).not_to include("notified: foo")
676
+ expect(result.stdout).not_to include("notified: baz")
677
+ expect(result.stdout).not_to include("notifying: foo")
678
+ expect(result.stdout).not_to include("notifying: baz")
679
+ result.error!
680
+ end
681
+ end
682
+
683
+ when_the_repository "has a cookbook with a unified resource with a correct before subscribes" do
684
+ before do
685
+ directory "cookbooks/x" do
686
+
687
+ file "resources/unified_mode.rb", <<-EOM
688
+ unified_mode true
689
+ resource_name :unified_mode
690
+ provides :unified_mode
691
+ action :doit do
692
+ klass = new_resource.class
693
+ var = "foo"
694
+ ruby_block "notified block" do
695
+ block do
696
+ puts "\nnotified: \#\{var\}"
697
+ end
698
+ subscribes :run, "whyrun_safe_ruby_block[notifying block]", :before
699
+ action :nothing
700
+ end
701
+ var = "bar"
702
+ whyrun_safe_ruby_block "notifying block" do
703
+ block do
704
+ puts "\nnotifying: \#\{var\}"
705
+ end
706
+ end
707
+ var = "baz"
708
+ end
709
+ EOM
710
+
711
+ file "recipes/default.rb", <<-EOM
712
+ unified_mode "whatever"
713
+ EOM
714
+
715
+ end # directory 'cookbooks/x'
716
+ end
717
+
718
+ it "should complete with success" do
719
+ file "config/client.rb", <<~EOM
720
+ local_mode true
721
+ cookbook_path "#{path_to("cookbooks")}"
722
+ log_level :warn
723
+ EOM
724
+
725
+ result = shell_out("#{chef_client} -c \"#{path_to("config/client.rb")}\" --no-color -F doc -o 'x::default'", cwd: chef_dir)
726
+ expect(result.stdout.scan(/notifying: bar/).length).to eql(2)
727
+ expect(result.stdout).to include("Would execute the whyrun_safe_ruby_block notifying block")
728
+ expect(result.stdout).to include("notified: bar")
729
+ # no other actions should run
730
+ expect(result.stdout).not_to include("notified: foo")
731
+ expect(result.stdout).not_to include("notified: baz")
732
+ expect(result.stdout).not_to include("notifying: foo")
733
+ expect(result.stdout).not_to include("notifying: baz")
734
+ result.error!
735
+ end
736
+ end
737
+
738
+ when_the_repository "has a cookbook with a unified resource with a broken/reversed before notification" do
739
+ before do
740
+ directory "cookbooks/x" do
741
+
742
+ file "resources/unified_mode.rb", <<-EOM
743
+ unified_mode true
744
+ resource_name :unified_mode
745
+ provides :unified_mode
746
+ action :doit do
747
+ klass = new_resource.class
748
+ var = "foo"
749
+ whyrun_safe_ruby_block "notifying block" do
750
+ block do
751
+ puts "\nnotifying: \#\{var\}"
752
+ end
753
+ notifies :run, "ruby_block[notified block]", :before
754
+ end
755
+ var = "bar"
756
+ ruby_block "notified block" do
757
+ block do
758
+ puts "\nnotified: \#\{var\}"
759
+ end
760
+ action :nothing
761
+ end
762
+ var = "baz"
763
+ end
764
+ EOM
765
+
766
+ file "recipes/default.rb", <<-EOM
767
+ unified_mode "whatever"
768
+ EOM
769
+
770
+ end # directory 'cookbooks/x'
771
+ end
772
+
773
+ it "should fail the run" do
774
+ file "config/client.rb", <<~EOM
775
+ local_mode true
776
+ cookbook_path "#{path_to("cookbooks")}"
777
+ log_level :warn
778
+ EOM
779
+
780
+ result = shell_out("#{chef_client} -c \"#{path_to("config/client.rb")}\" --no-color -F doc -o 'x::default' -l debug", cwd: chef_dir)
781
+ # this doesn't work and we can't tell the difference between it and if we were trying to do a correct :before notification but typo'd the name
782
+ # so Chef::Exceptions::ResourceNotFound is the best we can do
783
+ expect(result.stdout).to include("Chef::Exceptions::ResourceNotFound")
784
+ expect(result.error?).to be true
785
+ end
786
+ end
787
+
788
+ when_the_repository "has a cookbook with a unified resource with a broken/reversed before subscribes" do
789
+ before do
790
+ directory "cookbooks/x" do
791
+
792
+ file "resources/unified_mode.rb", <<-EOM
793
+ unified_mode true
794
+ resource_name :unified_mode
795
+ provides :unified_mode
796
+ action :doit do
797
+ klass = new_resource.class
798
+ var = "foo"
799
+ whyrun_safe_ruby_block "notifying block" do
800
+ block do
801
+ puts "\nnotifying: \#\{var\}"
802
+ end
803
+ end
804
+ var = "bar"
805
+ ruby_block "notified block" do
806
+ block do
807
+ puts "\nnotified: \#\{var\}"
808
+ end
809
+ subscribes :run, "whyrun_safe_ruby_block[notifying block]", :before
810
+ action :nothing
811
+ end
812
+ var = "baz"
813
+ end
814
+ EOM
815
+
816
+ file "recipes/default.rb", <<-EOM
817
+ unified_mode "whatever"
818
+ EOM
819
+
820
+ end # directory 'cookbooks/x'
821
+ end
822
+
823
+ it "should fail the run" do
824
+ file "config/client.rb", <<~EOM
825
+ local_mode true
826
+ cookbook_path "#{path_to("cookbooks")}"
827
+ log_level :warn
828
+ EOM
829
+
830
+ result = shell_out("#{chef_client} -c \"#{path_to("config/client.rb")}\" --no-color -F doc -o 'x::default'", cwd: chef_dir)
831
+ # this fires first normally before the error
832
+ expect(result.stdout).to include("notifying: foo")
833
+ # everything else does not run
834
+ expect(result.stdout).not_to include("notified: foo")
835
+ expect(result.stdout).not_to include("notified: bar")
836
+ expect(result.stdout).not_to include("notified: baz")
837
+ expect(result.stdout).not_to include("notifying: bar")
838
+ expect(result.stdout).not_to include("notifying: baz")
839
+ expect(result.stdout).to include("Chef::Exceptions::UnifiedModeBeforeSubscriptionEarlierResource")
840
+ expect(result.error?).to be true
841
+ end
842
+ end
843
+
844
+ when_the_repository "has global resource unified mode on" do
845
+ before do
846
+ directory "cookbooks/x" do
847
+
848
+ file "recipes/default.rb", <<-EOM
849
+ var = "foo"
850
+ ruby_block "first block" do
851
+ block do
852
+ puts "\nfirst: \#\{var\}"
853
+ end
854
+ end
855
+ var = "bar"
856
+ EOM
857
+
858
+ end # directory 'cookbooks/x'
859
+ end
860
+
861
+ it "recipes should still have a compile/converge mode" do
862
+ file "config/client.rb", <<~EOM
863
+ resource_unified_mode_default true
864
+ local_mode true
865
+ cookbook_path "#{path_to("cookbooks")}"
866
+ log_level :warn
867
+ EOM
868
+
869
+ result = shell_out("#{chef_client} -c \"#{path_to("config/client.rb")}\" --no-color -F doc -o 'x::default'", cwd: chef_dir)
870
+ # in recipe mode we should still run normally with a compile/converge mode
871
+ expect(result.stdout).to include("first: bar")
872
+ expect(result.stdout).not_to include("first: foo")
873
+ result.error!
874
+ end
875
+ end
876
+ end