chef 14.12.9-universal-mingw32 → 14.13.11-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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -9
  3. data/lib/chef/chef_fs/command_line.rb +11 -12
  4. data/lib/chef/deprecated.rb +3 -3
  5. data/lib/chef/dsl/data_query.rb +22 -4
  6. data/lib/chef/dsl/recipe.rb +1 -7
  7. data/lib/chef/dsl/universal.rb +6 -0
  8. data/lib/chef/file_access_control/windows.rb +5 -3
  9. data/lib/chef/knife.rb +3 -3
  10. data/lib/chef/knife/bootstrap.rb +1 -1
  11. data/lib/chef/knife/bootstrap/templates/chef-full.erb +2 -1
  12. data/lib/chef/knife/config_list_profiles.rb +1 -1
  13. data/lib/chef/knife/core/status_presenter.rb +9 -2
  14. data/lib/chef/mixin/template.rb +14 -9
  15. data/lib/chef/node_map.rb +5 -24
  16. data/lib/chef/provider/cron.rb +14 -2
  17. data/lib/chef/provider/file.rb +1 -1
  18. data/lib/chef/provider/service/insserv.rb +3 -1
  19. data/lib/chef/resource.rb +3 -10
  20. data/lib/chef/resource/windows_feature_powershell.rb +1 -1
  21. data/lib/chef/resource_collection.rb +3 -2
  22. data/lib/chef/shell.rb +1 -0
  23. data/lib/chef/version.rb +1 -1
  24. data/lib/chef/win32/api/security.rb +2 -0
  25. data/lib/chef/win32/file.rb +8 -0
  26. data/lib/chef/win32/security.rb +1 -1
  27. data/spec/data/templates/failed.erb +5 -0
  28. data/spec/functional/assets/inittest +36 -0
  29. data/spec/functional/resource/insserv_spec.rb +205 -0
  30. data/spec/functional/resource/link_spec.rb +2 -2
  31. data/spec/spec_helper.rb +1 -0
  32. data/spec/support/platform_helpers.rb +4 -0
  33. data/spec/support/shared/functional/directory_resource.rb +12 -10
  34. data/spec/support/shared/functional/file_resource.rb +2 -2
  35. data/spec/support/shared/functional/securable_resource.rb +102 -71
  36. data/spec/support/shared/unit/provider/file.rb +1 -0
  37. data/spec/unit/knife/bootstrap_spec.rb +22 -0
  38. data/spec/unit/knife_spec.rb +8 -5
  39. data/spec/unit/mixin/template_spec.rb +45 -0
  40. data/spec/unit/node_map_spec.rb +10 -43
  41. data/spec/unit/provider/cron_spec.rb +123 -20
  42. data/spec/unit/provider/service/insserv_service_spec.rb +2 -2
  43. data/spec/unit/resource_collection_spec.rb +8 -0
  44. data/spec/unit/resource_spec.rb +1 -13
  45. data/spec/unit/win32/security_spec.rb +25 -0
  46. metadata +7 -4
@@ -117,8 +117,7 @@ shared_context "use Windows permissions", :windows_only do
117
117
 
118
118
  let(:expected_write_perms) do
119
119
  {
120
- generic: Chef::ReservedNames::Win32::API::Security::GENERIC_WRITE,
121
- specific: Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_WRITE,
120
+ specific: Chef::ReservedNames::Win32::API::Security::WRITE,
122
121
  }
123
122
  end
124
123
 
@@ -136,6 +135,8 @@ shared_context "use Windows permissions", :windows_only do
136
135
  }
137
136
  end
138
137
 
138
+ let (:write_flag) { 3 }
139
+
139
140
  RSpec::Matchers.define :have_expected_properties do |mask, type, flags|
140
141
  match do |ace|
141
142
  ace.mask == mask &&
@@ -363,78 +364,108 @@ shared_examples_for "a securable resource without existing target" do
363
364
  expect(descriptor.group).to eq(arbitrary_non_default_group)
364
365
  end
365
366
 
366
- describe "with rights and deny_rights attributes" do
367
-
368
- it "correctly sets :read rights" do
369
- resource.rights(:read, "Guest")
370
- resource.run_action(:create)
371
- expect(explicit_aces).to eq(allowed_acl(SID.Guest, expected_read_perms))
367
+ describe "#allowed_acl" do
368
+ context "correctly sets" do
369
+
370
+ it ":read rights" do
371
+ resource.rights(:read, "Guest")
372
+ resource.run_action(:create)
373
+ expect(explicit_aces).to eq(allowed_acl(SID.Guest, expected_read_perms))
374
+ end
375
+
376
+ it ":read_execute rights" do
377
+ resource.rights(:read_execute, "Guest")
378
+ resource.run_action(:create)
379
+ expect(explicit_aces).to eq(allowed_acl(SID.Guest, expected_read_execute_perms))
380
+ end
381
+
382
+ it ":write rights" do
383
+ resource.rights(:write, "Guest")
384
+ resource.run_action(:create)
385
+ expect(explicit_aces).to eq(allowed_acl(SID.Guest, expected_write_perms, write_flag))
386
+ end
387
+
388
+ it ":modify rights" do
389
+ resource.rights(:modify, "Guest")
390
+ resource.run_action(:create)
391
+ expect(explicit_aces).to eq(allowed_acl(SID.Guest, expected_modify_perms))
392
+ end
393
+
394
+ it ":full_control rights" do
395
+ resource.rights(:full_control, "Guest")
396
+ resource.run_action(:create)
397
+ expect(explicit_aces).to eq(allowed_acl(SID.Guest, expected_full_control_perms))
398
+ end
399
+
400
+ it "multiple rights" do
401
+ resource.rights(:read, "Everyone")
402
+ resource.rights(:modify, "Guest")
403
+ resource.run_action(:create)
404
+
405
+ expect(explicit_aces).to eq(
406
+ allowed_acl(SID.Everyone, expected_read_perms) +
407
+ allowed_acl(SID.Guest, expected_modify_perms)
408
+ )
409
+ end
372
410
  end
411
+ end
373
412
 
374
- it "correctly sets :read_execute rights" do
375
- resource.rights(:read_execute, "Guest")
376
- resource.run_action(:create)
377
- expect(explicit_aces).to eq(allowed_acl(SID.Guest, expected_read_execute_perms))
378
- end
379
-
380
- it "correctly sets :write rights" do
381
- resource.rights(:write, "Guest")
382
- resource.run_action(:create)
383
- expect(explicit_aces).to eq(allowed_acl(SID.Guest, expected_write_perms))
384
- end
385
-
386
- it "correctly sets :modify rights" do
387
- resource.rights(:modify, "Guest")
388
- resource.run_action(:create)
389
- expect(explicit_aces).to eq(allowed_acl(SID.Guest, expected_modify_perms))
390
- end
391
-
392
- it "correctly sets :full_control rights" do
393
- resource.rights(:full_control, "Guest")
394
- resource.run_action(:create)
395
- expect(explicit_aces).to eq(allowed_acl(SID.Guest, expected_full_control_perms))
396
- end
397
-
398
- it "correctly sets deny_rights" do
399
- # deny is an ACE with full rights, but is a deny type ace, not an allow type
400
- resource.deny_rights(:full_control, "Guest")
401
- resource.run_action(:create)
402
- expect(explicit_aces).to eq(denied_acl(SID.Guest, expected_full_control_perms))
403
- end
404
-
405
- it "Sets multiple rights" do
406
- resource.rights(:read, "Everyone")
407
- resource.rights(:modify, "Guest")
408
- resource.run_action(:create)
409
-
410
- expect(explicit_aces).to eq(
411
- allowed_acl(SID.Everyone, expected_read_perms) +
412
- allowed_acl(SID.Guest, expected_modify_perms)
413
- )
414
- end
415
-
416
- it "Sets deny_rights ahead of rights" do
417
- resource.rights(:read, "Everyone")
418
- resource.deny_rights(:modify, "Guest")
419
- resource.run_action(:create)
420
-
421
- expect(explicit_aces).to eq(
422
- denied_acl(SID.Guest, expected_modify_perms) +
423
- allowed_acl(SID.Everyone, expected_read_perms)
424
- )
425
- end
426
-
427
- it "Sets deny_rights ahead of rights when specified in reverse order" do
428
- resource.deny_rights(:modify, "Guest")
429
- resource.rights(:read, "Everyone")
430
- resource.run_action(:create)
431
-
432
- expect(explicit_aces).to eq(
433
- denied_acl(SID.Guest, expected_modify_perms) +
434
- allowed_acl(SID.Everyone, expected_read_perms)
435
- )
413
+ describe "#denied_acl" do
414
+ context "correctly sets" do
415
+
416
+ it ":read rights" do
417
+ resource.deny_rights(:read, "Guest")
418
+ resource.run_action(:create)
419
+ expect(explicit_aces).to eq(denied_acl(SID.Guest, expected_read_perms))
420
+ end
421
+
422
+ it ":read_execute rights" do
423
+ resource.deny_rights(:read_execute, "Guest")
424
+ resource.run_action(:create)
425
+ expect(explicit_aces).to eq(denied_acl(SID.Guest, expected_read_execute_perms))
426
+ end
427
+
428
+ it ":write rights" do
429
+ resource.deny_rights(:write, "Guest")
430
+ resource.run_action(:create)
431
+ expect(explicit_aces).to eq(denied_acl(SID.Guest, expected_write_perms, write_flag))
432
+ end
433
+
434
+ it ":modify rights" do
435
+ resource.deny_rights(:modify, "Guest")
436
+ resource.run_action(:create)
437
+ expect(explicit_aces).to eq(denied_acl(SID.Guest, expected_modify_perms))
438
+ end
439
+
440
+ it ":full_control rights" do
441
+ # deny is an ACE with full rights, but is a deny type ace, not an allow type
442
+ resource.deny_rights(:full_control, "Guest")
443
+ resource.run_action(:create)
444
+ expect(explicit_aces).to eq(denied_acl(SID.Guest, expected_full_control_perms))
445
+ end
446
+
447
+ it "deny_rights ahead of rights" do
448
+ resource.rights(:read, "Everyone")
449
+ resource.deny_rights(:modify, "Guest")
450
+ resource.run_action(:create)
451
+
452
+ expect(explicit_aces).to eq(
453
+ denied_acl(SID.Guest, expected_modify_perms) +
454
+ allowed_acl(SID.Everyone, expected_read_perms)
455
+ )
456
+ end
457
+
458
+ it "deny_rights ahead of rights when specified in reverse order" do
459
+ resource.deny_rights(:modify, "Guest")
460
+ resource.rights(:read, "Everyone")
461
+ resource.run_action(:create)
462
+
463
+ expect(explicit_aces).to eq(
464
+ denied_acl(SID.Guest, expected_modify_perms) +
465
+ allowed_acl(SID.Everyone, expected_read_perms)
466
+ )
467
+ end
436
468
  end
437
-
438
469
  end
439
470
 
440
471
  context "with a mode attribute" do
@@ -76,6 +76,7 @@ def setup_symlink
76
76
  allow(File).to receive(:directory?).with(path).and_return(false)
77
77
  allow(File).to receive(:writable?).with(path).and_return(true)
78
78
  allow(file_symlink_class).to receive(:symlink?).with(path).and_return(true)
79
+ allow(file_symlink_class).to receive(:realpath).with(path).and_return(path)
79
80
  end
80
81
  allow(File).to receive(:directory?).with(enclosing_directory).and_return(true)
81
82
  end
@@ -96,6 +96,28 @@ describe Chef::Knife::Bootstrap do
96
96
  end
97
97
  end
98
98
 
99
+ context "with --bootstrap-proxy" do
100
+ let(:bootstrap_cli_options) { [ "--bootstrap-proxy", "1.1.1.1" ] }
101
+ let(:rendered_template) do
102
+ knife.merge_configs
103
+ knife.render_template
104
+ end
105
+ it "configures the https_proxy environment variable in the bootstrap template correctly" do
106
+ expect(rendered_template).to match(%r{https_proxy="1.1.1.1" export https_proxy})
107
+ end
108
+ end
109
+
110
+ context "with --bootstrap-no-proxy" do
111
+ let(:bootstrap_cli_options) { [ "--bootstrap-no-proxy", "localserver" ] }
112
+ let(:rendered_template) do
113
+ knife.merge_configs
114
+ knife.render_template
115
+ end
116
+ it "configures the https_proxy environment variable in the bootstrap template correctly" do
117
+ expect(rendered_template).to match(%r{no_proxy="localserver" export no_proxy})
118
+ end
119
+ end
120
+
99
121
  context "with :bootstrap_template and :template_file cli options" do
100
122
  let(:bootstrap_cli_options) { [ "--bootstrap-template", "my-template", "other-template" ] }
101
123
 
@@ -344,11 +344,14 @@ describe Chef::Knife do
344
344
  end
345
345
  end
346
346
 
347
- it "does not humanize the exception if Chef::Config[:verbosity] is two" do
348
- Chef::Config[:verbosity] = 2
349
- allow(knife).to receive(:run).and_raise(Exception)
350
- expect(knife).not_to receive(:humanize_exception)
351
- expect { knife.run_with_pretty_exceptions }.to raise_error(Exception)
347
+ # -VV (2) is debug, -VVV (3) is trace
348
+ [ 2, 3 ].each do |verbosity|
349
+ it "does not humanize the exception if Chef::Config[:verbosity] is #{verbosity}" do
350
+ Chef::Config[:verbosity] = verbosity
351
+ allow(knife).to receive(:run).and_raise(Exception)
352
+ expect(knife).not_to receive(:humanize_exception)
353
+ expect { knife.run_with_pretty_exceptions }.to raise_error(Exception)
354
+ end
352
355
  end
353
356
  end
354
357
 
@@ -182,6 +182,51 @@ describe Chef::Mixin::Template, "render_template" do
182
182
  expect(output).to eq("before {partial one We could be diving for pearls! calling home} after")
183
183
  end
184
184
 
185
+ describe "when an exception is raised in the template" do
186
+ let(:template_file) { File.expand_path(File.join(CHEF_SPEC_DATA, "templates", "failed.erb")) }
187
+
188
+ def do_raise
189
+ @template_context.render_template(template_file)
190
+ end
191
+
192
+ it "should catch and re-raise the exception as a TemplateError" do
193
+ expect { do_raise }.to raise_error(Chef::Mixin::Template::TemplateError)
194
+ end
195
+
196
+ describe "the raised TemplateError" do
197
+ subject(:exception) do
198
+ begin
199
+ do_raise
200
+ rescue Chef::Mixin::Template::TemplateError => e
201
+ e
202
+ end
203
+ end
204
+
205
+ it "should contain template file and line numbers" do
206
+ expect(exception.line_number).to eq(5)
207
+ end
208
+
209
+ it "should provide a source listing of the template around the exception" do
210
+ expect(exception.source_listing).to eq(" 3: Which includes some content\n 4: \n 5: And will fail <%= nil[] %>")
211
+ end
212
+
213
+ it "should provide a nice source location" do
214
+ expect(exception.source_location).to eq("on line #5")
215
+ end
216
+
217
+ it "should create a pretty output for the terminal" do
218
+ expect(exception.to_s).to match(/Chef::Mixin::Template::TemplateError/)
219
+ expect(exception.to_s).to match(/undefined method `\[\]' for nil:NilClass/)
220
+ expect(exception.to_s).to include(" 3: Which includes some content\n 4: \n 5: And will fail <%= nil[] %>")
221
+ expect(exception.to_s).to include(exception.original_exception.backtrace.first)
222
+ end
223
+
224
+ it "should include template file on original_exception backtrace" do
225
+ expect(exception.original_exception.backtrace).to include(/#{Regexp.escape(template_file)}/)
226
+ end
227
+ end
228
+ end
229
+
185
230
  describe "when customizing the template context" do
186
231
 
187
232
  it "extends the context to include modules" do
@@ -1,6 +1,6 @@
1
1
  #
2
2
  # Author:: Lamont Granquist (<lamont@chef.io>)
3
- # Copyright:: Copyright 2014-2018, Chef Software Inc.
3
+ # Copyright:: Copyright 2014-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");
@@ -145,14 +145,14 @@ describe Chef::NodeMap do
145
145
  describe "deleting classes" do
146
146
  it "deletes a class and removes the mapping completely" do
147
147
  node_map.set(:thing, Bar)
148
- expect( node_map.delete_class(Bar) ).to include({ thing: [{ klass: Bar, cookbook_override: false, core_override: false }] })
148
+ expect( node_map.delete_class(Bar) ).to include({ thing: [{ klass: Bar }] })
149
149
  expect( node_map.get(node, :thing) ).to eql(nil)
150
150
  end
151
151
 
152
152
  it "deletes a class and leaves the mapping that still has an entry" do
153
153
  node_map.set(:thing, Bar)
154
154
  node_map.set(:thing, Foo)
155
- expect( node_map.delete_class(Bar) ).to eql({ thing: [{ klass: Bar, cookbook_override: false, core_override: false }] })
155
+ expect( node_map.delete_class(Bar) ).to eql({ thing: [{ klass: Bar }] })
156
156
  expect( node_map.get(node, :thing) ).to eql(Foo)
157
157
  end
158
158
 
@@ -160,7 +160,7 @@ describe Chef::NodeMap do
160
160
  node_map.set(:thing1, Bar)
161
161
  node_map.set(:thing2, Bar)
162
162
  node_map.set(:thing2, Foo)
163
- expect( node_map.delete_class(Bar) ).to eql({ thing1: [{ klass: Bar, cookbook_override: false, core_override: false }], thing2: [{ klass: Bar, cookbook_override: false, core_override: false }] })
163
+ expect( node_map.delete_class(Bar) ).to eql({ thing1: [{ klass: Bar }], thing2: [{ klass: Bar }] })
164
164
  expect( node_map.get(node, :thing1) ).to eql(nil)
165
165
  expect( node_map.get(node, :thing2) ).to eql(Foo)
166
166
  end
@@ -213,7 +213,7 @@ describe Chef::NodeMap do
213
213
  describe "locked mode" do
214
214
  context "while unlocked" do
215
215
  it "allows setting the same key twice" do
216
- expect(Chef).to_not receive(:deprecated)
216
+ expect(Chef::Log).to_not receive(:warn)
217
217
  node_map.set(:foo, FooResource)
218
218
  node_map.set(:foo, BarResource)
219
219
  expect(node_map.get(node, :foo)).to eql(BarResource)
@@ -221,53 +221,20 @@ describe Chef::NodeMap do
221
221
  end
222
222
 
223
223
  context "while locked" do
224
- # Uncomment the commented `expect`s in 15.0.
225
- it "rejects setting the same key twice" do
226
- expect(Chef).to receive(:deprecated).with(:map_collision, /Resource foo/)
224
+ it "warns on setting the same key twice" do
225
+ expect(Chef::Log).to receive(:warn).with(/Resource foo/)
227
226
  node_map.set(:foo, FooResource)
228
227
  node_map.lock!
229
228
  node_map.set(:foo, BarResource)
230
- # expect(node_map.get(node, :foo)).to eql(FooResource)
231
- end
232
-
233
- it "allows setting the same key twice when the first has allow_cookbook_override" do
234
- expect(Chef).to_not receive(:deprecated)
235
- node_map.set(:foo, FooResource, allow_cookbook_override: true)
236
- node_map.lock!
237
- node_map.set(:foo, BarResource)
238
- expect(node_map.get(node, :foo)).to eql(BarResource)
239
- end
240
-
241
- it "allows setting the same key twice when the first has allow_cookbook_override with a future version" do
242
- expect(Chef).to_not receive(:deprecated)
243
- node_map.set(:foo, FooResource, allow_cookbook_override: "< 100")
244
- node_map.lock!
245
- node_map.set(:foo, BarResource)
246
- expect(node_map.get(node, :foo)).to eql(BarResource)
247
- end
248
-
249
- it "rejects setting the same key twice when the first has allow_cookbook_override with a past version" do
250
- expect(Chef).to receive(:deprecated).with(:map_collision, /Resource foo/)
251
- node_map.set(:foo, FooResource, allow_cookbook_override: "< 1")
252
- node_map.lock!
253
- node_map.set(:foo, BarResource)
254
- # expect(node_map.get(node, :foo)).to eql(FooResource)
255
- end
256
-
257
- it "allows setting the same key twice when the second has __core_override__" do
258
- expect(Chef).to_not receive(:deprecated)
259
- node_map.set(:foo, FooResource)
260
- node_map.lock!
261
- node_map.set(:foo, BarResource, __core_override__: true)
262
229
  expect(node_map.get(node, :foo)).to eql(BarResource)
263
230
  end
264
231
 
265
- it "rejects setting the same key twice for a provider" do
266
- expect(Chef).to receive(:deprecated).with(:map_collision, /Provider foo/)
232
+ it "warns on setting the same key twice for a provider" do
233
+ expect(Chef::Log).to receive(:warn).with(/Provider foo/)
267
234
  node_map.set(:foo, FooProvider)
268
235
  node_map.lock!
269
236
  node_map.set(:foo, BarProvider)
270
- # expect(node_map.get(node, :foo)).to eql(FooProvider)
237
+ expect(node_map.get(node, :foo)).to eql(BarProvider)
271
238
  end
272
239
  end
273
240
  end
@@ -690,33 +690,136 @@ CRONTAB
690
690
  end
691
691
 
692
692
  context "when there is a crontab with a matching and identical section" do
693
- before :each do
694
- @provider.cron_exists = true
695
- allow(@provider).to receive(:cron_different?).and_return(false)
696
- allow(@provider).to receive(:read_crontab).and_return(<<~CRONTAB)
697
- 0 2 * * * /some/other/command
693
+ context "when environment variable is not used" do
694
+ before :each do
695
+ @provider.cron_exists = true
696
+ allow(@provider).to receive(:cron_different?).and_return(false)
697
+ allow(@provider).to receive(:read_crontab).and_return(<<~CRONTAB)
698
+ 0 2 * * * /some/other/command
698
699
 
699
- # Chef Name: cronhole some stuff
700
- * 5 * * * /bin/true
700
+ # Chef Name: cronhole some stuff
701
+ SHELL=/bash
702
+ * 5 * * * /bin/true
701
703
 
702
- # Another comment
703
- CRONTAB
704
- end
704
+ # Another comment
705
+ CRONTAB
706
+ end
705
707
 
706
- it "should not update the crontab" do
707
- expect(@provider).not_to receive(:write_crontab)
708
- @provider.run_action(:create)
708
+ it "should not update the crontab" do
709
+ expect(@provider).not_to receive(:write_crontab)
710
+ @provider.run_action(:create)
711
+ end
712
+
713
+ it "should not mark the resource as updated" do
714
+ @provider.run_action(:create)
715
+ expect(@new_resource).not_to be_updated_by_last_action
716
+ end
717
+
718
+ it "should log nothing changed" do
719
+ expect(logger).to receive(:trace).with("Found cron '#{@new_resource.name}'")
720
+ expect(logger).to receive(:trace).with("Skipping existing cron entry '#{@new_resource.name}'")
721
+ @provider.run_action(:create)
722
+ end
709
723
  end
710
724
 
711
- it "should not mark the resource as updated" do
712
- @provider.run_action(:create)
713
- expect(@new_resource).not_to be_updated_by_last_action
725
+ context "when environment variable is used" do
726
+ before :each do
727
+ @provider.cron_exists = true
728
+ allow(@provider).to receive(:read_crontab).and_return(<<~CRONTAB)
729
+ 0 2 * * * /some/other/command
730
+
731
+ # Chef Name: cronhole some stuff
732
+ SHELL=/bash
733
+ ENV=environment
734
+ 30 * * * * /bin/true
735
+
736
+ # Another comment
737
+ CRONTAB
738
+ end
739
+ context "contains an entry that can also be specified as a `property`" do
740
+ before :each do
741
+ @new_resource.environment = { "SHELL" => "/bash", "ENV" => "environment" }
742
+ end
743
+
744
+ it "should raise a warning for idempotency" do
745
+ expect(logger).to receive(:warn).with("cronhole some stuff: the environment property contains the 'SHELL' variable, which should be set separately as a property.")
746
+ @provider.run_action(:create)
747
+ end
748
+
749
+ it "should not update the crontab" do
750
+ expect(@provider).not_to receive(:write_crontab)
751
+ @provider.run_action(:create)
752
+ end
753
+
754
+ it "should not mark the resource as updated" do
755
+ expect(@new_resource).not_to be_updated_by_last_action
756
+ @provider.run_action(:create)
757
+ end
758
+ end
759
+
760
+ context "contains an entry that cannot be specified as a `property`" do
761
+ before :each do
762
+ @new_resource.environment = { "ENV" => "environment" }
763
+ @new_resource.shell "/bash"
764
+ end
765
+
766
+ it "should not raise a warning for idempotency" do
767
+ expect(logger).not_to receive(:warn).with("cronhole some stuff: the environment property contains the 'SHELL' variable, which should be set separately as a property.")
768
+ @provider.run_action(:create)
769
+ end
770
+
771
+ it "should not update the crontab" do
772
+ expect(@provider).not_to receive(:write_crontab)
773
+ @provider.run_action(:create)
774
+ end
775
+
776
+ it "should not mark the resource as updated" do
777
+ @provider.run_action(:create)
778
+ expect(@new_resource).not_to be_updated_by_last_action
779
+ end
780
+ end
714
781
  end
715
782
 
716
- it "should log nothing changed" do
717
- expect(logger).to receive(:trace).with("Found cron '#{@new_resource.name}'")
718
- expect(logger).to receive(:trace).with("Skipping existing cron entry '#{@new_resource.name}'")
719
- @provider.run_action(:create)
783
+ context "when environment variable is used with property" do
784
+ before :each do
785
+ @provider.cron_exists = true
786
+ allow(@provider).to receive(:read_crontab).and_return(<<~CRONTAB)
787
+ 0 2 * * * /some/other/command
788
+
789
+ # Chef Name: cronhole some stuff
790
+ SHELL=/bash
791
+ ENV=environment
792
+ 30 * * * * /bin/true
793
+
794
+ # Another comment
795
+ CRONTAB
796
+ end
797
+
798
+ context "when environment variable is same as property" do
799
+ it "should throw an error" do
800
+ @new_resource.shell "/bash"
801
+ @new_resource.environment "SHELL" => "/bash"
802
+ expect do
803
+ @provider.run_action(:create)
804
+ end.to raise_error(Chef::Exceptions::Cron, /cronhole some stuff: the 'SHELL' property is set and environment property also contains the 'SHELL' variable. Remove the variable from the environment property./)
805
+ end
806
+ end
807
+
808
+ context "when environment variable is different from property" do
809
+ it "should not update the crontab" do
810
+ @new_resource.shell "/bash"
811
+ @new_resource.environment "ENV" => "environment"
812
+ expect(@provider).not_to receive(:write_crontab)
813
+ @provider.run_action(:create)
814
+ end
815
+
816
+ it "should not mark the resource as updated" do
817
+ @new_resource.shell "/bash"
818
+ @new_resource.environment "ENV" => "environment"
819
+ @provider.run_action(:create)
820
+ expect(@new_resource).not_to be_updated_by_last_action
821
+ end
822
+ end
720
823
  end
721
824
  end
722
825
  end