ruby-pwsh 0.10.3 → 0.11.0.rc.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'spec_helper'
4
+ require 'puppet/resource_api'
4
5
  require 'puppet/type'
5
6
  require 'puppet/provider/dsc_base_provider/dsc_base_provider'
6
7
  require 'json'
@@ -8,21 +9,21 @@ require 'json'
8
9
  RSpec.describe Puppet::Provider::DscBaseProvider do
9
10
  subject(:provider) { described_class.new }
10
11
 
11
- let(:context) { instance_double('Puppet::ResourceApi::PuppetContext') }
12
- let(:type) { instance_double('Puppet::ResourceApi::TypeDefinition') }
13
- let(:ps_manager) { instance_double('Pwsh::Manager') }
12
+ let(:context) { instance_double(Puppet::ResourceApi::PuppetContext) }
13
+ let(:type) { instance_double(Puppet::ResourceApi::TypeDefinition) }
14
+ let(:ps_manager) { instance_double(Pwsh::Manager) }
14
15
  let(:execute_response) { { stdout: nil, stderr: nil, exitcode: 0 } }
15
16
 
16
17
  # Reset the caches after each run
17
- after(:each) do
18
+ after do
18
19
  described_class.class_variable_set(:@@cached_canonicalized_resource, nil) # rubocop:disable Style/ClassVars
19
20
  described_class.class_variable_set(:@@cached_query_results, nil) # rubocop:disable Style/ClassVars
20
21
  described_class.class_variable_set(:@@cached_test_results, nil) # rubocop:disable Style/ClassVars
21
22
  described_class.class_variable_set(:@@logon_failures, nil) # rubocop:disable Style/ClassVars
22
23
  end
23
24
 
24
- context '.initialize' do
25
- before(:each) do
25
+ describe '.initialize' do
26
+ before do
26
27
  # Need to initialize the provider to load the class variables
27
28
  provider
28
29
  end
@@ -30,18 +31,21 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
30
31
  it 'initializes the cached_canonicalized_resource class variable' do
31
32
  expect(described_class.class_variable_get(:@@cached_canonicalized_resource)).to eq([])
32
33
  end
34
+
33
35
  it 'initializes the cached_query_results class variable' do
34
36
  expect(described_class.class_variable_get(:@@cached_query_results)).to eq([])
35
37
  end
38
+
36
39
  it 'initializes the cached_test_results class variable' do
37
40
  expect(described_class.class_variable_get(:@@cached_test_results)).to eq([])
38
41
  end
42
+
39
43
  it 'initializes the logon_failures class variable' do
40
44
  expect(described_class.class_variable_get(:@@logon_failures)).to eq([])
41
45
  end
42
46
  end
43
47
 
44
- context '.cached_test_results' do
48
+ describe '.cached_test_results' do
45
49
  let(:cache_value) { %w[foo bar] }
46
50
 
47
51
  it 'returns the value of the @@cached_test_results class variable' do
@@ -50,7 +54,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
50
54
  end
51
55
  end
52
56
 
53
- context '.fetch_cached_hashes' do
57
+ describe '.fetch_cached_hashes' do
54
58
  let(:cached_hashes) { [{ foo: 1, bar: 2, baz: 3 }, { foo: 4, bar: 5, baz: 6 }] }
55
59
  let(:findable_full_hash) { { foo: 1, bar: 2, baz: 3 } }
56
60
  let(:findable_sub_hash) { { foo: 1 } }
@@ -59,15 +63,17 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
59
63
  it 'finds a hash that exactly matches one in the cache' do
60
64
  expect(provider.fetch_cached_hashes(cached_hashes, [findable_full_hash])).to eq([findable_full_hash])
61
65
  end
66
+
62
67
  it 'finds a hash that is wholly contained by a hash in the cache' do
63
68
  expect(provider.fetch_cached_hashes(cached_hashes, [findable_sub_hash])).to eq([findable_full_hash])
64
69
  end
70
+
65
71
  it 'returns an empty array if there is no match' do
66
72
  expect(provider.fetch_cached_hashes(cached_hashes, [undiscoverable_hash])).to eq([])
67
73
  end
68
74
  end
69
75
 
70
- context '.canonicalize' do
76
+ describe '.canonicalize' do
71
77
  subject(:canonicalized_resource) { provider.canonicalize(context, [manifest_resource]) }
72
78
 
73
79
  let(:resource_name_hash) { { name: 'foo', dsc_name: 'foo' } }
@@ -76,7 +82,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
76
82
  let(:credential_hash) { { 'username' => 'foo', 'password' => 'bar' } }
77
83
  let(:base_resource) { resource_name_hash.dup }
78
84
 
79
- before(:each) do
85
+ before do
80
86
  allow(context).to receive(:debug)
81
87
  allow(provider).to receive(:namevar_attributes).and_return(namevar_keys)
82
88
  allow(provider).to receive(:fetch_cached_hashes).and_return(cached_canonicalized_resource)
@@ -88,7 +94,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
88
94
  let(:cached_canonicalized_resource) { expected_resource.dup }
89
95
 
90
96
  it 'does not get removed as part of the canonicalization' do
91
- expect(canonicalized_resource.first[:noop]).to eq(true)
97
+ expect(canonicalized_resource.first[:noop]).to be(true)
92
98
  end
93
99
  end
94
100
 
@@ -105,7 +111,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
105
111
  context 'when a manifest resource not in the canonicalized resource cache' do
106
112
  let(:cached_canonicalized_resource) { [] }
107
113
 
108
- before(:each) do
114
+ before do
109
115
  allow(provider).to receive(:invoke_get_method).and_return(actual_resource)
110
116
  end
111
117
 
@@ -119,7 +125,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
119
125
  end
120
126
 
121
127
  context 'when invoke_get_method returns a resource' do
122
- before(:each) do
128
+ before do
123
129
  allow(provider).to receive(:parameter_attributes).and_return(parameter_keys)
124
130
  allow(provider).to receive(:enum_attributes).and_return([])
125
131
  end
@@ -148,7 +154,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
148
154
  let(:actual_resource) { base_resource.merge({ dsc_property: 'Bar' }) }
149
155
 
150
156
  it 'treats the manifest value as canonical' do
151
- expect(canonicalized_resource.first[:dsc_property]).to eq(nil)
157
+ expect(canonicalized_resource.first[:dsc_property]).to be_nil
152
158
  end
153
159
  end
154
160
 
@@ -165,7 +171,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
165
171
  let(:manifest_resource) { base_resource.merge({ dsc_property: 'Dword' }) }
166
172
  let(:actual_resource) { base_resource.merge({ dsc_property: 'DWord' }) }
167
173
 
168
- before(:each) do
174
+ before do
169
175
  allow(provider).to receive(:enum_attributes).and_return([:dsc_property])
170
176
  end
171
177
 
@@ -230,8 +236,8 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
230
236
  end
231
237
  end
232
238
 
233
- context '.get' do
234
- after(:each) do
239
+ describe '.get' do
240
+ after do
235
241
  described_class.class_variable_set(:@@cached_canonicalized_resource, []) # rubocop:disable Style/ClassVars
236
242
  end
237
243
 
@@ -242,6 +248,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
242
248
  expect(provider).not_to receive(:invoke_get_method)
243
249
  expect(provider.get(context, [{ name: 'foo' }])).to eq([{ name: 'foo', property: 'bar' }])
244
250
  end
251
+
245
252
  it 'adds mandatory properties to the name hash when calling invoke_get_method' do
246
253
  described_class.class_variable_set(:@@cached_canonicalized_resource, [{ name: 'foo', property: 'bar', dsc_some_parameter: 'baz' }]) # rubocop:disable Style/ClassVars
247
254
  allow(context).to receive(:debug)
@@ -253,7 +260,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
253
260
  end
254
261
  end
255
262
 
256
- context '.set' do
263
+ describe '.set' do
257
264
  subject(:result) { provider.set(context, change_set) }
258
265
 
259
266
  let(:name_hash) { { name: 'foo', dsc_name: 'foo' } }
@@ -261,7 +268,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
261
268
  # Empty because we can mock everything but calling .keys on the hash
262
269
  let(:attributes) { { name: {}, dsc_name: {}, dsc_setting: {} } }
263
270
 
264
- before(:each) do
271
+ before do
265
272
  allow(context).to receive(:type).and_return(type)
266
273
  allow(type).to receive(:namevars).and_return(%i[name dsc_name])
267
274
  allow(type).to receive(:attributes).and_return(attributes)
@@ -342,6 +349,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
342
349
  context 'when `is` is nil' do
343
350
  let(:change_set) { { name_hash => { should: should_state } } }
344
351
  let(:should_state) { name_hash.merge(dsc_setting: 'Foo') }
352
+
345
353
  it 'attempts to retrieve the resource from the machine to populate `is` value' do
346
354
  pending('Implementation only works for when `get` returns an array, but `get` returns one resource as a hash')
347
355
  expect(provider).to receive(:get).with(context, [name_hash]).and_return(name_hash.merge(dsc_setting: 'Bar'))
@@ -353,7 +361,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
353
361
  end
354
362
  end
355
363
 
356
- context '.create' do
364
+ describe '.create' do
357
365
  it 'calls invoke_set_method' do
358
366
  allow(context).to receive(:debug)
359
367
  expect(provider).to receive(:invoke_set_method)
@@ -361,7 +369,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
361
369
  end
362
370
  end
363
371
 
364
- context '.update' do
372
+ describe '.update' do
365
373
  it 'calls invoke_set_method' do
366
374
  allow(context).to receive(:debug)
367
375
  expect(provider).to receive(:invoke_set_method)
@@ -369,7 +377,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
369
377
  end
370
378
  end
371
379
 
372
- context '.delete' do
380
+ describe '.delete' do
373
381
  it 'calls invoke_set_method' do
374
382
  allow(context).to receive(:debug)
375
383
  expect(provider).to receive(:invoke_set_method)
@@ -377,7 +385,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
377
385
  end
378
386
  end
379
387
 
380
- context '.insync?' do
388
+ describe '.insync?' do
381
389
  let(:name) { { name: 'foo' } }
382
390
  let(:attribute_name) { :foo }
383
391
  let(:is_hash) { { name: 'foo', foo: 1 } }
@@ -391,22 +399,24 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
391
399
  expect(provider).to receive(:invoke_test_method).and_return(true)
392
400
  expect(provider.send(:insync?, context, name, attribute_name, is_hash, should_hash_validate_by_resource)).to be true
393
401
  end
402
+
394
403
  it 'does not call invoke_test_method if the result of a test is already cached' do
395
404
  expect(provider).to receive(:fetch_cached_hashes).and_return(cached_test_result)
396
405
  expect(provider).not_to receive(:invoke_test_method)
397
406
  expect(provider.send(:insync?, context, name, attribute_name, is_hash, should_hash_validate_by_resource)).to be true
398
407
  end
399
408
  end
409
+
400
410
  context 'when the validation_mode is "property"' do
401
411
  it 'does not call invoke_test_method and returns nil' do
402
412
  expect(provider).not_to receive(:fetch_cached_hashes)
403
413
  expect(provider).not_to receive(:invoke_test_method)
404
- expect(provider.send(:insync?, context, name, attribute_name, is_hash, should_hash_validate_by_property)).to be nil
414
+ expect(provider.send(:insync?, context, name, attribute_name, is_hash, should_hash_validate_by_property)).to be_nil
405
415
  end
406
416
  end
407
417
  end
408
418
 
409
- context '.invoke_get_method' do
419
+ describe '.invoke_get_method' do
410
420
  subject(:result) { provider.invoke_get_method(context, name_hash) }
411
421
 
412
422
  let(:attributes) do
@@ -508,7 +518,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
508
518
  }
509
519
  end
510
520
 
511
- before(:each) do
521
+ before do
512
522
  allow(context).to receive(:debug)
513
523
  allow(provider).to receive(:mandatory_get_attributes).and_return(mandatory_get_attributes)
514
524
  allow(provider).to receive(:invocable_resource).with(query_props, context, 'get').and_return(resource)
@@ -520,12 +530,12 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
520
530
  allow(type).to receive(:attributes).and_return(attributes)
521
531
  end
522
532
 
523
- after(:each) do
533
+ after do
524
534
  described_class.class_variable_set(:@@cached_query_results, nil) # rubocop:disable Style/ClassVars
525
535
  end
526
536
 
527
537
  context 'when the invocation script returns data without errors' do
528
- before(:each) do
538
+ before do
529
539
  allow(ps_manager).to receive(:execute).with(script).and_return({ stdout: 'DSC Data' })
530
540
  allow(JSON).to receive(:parse).with('DSC Data').and_return(parsed_invocation_data)
531
541
  allow(Puppet::Pops::Time::Timestamp).to receive(:parse).with('2100-01-01').and_return('TimeStamp:2100-01-01')
@@ -536,32 +546,40 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
536
546
  expect(provider).not_to receive(:logon_failed_already?)
537
547
  expect { result }.not_to raise_error
538
548
  end
549
+
539
550
  it 'writes no errors to the context' do
540
551
  expect(context).not_to receive(:err)
541
552
  expect { result }.not_to raise_error
542
553
  end
554
+
543
555
  it 're-adds the puppet name to the resource' do
544
556
  expect(result[:name]).to eq('foo')
545
557
  end
558
+
546
559
  it 'caches the result' do
547
560
  expect { result }.not_to raise_error
548
561
  expect(described_class.class_variable_get(:@@cached_query_results)).to eq([result])
549
562
  end
563
+
550
564
  it 'removes unrelated properties from the result' do
551
565
  expect(result.keys).not_to include('UnusedProperty')
552
566
  expect(result.keys).not_to include('unusedproperty')
553
567
  expect(result.keys).not_to include(:unusedproperty)
554
568
  end
569
+
555
570
  it 'removes parameters from the result' do
556
571
  expect(result[:dsc_param]).to be_nil
557
572
  end
573
+
558
574
  it 'handles timestamps' do
559
575
  expect(result[:dsc_time]).to eq('TimeStamp:2100-01-01')
560
576
  end
577
+
561
578
  it 'downcases keys in cim instance properties' do
562
579
  expect(result[:dsc_nestedciminstance].keys).to eq(%w[baz nestedproperty])
563
580
  expect(result[:dsc_nestedciminstance]['nestedproperty'].keys).to eq(%w[cim_instance_type nestedbar nestedfoo])
564
581
  end
582
+
565
583
  it 'recursively sorts the result for order-insensitive comparisons' do
566
584
  expect(result.keys).to eq(%i[dsc_array dsc_ciminstance dsc_ensure dsc_name dsc_nestedciminstance dsc_time name])
567
585
  expect(result[:dsc_array]).to eq(%w[bar foo])
@@ -643,7 +661,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
643
661
  end
644
662
 
645
663
  context 'when handling DateTimes' do
646
- before(:each) do
664
+ before do
647
665
  allow(ps_manager).to receive(:execute).with(script).and_return({ stdout: 'DSC Data' })
648
666
  allow(JSON).to receive(:parse).with('DSC Data').and_return(parsed_invocation_data)
649
667
  allow(provider).to receive(:fetch_cached_hashes).and_return([])
@@ -657,7 +675,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
657
675
 
658
676
  it 'returns nil for the value' do
659
677
  expect(context).not_to receive(:err)
660
- expect(result[:dsc_time]).to eq(nil)
678
+ expect(result[:dsc_time]).to be_nil
661
679
  end
662
680
  end
663
681
 
@@ -669,7 +687,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
669
687
 
670
688
  it 'writes an error and sets the value of `dsc_time` to nil' do
671
689
  expect(context).to receive(:err).with(/Value returned for DateTime/)
672
- expect(result[:dsc_time]).to eq(nil)
690
+ expect(result[:dsc_time]).to be_nil
673
691
  end
674
692
  end
675
693
 
@@ -681,7 +699,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
681
699
 
682
700
  it 'writes an error and sets the value of `dsc_time` to nil' do
683
701
  expect(context).to receive(:err).with(/Value returned for DateTime/)
684
- expect(result[:dsc_time]).to eq(nil)
702
+ expect(result[:dsc_time]).to be_nil
685
703
  end
686
704
  end
687
705
  end
@@ -694,23 +712,26 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
694
712
  let(:query_props) { { dsc_name: 'foo', dsc_psdscrunascredential: credential_hash } }
695
713
 
696
714
  context 'when the credential is invalid' do
697
- before(:each) do
715
+ before do
698
716
  allow(provider).to receive(:logon_failed_already?).and_return(false)
699
717
  allow(ps_manager).to receive(:execute).with(script).and_return({ stdout: 'DSC Data' })
700
718
  allow(JSON).to receive(:parse).with('DSC Data').and_return({ 'errormessage' => dsc_logon_failure_error })
701
719
  allow(context).to receive(:err).with(name_hash[:name], puppet_logon_failure_error)
702
720
  end
703
- after(:each) do
721
+
722
+ after do
704
723
  described_class.class_variable_set(:@@logon_failures, nil) # rubocop:disable Style/ClassVars
705
724
  end
706
725
 
707
726
  it 'errors specifically for a logon failure and returns nil' do
708
727
  expect(result).to be_nil
709
728
  end
729
+
710
730
  it 'caches the logon failure' do
711
731
  expect { result }.not_to raise_error
712
732
  expect(described_class.class_variable_get(:@@logon_failures)).to eq([credential_hash])
713
733
  end
734
+
714
735
  it 'caches the query results' do
715
736
  expect { result }.not_to raise_error
716
737
  expect(described_class.class_variable_get(:@@cached_query_results)).to eq([name_hash])
@@ -727,7 +748,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
727
748
  end
728
749
  end
729
750
 
730
- context '.invoke_set_method' do
751
+ describe '.invoke_set_method' do
731
752
  subject(:result) { provider.invoke_set_method(context, name, should_hash) }
732
753
 
733
754
  let(:name) { { name: 'foo', dsc_name: 'foo' } }
@@ -736,7 +757,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
736
757
  let(:resource) { "Resource: #{apply_props}" }
737
758
  let(:script) { "Script: #{apply_props}" }
738
759
 
739
- before(:each) do
760
+ before do
740
761
  allow(context).to receive(:debug)
741
762
  allow(provider).to receive(:invocable_resource).with(apply_props, context, 'set').and_return(resource)
742
763
  allow(provider).to receive(:ps_script_content).with(resource).and_return(script)
@@ -750,7 +771,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
750
771
  it 'returns immediately' do
751
772
  expect(provider).to receive(:logon_failed_already?).and_return(true)
752
773
  expect(context).to receive(:err).with('Logon credentials are invalid')
753
- expect(result).to eq(nil)
774
+ expect(result).to be_nil
754
775
  end
755
776
  end
756
777
 
@@ -766,7 +787,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
766
787
  it 'writes the error via context but does not raise and returns nil' do
767
788
  expect(ps_manager).to receive(:execute).and_return({ stdout: '{"errormessage": "DSC Error!"}' })
768
789
  expect(context).to receive(:err).with('DSC Error!')
769
- expect(result).to eq(nil)
790
+ expect(result).to be_nil
770
791
  end
771
792
  end
772
793
 
@@ -779,7 +800,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
779
800
  end
780
801
  end
781
802
 
782
- context '.puppetize_name' do
803
+ describe '.puppetize_name' do
783
804
  it 'downcases the input string' do
784
805
  expect(provider.puppetize_name('FooBar')).to eq('foobar')
785
806
  end
@@ -793,7 +814,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
793
814
  end
794
815
  end
795
816
 
796
- context '.invocable_resource' do
817
+ describe '.invocable_resource' do
797
818
  subject(:result) { provider.invocable_resource(should_hash, context, 'Get') }
798
819
 
799
820
  let(:definition) do
@@ -843,7 +864,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
843
864
  let(:should_hash) { { dsc_name: 'foo' } }
844
865
  let(:vendored_modules_path) { 'C:/code/puppetlabs/gems/ruby-pwsh/lib/puppet_x/puppetdsc/dsc_resources' }
845
866
 
846
- before(:each) do
867
+ before do
847
868
  allow(context).to receive(:debug)
848
869
  allow(context).to receive(:type).and_return(type)
849
870
  allow(type).to receive(:definition).and_return(definition)
@@ -892,11 +913,11 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
892
913
  end
893
914
  end
894
915
 
895
- context '.vendored_modules_path' do
916
+ describe '.vendored_modules_path' do
896
917
  let(:load_path) { [] }
897
918
  let(:new_path_nil_root_module) { 'C:/code/puppetlabs/gems/ruby-pwsh/lib/puppet_x/puppetdsc/dsc_resources' }
898
919
 
899
- before(:each) do
920
+ before do
900
921
  allow(provider).to receive(:load_path).and_return(load_path)
901
922
  allow(File).to receive(:exist?).and_call_original
902
923
  end
@@ -954,34 +975,34 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
954
975
  end
955
976
  end
956
977
 
957
- context '.load_path' do
978
+ describe '.load_path' do
958
979
  it 'returns the ruby LOAD_PATH global variable' do
959
980
  expect(provider.load_path).to eq($LOAD_PATH)
960
981
  end
961
982
  end
962
983
 
963
- context '.invoke_test_method' do
964
- subject(:result) { provider.invoke_test_method(context, name, should) }
984
+ describe '.invoke_test_method' do
985
+ subject(:result) { provider.invoke_test_method(context, name, test_should) }
965
986
 
966
987
  let(:name) { { name: 'foo', dsc_name: 'bar' } }
967
- let(:should) { name.merge(dsc_ensure: 'present') }
968
- let(:test_properties) { should.reject { |k, _v| k == :name } }
988
+ let(:test_should) { name.merge(dsc_ensure: 'present') }
989
+ let(:test_properties) { test_should.reject { |k, _v| k == :name } }
969
990
  let(:invoke_dsc_resource_data) { nil }
970
991
 
971
- before(:each) do
992
+ before do
972
993
  allow(context).to receive(:notice)
973
994
  allow(context).to receive(:debug)
974
995
  allow(provider).to receive(:invoke_dsc_resource).with(context, name, test_properties, 'test').and_return(invoke_dsc_resource_data)
975
996
  end
976
997
 
977
- after(:each) do
998
+ after do
978
999
  described_class.class_variable_set(:@@cached_test_results, []) # rubocop:disable Style/ClassVars
979
1000
  end
980
1001
 
981
1002
  context 'when something went wrong calling Invoke-DscResource' do
982
1003
  it 'falls back on property-by-property state comparison and does not cache anything' do
983
1004
  expect(context).not_to receive(:err)
984
- expect(result).to be(nil)
1005
+ expect(result).to be_nil
985
1006
  expect(provider.cached_test_results).to eq([])
986
1007
  end
987
1008
  end
@@ -991,7 +1012,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
991
1012
 
992
1013
  it 'returns true and caches the result' do
993
1014
  expect(context).not_to receive(:err)
994
- expect(result).to eq(true)
1015
+ expect(result).to be(true)
995
1016
  expect(provider.cached_test_results).to eq([name.merge(in_desired_state: true)])
996
1017
  end
997
1018
  end
@@ -1002,7 +1023,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
1002
1023
  it 'returns false and caches the result' do
1003
1024
  expect(context).not_to receive(:err)
1004
1025
  # Resource is not in the desired state
1005
- expect(result.first).to eq(false)
1026
+ expect(result.first).to be(false)
1006
1027
  # Custom out-of-sync message passed
1007
1028
  expect(result.last).to match(/not in the desired state/)
1008
1029
  expect(provider.cached_test_results).to eq([name.merge(in_desired_state: false)])
@@ -1010,33 +1031,34 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
1010
1031
  end
1011
1032
  end
1012
1033
 
1013
- context '.random_variable_name' do
1034
+ describe '.random_variable_name' do
1014
1035
  it 'creates random variables' do
1015
1036
  expect(provider.random_variable_name).not_to be_nil
1016
1037
  end
1017
1038
 
1018
1039
  it 'includes underscores instead of hyphens' do
1019
1040
  expect(provider.random_variable_name).to match(/_/)
1020
- expect(provider.random_variable_name).to_not match(/-/)
1041
+ expect(provider.random_variable_name).not_to match(/-/)
1021
1042
  end
1022
1043
  end
1023
1044
 
1024
- context '.instantiated_variables' do
1025
- after(:each) do
1045
+ describe '.instantiated_variables' do
1046
+ after do
1026
1047
  described_class.class_variable_set(:@@instantiated_variables, nil) # rubocop:disable Style/ClassVars
1027
1048
  end
1028
1049
 
1029
1050
  it 'sets the instantiated_variables class variable to {} if not initialized' do
1030
1051
  expect(provider.instantiated_variables).to eq({})
1031
1052
  end
1053
+
1032
1054
  it 'returns the instantiated_variables class variable if already initialized' do
1033
1055
  described_class.class_variable_set(:@@instantiated_variables, { foo: 'bar' }) # rubocop:disable Style/ClassVars
1034
1056
  expect(provider.instantiated_variables).to eq({ foo: 'bar' })
1035
1057
  end
1036
1058
  end
1037
1059
 
1038
- context '.clear_instantiated_variables!' do
1039
- after(:each) do
1060
+ describe '.clear_instantiated_variables!' do
1061
+ after do
1040
1062
  described_class.class_variable_set(:@@instantiated_variables, nil) # rubocop:disable Style/ClassVars
1041
1063
  end
1042
1064
 
@@ -1047,40 +1069,41 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
1047
1069
  end
1048
1070
  end
1049
1071
 
1050
- context '.logon_failed_already?' do
1051
- let(:good_password) { instance_double('Puppet::Pops::Types::PSensitiveType::Sensitive', 'foo') }
1052
- let(:bad_password) { instance_double('Puppet::Pops::Types::PSensitiveType::Sensitive', 'bar') }
1072
+ describe '.logon_failed_already?' do
1073
+ let(:good_password) { instance_double(Puppet::Pops::Types::PSensitiveType::Sensitive, 'foo') }
1074
+ let(:bad_password) { instance_double(Puppet::Pops::Types::PSensitiveType::Sensitive, 'bar') }
1053
1075
  let(:good_credential_hash) { { 'user' => 'foo', 'password' => good_password } }
1054
1076
  let(:bad_credential_hash) { { 'user' => 'bar', 'password' => bad_password } }
1055
1077
 
1056
1078
  context 'when the logon_failures cache is empty' do
1057
1079
  it 'returns false' do
1058
- expect(provider.logon_failed_already?(good_credential_hash)).to eq(false)
1080
+ expect(provider.logon_failed_already?(good_credential_hash)).to be(false)
1059
1081
  end
1060
1082
  end
1061
1083
 
1062
1084
  context 'when the logon_failures cache has entries' do
1063
- before(:each) do
1085
+ before do
1064
1086
  allow(good_password).to receive(:unwrap).and_return('foo')
1065
1087
  allow(bad_password).to receive(:unwrap).and_return('bar')
1066
1088
  end
1067
1089
 
1068
- after(:each) do
1090
+ after do
1069
1091
  described_class.class_variable_set(:@@logon_failures, nil) # rubocop:disable Style/ClassVars
1070
1092
  end
1071
1093
 
1072
1094
  it 'returns false if there have been no failed logons with the username/password combination' do
1073
1095
  described_class.class_variable_set(:@@logon_failures, [bad_credential_hash]) # rubocop:disable Style/ClassVars
1074
- expect(provider.logon_failed_already?(good_credential_hash)).to eq(false)
1096
+ expect(provider.logon_failed_already?(good_credential_hash)).to be(false)
1075
1097
  end
1098
+
1076
1099
  it 'returns true if the username/password specified are found in the logon_failures class variable' do
1077
1100
  described_class.class_variable_set(:@@logon_failures, [good_credential_hash, bad_credential_hash]) # rubocop:disable Style/ClassVars
1078
- expect(provider.logon_failed_already?(bad_credential_hash)).to eq(true)
1101
+ expect(provider.logon_failed_already?(bad_credential_hash)).to be(true)
1079
1102
  end
1080
1103
  end
1081
1104
  end
1082
1105
 
1083
- context '.downcase_hash_keys!' do
1106
+ describe '.downcase_hash_keys!' do
1084
1107
  let(:test_hash) do
1085
1108
  {
1086
1109
  'SomeKey' => 'value',
@@ -1116,7 +1139,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
1116
1139
  end
1117
1140
  end
1118
1141
 
1119
- context '.munge_cim_instances!' do
1142
+ describe '.munge_cim_instances!' do
1120
1143
  let(:cim_instance) do
1121
1144
  {
1122
1145
  'CertificateSubject' => nil,
@@ -1147,7 +1170,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
1147
1170
  }
1148
1171
  end
1149
1172
 
1150
- before(:each) { provider.munge_cim_instances!(value) }
1173
+ before { provider.munge_cim_instances!(value) }
1151
1174
 
1152
1175
  context 'when called against a non-nested cim instance' do
1153
1176
  let(:value) { cim_instance.dup }
@@ -1164,6 +1187,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
1164
1187
  end
1165
1188
  end
1166
1189
  end
1190
+
1167
1191
  context 'when called against a nested cim instance' do
1168
1192
  let(:value) { nested_cim_instance.dup }
1169
1193
 
@@ -1190,7 +1214,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
1190
1214
  end
1191
1215
  end
1192
1216
 
1193
- context '.recursively_downcase' do
1217
+ describe '.recursively_downcase' do
1194
1218
  let(:test_hash) do
1195
1219
  {
1196
1220
  SomeKey: 'Value',
@@ -1234,7 +1258,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
1234
1258
  end
1235
1259
  end
1236
1260
 
1237
- context '.recursively_sort' do
1261
+ describe '.recursively_sort' do
1238
1262
  let(:test_hash) do
1239
1263
  {
1240
1264
  SomeKey: 'Value',
@@ -1276,26 +1300,30 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
1276
1300
  end
1277
1301
  end
1278
1302
 
1279
- context '.same?' do
1303
+ describe '.same?' do
1280
1304
  it 'compares hashes regardless of order' do
1281
1305
  expect(provider.same?({ foo: 1, bar: 2 }, { bar: 2, foo: 1 })).to be true
1282
1306
  end
1307
+
1283
1308
  it 'compares hashes with nested arrays regardless of order' do
1284
1309
  expect(provider.same?({ foo: [1, 2], bar: { baz: [1, 2] } }, { foo: [2, 1], bar: { baz: [2, 1] } })).to be true
1285
1310
  end
1311
+
1286
1312
  it 'compares arrays regardless of order' do
1287
1313
  expect(provider.same?([1, 2], [2, 1])).to be true
1288
1314
  end
1315
+
1289
1316
  it 'compares arrays with nested arrays regardless of order' do
1290
1317
  expect(provider.same?([1, [1, 2]], [[2, 1], 1])).to be true
1291
1318
  end
1319
+
1292
1320
  it 'compares non enumerables directly' do
1293
1321
  expect(provider.same?(1, 1)).to be true
1294
1322
  expect(provider.same?(1, 2)).to be false
1295
1323
  end
1296
1324
  end
1297
1325
 
1298
- context '.mandatory_get_attributes' do
1326
+ describe '.mandatory_get_attributes' do
1299
1327
  let(:attributes) do
1300
1328
  {
1301
1329
  name: { type: 'String' },
@@ -1312,7 +1340,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
1312
1340
  end
1313
1341
  end
1314
1342
 
1315
- context '.mandatory_set_attributes' do
1343
+ describe '.mandatory_set_attributes' do
1316
1344
  let(:attributes) do
1317
1345
  {
1318
1346
  name: { type: 'String' },
@@ -1329,7 +1357,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
1329
1357
  end
1330
1358
  end
1331
1359
 
1332
- context '.namevar_attributes' do
1360
+ describe '.namevar_attributes' do
1333
1361
  let(:attributes) do
1334
1362
  {
1335
1363
  name: { type: 'String', behaviour: :namevar },
@@ -1347,7 +1375,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
1347
1375
  end
1348
1376
  end
1349
1377
 
1350
- context '.parameter_attributes' do
1378
+ describe '.parameter_attributes' do
1351
1379
  let(:attributes) do
1352
1380
  {
1353
1381
  name: { type: 'String', behaviour: :namevar },
@@ -1365,7 +1393,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
1365
1393
  end
1366
1394
  end
1367
1395
 
1368
- context '.enum_attributes' do
1396
+ describe '.enum_attributes' do
1369
1397
  let(:enum_test_attributes) do
1370
1398
  {
1371
1399
  name: { type: 'String' },
@@ -1382,7 +1410,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
1382
1410
  end
1383
1411
  end
1384
1412
 
1385
- context '.interpolate_variables' do
1413
+ describe '.interpolate_variables' do
1386
1414
  let(:instantiated_variables) do
1387
1415
  {
1388
1416
  some_variable_name: 'FooBar',
@@ -1391,26 +1419,27 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
1391
1419
  }
1392
1420
  end
1393
1421
 
1394
- before(:each) do
1422
+ before do
1395
1423
  allow(provider).to receive(:instantiated_variables).and_return(instantiated_variables)
1396
1424
  end
1397
1425
 
1398
1426
  it 'replaces all discovered pointers to a variable with the variable' do
1399
1427
  expect(provider.interpolate_variables("'FooBar' ; 'FooBar'")).to eq('$some_variable_name ; $some_variable_name')
1400
1428
  end
1429
+
1401
1430
  it 'replaces discovered pointers in reverse order they were stored' do
1402
1431
  expect(provider.interpolate_variables("'Get-Foo \"bar\"'")).to eq('$third_variable_name')
1403
1432
  end
1404
1433
  end
1405
1434
 
1406
- context '.munge_psmodulepath' do
1435
+ describe '.munge_psmodulepath' do
1407
1436
  subject(:result) { provider.munge_psmodulepath(test_resource) }
1408
1437
 
1409
1438
  context 'when the resource does not have the dscmeta_resource_implementation key' do
1410
1439
  let(:test_resource) { {} }
1411
1440
 
1412
1441
  it 'returns nil' do
1413
- expect(result).to be(nil)
1442
+ expect(result).to be_nil
1414
1443
  end
1415
1444
  end
1416
1445
 
@@ -1418,7 +1447,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
1418
1447
  let(:test_resource) { { dscmeta_resource_implementation: 'MOF' } }
1419
1448
 
1420
1449
  it 'returns nil' do
1421
- expect(result).to be(nil)
1450
+ expect(result).to be_nil
1422
1451
  end
1423
1452
  end
1424
1453
 
@@ -1428,19 +1457,22 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
1428
1457
  it 'sets $UnmungedPSModulePath to the current PSModulePath' do
1429
1458
  expect(result).to match(/\$UnmungedPSModulePath = .+GetEnvironmentVariable.+PSModulePath.+machine/)
1430
1459
  end
1460
+
1431
1461
  it 'sets $MungedPSModulePath the vendor path with backslash separators' do
1432
1462
  expect(result).to match(/\$MungedPSModulePath = .+;C:\\foo\\bar/)
1433
1463
  end
1464
+
1434
1465
  it 'updates the system PSModulePath to $MungedPSModulePath' do
1435
1466
  expect(result).to match(/SetEnvironmentVariable\('PSModulePath', \$MungedPSModulePath/)
1436
1467
  end
1468
+
1437
1469
  it 'sets the process level PSModulePath to the modified system PSModulePath' do
1438
1470
  expect(result).to match(/\$env:PSModulePath = .+GetEnvironmentVariable.+PSModulePath.+machine/)
1439
1471
  end
1440
1472
  end
1441
1473
  end
1442
1474
 
1443
- context '.prepare_credentials' do
1475
+ describe '.prepare_credentials' do
1444
1476
  subject(:result) { provider.prepare_credentials(test_resource) }
1445
1477
 
1446
1478
  let(:base_resource) do
@@ -1460,8 +1492,8 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
1460
1492
  end
1461
1493
 
1462
1494
  context 'when one or more PSCredentials are passed as parameters' do
1463
- let(:foo_password) { instance_double('Puppet::Pops::Types::PSensitiveType::Sensitive', 'foo') }
1464
- let(:bar_password) { instance_double('Puppet::Pops::Types::PSensitiveType::Sensitive', 'bar') }
1495
+ let(:foo_password) { instance_double(Puppet::Pops::Types::PSensitiveType::Sensitive, 'foo') }
1496
+ let(:bar_password) { instance_double(Puppet::Pops::Types::PSensitiveType::Sensitive, 'bar') }
1465
1497
  let(:additional_parameters) do
1466
1498
  {
1467
1499
  parameters: {
@@ -1473,12 +1505,12 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
1473
1505
  end
1474
1506
  let(:test_resource) { base_resource.merge(additional_parameters) }
1475
1507
 
1476
- before(:each) do
1508
+ before do
1477
1509
  allow(foo_password).to receive(:unwrap).and_return('foo')
1478
1510
  allow(bar_password).to receive(:unwrap).and_return('bar')
1479
1511
  end
1480
1512
 
1481
- after(:each) do
1513
+ after do
1482
1514
  described_class.class_variable_set(:@@instantiated_variables, nil) # rubocop:disable Style/ClassVars
1483
1515
  end
1484
1516
 
@@ -1491,6 +1523,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
1491
1523
  expect(first_credential_hash).to eq({ 'user' => 'foo', 'password' => 'foo' })
1492
1524
  expect(second_credential_hash).to eq({ 'user' => 'bar', 'password' => 'bar' })
1493
1525
  end
1526
+
1494
1527
  it 'returns an array of strings each containing the instantiation of a PowerShell variable representing the credential hash' do
1495
1528
  expect(result[0]).to match(/^\$\w+ = New-PSCredential -User foo -Password 'foo#PuppetSensitive'/)
1496
1529
  expect(result[1]).to match(/^\$\w+ = New-PSCredential -User bar -Password 'bar#PuppetSensitive'/)
@@ -1498,7 +1531,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
1498
1531
  end
1499
1532
  end
1500
1533
 
1501
- context '.format_pscredential' do
1534
+ describe '.format_pscredential' do
1502
1535
  let(:credential_hash) { { 'user' => 'foo', 'password' => 'bar' } }
1503
1536
 
1504
1537
  it 'returns a string representing the instantiation of a PowerShell variable representing the credential hash' do
@@ -1507,10 +1540,10 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
1507
1540
  end
1508
1541
  end
1509
1542
 
1510
- context '.prepare_cim_instances' do
1543
+ describe '.prepare_cim_instances' do
1511
1544
  subject(:result) { provider.prepare_cim_instances(test_resource) }
1512
1545
 
1513
- after(:each) do
1546
+ after do
1514
1547
  described_class.class_variable_set(:@@instantiated_variables, nil) # rubocop:disable Style/ClassVars
1515
1548
  end
1516
1549
 
@@ -1528,7 +1561,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
1528
1561
  }
1529
1562
  end
1530
1563
 
1531
- before(:each) do
1564
+ before do
1532
1565
  allow(provider).to receive(:nested_cim_instances).with(test_resource[:parameters][:dsc_someciminstance][:value]).and_return([nil, nil])
1533
1566
  allow(provider).to receive(:random_variable_name).and_return('cim_foo')
1534
1567
  end
@@ -1566,7 +1599,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
1566
1599
  [[[{ 'accesscontroltype' => 'Allow', 'ensure' => 'Present', 'cim_instance_type' => 'NTFSAccessControlEntry' }], nil]]
1567
1600
  end
1568
1601
 
1569
- before(:each) do
1602
+ before do
1570
1603
  allow(provider).to receive(:nested_cim_instances).with(test_resource[:parameters][:dsc_accesscontrollist][:value]).and_return(nested_cim_instances)
1571
1604
  allow(provider).to receive(:random_variable_name).and_return('cim_foo', 'cim_bar')
1572
1605
  end
@@ -1576,6 +1609,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
1576
1609
  expect(cim_instance_declarations.first).to match(/\$cim_foo =/)
1577
1610
  expect(cim_instance_declarations.first).to match(/ClassName 'NTFSAccessControlEntry'/)
1578
1611
  end
1612
+
1579
1613
  it 'references nested cim instances as variables in the parent cim instance' do
1580
1614
  cim_instance_declarations = result.split("\n")
1581
1615
  expect(cim_instance_declarations[1]).to match(/\$cim_bar =.+Property @{'accesscontrolentry' = \[CimInstance\[\]\]@\(\$cim_foo\); 'principal' = 'veryRealUserName'}/)
@@ -1597,7 +1631,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
1597
1631
  end
1598
1632
  end
1599
1633
 
1600
- context '.nested_cim_instances' do
1634
+ describe '.nested_cim_instances' do
1601
1635
  subject(:nested_cim_instances) { provider.nested_cim_instances(enumerable).flatten }
1602
1636
 
1603
1637
  let(:enumerable) do
@@ -1617,8 +1651,8 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
1617
1651
  end
1618
1652
  end
1619
1653
 
1620
- context '.format_ciminstance' do
1621
- after(:each) do
1654
+ describe '.format_ciminstance' do
1655
+ after do
1622
1656
  described_class.class_variable_set(:@@instantiated_variables, nil) # rubocop:disable Style/ClassVars
1623
1657
  end
1624
1658
 
@@ -1627,11 +1661,13 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
1627
1661
  expected_command = "$foo = New-CimInstance -ClientOnly -ClassName 'SomeClass' -Property @{'foo' = 1; 'bar' = 'two'}"
1628
1662
  expect(provider.format_ciminstance('foo', 'SomeClass', property_hash)).to eq(expected_command)
1629
1663
  end
1664
+
1630
1665
  it 'handles arrays of cim instances' do
1631
1666
  property_hash = [{ 'foo' => 1, 'bar' => 'two' }, { 'foo' => 3, 'bar' => 'four' }]
1632
1667
  expected_cim_instance_array_regex = /Property \[CimInstance\[\]\]@\(@\{'foo' = 1; 'bar' = 'two'}, @\{'foo' = 3; 'bar' = 'four'\}\)/
1633
1668
  expect(provider.format_ciminstance('foo', 'SomeClass', property_hash)).to match(expected_cim_instance_array_regex)
1634
1669
  end
1670
+
1635
1671
  it 'interpolates variables in the case of a cim instance containing a nested instance' do
1636
1672
  described_class.class_variable_set(:@@instantiated_variables, { 'SomeVariable' => { 'bar' => 'ope' } }) # rubocop:disable Style/ClassVars
1637
1673
  property_hash = { 'foo' => { 'bar' => 'ope' } }
@@ -1639,7 +1675,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
1639
1675
  end
1640
1676
  end
1641
1677
 
1642
- context '.invoke_params' do
1678
+ describe '.invoke_params' do
1643
1679
  subject(:result) { provider.invoke_params(test_resource) }
1644
1680
 
1645
1681
  let(:test_parameter) { { dsc_name: { value: 'foo', mof_type: 'String', mof_is_embedded: false } } }
@@ -1659,9 +1695,11 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
1659
1695
  it 'includes the DSC Resource name in the output hash' do
1660
1696
  expect(result).to match(/Name = 'Foo'/)
1661
1697
  end
1698
+
1662
1699
  it 'includes the specified method in the output hash' do
1663
1700
  expect(result).to match(/Method = 'Get'/)
1664
1701
  end
1702
+
1665
1703
  it 'includes the properties as a hashtable to pass the DSC Resource in the output hash' do
1666
1704
  expect(result).to match(/Property = @\{name = 'foo'\}/)
1667
1705
  end
@@ -1685,7 +1723,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
1685
1723
  }
1686
1724
  end
1687
1725
  let(:expected_module_name) do
1688
- "ModuleName = @\{ModuleName = 'C:/path/to/ruby-pwsh/lib/puppet_x/puppetdsc/dsc_resources/PuppetDsc/PuppetDsc.psd1'; RequiredVersion = '1.2.3.4'\}"
1726
+ "ModuleName = @{ModuleName = 'C:/path/to/ruby-pwsh/lib/puppet_x/puppetdsc/dsc_resources/PuppetDsc/PuppetDsc.psd1'; RequiredVersion = '1.2.3.4'}"
1689
1727
  end
1690
1728
 
1691
1729
  it 'includes the ModuleName in the output hash as a hashtable of name and version' do
@@ -1696,7 +1734,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
1696
1734
 
1697
1735
  context 'parameter handling' do
1698
1736
  context 'PSCredential' do
1699
- let(:password) { instance_double('Puppet::Pops::Types::PSensitiveType::Sensitive', 'FooPassword') }
1737
+ let(:password) { instance_double(Puppet::Pops::Types::PSensitiveType::Sensitive, 'FooPassword') }
1700
1738
  let(:test_parameter) do
1701
1739
  { dsc_credential: { value: { 'user' => 'foo', 'password' => password }, mof_type: 'PSCredential', mof_is_embedded: false } }
1702
1740
  end
@@ -1715,7 +1753,7 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
1715
1753
  end
1716
1754
 
1717
1755
  context 'DateTime' do
1718
- let(:date_time) { instance_double('Puppet::Pops::Time::Timestamp', '2100-01-01') }
1756
+ let(:date_time) { instance_double(Puppet::Pops::Time::Timestamp, '2100-01-01') }
1719
1757
  let(:test_parameter) do
1720
1758
  { dsc_datetime: { value: date_time, mof_type: 'DateTime', mof_is_embedded: false } }
1721
1759
  end
@@ -1748,17 +1786,17 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
1748
1786
  end
1749
1787
  end
1750
1788
 
1751
- context '.ps_script_content' do
1752
- let(:gem_root) { File.expand_path('../../../../../../', __FILE__) }
1789
+ describe '.ps_script_content' do
1790
+ let(:gem_root) { File.expand_path('../../../../..', __dir__) }
1753
1791
  let(:template_path) { "#{gem_root}/lib/puppet/provider/dsc_base_provider" }
1754
- let(:functions_file_handle) { instance_double('File', 'functions_file') }
1755
- let(:preamble_file_handle) { instance_double('File', 'preamble_file') }
1756
- let(:postscript_file_handle) { instance_double('File', 'postscript_file') }
1792
+ let(:functions_file_handle) { instance_double(File, 'functions_file') }
1793
+ let(:preamble_file_handle) { instance_double(File, 'preamble_file') }
1794
+ let(:postscript_file_handle) { instance_double(File, 'postscript_file') }
1757
1795
  let(:expected_script_content) do
1758
1796
  "Functions Block\nPreamble Block\n\n\n\nParameters Block\nPostscript Block"
1759
1797
  end
1760
1798
 
1761
- before(:each) do
1799
+ before do
1762
1800
  allow(File).to receive(:new).with("#{template_path}/invoke_dsc_resource_functions.ps1").and_return(functions_file_handle)
1763
1801
  allow(functions_file_handle).to receive(:read).and_return('Functions Block')
1764
1802
  allow(File).to receive(:new).with("#{template_path}/invoke_dsc_resource_preamble.ps1").and_return(preamble_file_handle)
@@ -1777,64 +1815,76 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
1777
1815
  it 'returns a powershell script with the helper functions' do
1778
1816
  expect(provider.ps_script_content('Basic')).to match("Functions Block\n")
1779
1817
  end
1818
+
1780
1819
  it 'includes the preamble' do
1781
1820
  expect(provider.ps_script_content('Basic')).to match("Preamble Block\n")
1782
1821
  end
1822
+
1783
1823
  it 'includes the module path block, if needed' do
1784
1824
  expect(provider.ps_script_content('Basic')).not_to match("PSModulePath Block\n")
1785
1825
  expect(provider.ps_script_content('ClassBasedResource')).to match("PSModulePath Block\n")
1786
1826
  end
1827
+
1787
1828
  it 'includes the credential block, if needed' do
1788
1829
  expect(provider.ps_script_content('Basic')).not_to match("Credential Block\n")
1789
1830
  expect(provider.ps_script_content('ResourceWithCredentials')).to match("Credential Block\n")
1790
1831
  end
1832
+
1791
1833
  it 'includes the cim instances block, if needed' do
1792
1834
  expect(provider.ps_script_content('Basic')).not_to match("Cim Instance Block\n")
1793
1835
  expect(provider.ps_script_content('ResourceWithCimInstances')).to match("Cim Instance Block\n")
1794
1836
  end
1837
+
1795
1838
  it 'includes the parameters block' do
1796
1839
  expect(provider.ps_script_content('Basic')).to match("Parameters Block\n")
1797
1840
  end
1841
+
1798
1842
  it 'includes the postscript block' do
1799
1843
  expect(provider.ps_script_content('Basic')).to match('Postscript Block')
1800
1844
  end
1845
+
1801
1846
  it 'returns a single string with all the blocks joined' do
1802
1847
  expect(provider.ps_script_content('Basic')).to eq(expected_script_content)
1803
1848
  end
1804
1849
  end
1805
1850
 
1806
- context '.format' do
1851
+ describe '.format' do
1807
1852
  let(:sensitive_string) { Puppet::Pops::Types::PSensitiveType::Sensitive.new('foo') }
1808
1853
 
1809
1854
  it 'uses Pwsh::Util to format the values' do
1810
1855
  expect(Pwsh::Util).to receive(:format_powershell_value).with('foo').and_return('bar')
1811
1856
  expect(provider.format('foo')).to eq('bar')
1812
1857
  end
1858
+
1813
1859
  it 'handles sensitive values especially' do
1814
1860
  expect(Pwsh::Util).to receive(:format_powershell_value).with(sensitive_string).and_raise(RuntimeError, 'Could not format Sensitive [value redacted]')
1815
1861
  expect(provider).to receive(:unwrap).with(sensitive_string).and_return('foo#PuppetSensitive')
1816
1862
  expect(Pwsh::Util).to receive(:format_powershell_value).with('foo#PuppetSensitive').and_return("'foo#PuppetSensitive'")
1817
1863
  expect(provider.format(sensitive_string)).to eq("'foo#PuppetSensitive'")
1818
1864
  end
1865
+
1819
1866
  it 'raises an error if Pwsh::Util raises any error not related to unwrapping a sensitive string' do
1820
1867
  expect(Pwsh::Util).to receive(:format_powershell_value).with('foo').and_raise(RuntimeError, 'Ope!')
1821
1868
  expect { provider.format('foo') }.to raise_error(RuntimeError, 'Ope!')
1822
1869
  end
1823
1870
  end
1824
1871
 
1825
- context '.unwrap' do
1872
+ describe '.unwrap' do
1826
1873
  let(:sensitive_string) { Puppet::Pops::Types::PSensitiveType::Sensitive.new('foo') }
1827
1874
  let(:unwrapped_string) { 'foo#PuppetSensitive' }
1828
1875
 
1829
1876
  it 'unwraps a sensitive string, appending "#PuppetSensitive" to the end' do
1830
1877
  expect(provider.unwrap(sensitive_string)).to eq(unwrapped_string)
1831
1878
  end
1879
+
1832
1880
  it 'handles sensitive values in a hash' do
1833
1881
  expect(provider.unwrap({ key: sensitive_string })).to eq({ key: unwrapped_string })
1834
1882
  end
1883
+
1835
1884
  it 'handles sensitive values in an array' do
1836
1885
  expect(provider.unwrap([1, sensitive_string])).to eq([1, unwrapped_string])
1837
1886
  end
1887
+
1838
1888
  it 'handles sensitive values in a deeply nested structure' do
1839
1889
  sensitive_structure = {
1840
1890
  array: [sensitive_string, 'ope'],
@@ -1854,12 +1904,13 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
1854
1904
  expect(result[:hash][:nested_array]).to eq([unwrapped_string, 'bar'])
1855
1905
  expect(result[:hash][:nested_hash][:deeply_nested_value]).to eq(unwrapped_string)
1856
1906
  end
1907
+
1857
1908
  it 'returns the input if it does not include any sensitive strings' do
1858
1909
  expect(provider.unwrap('foo bar baz')).to eq('foo bar baz')
1859
1910
  end
1860
1911
  end
1861
1912
 
1862
- context '.escape_quotes' do
1913
+ describe '.escape_quotes' do
1863
1914
  let(:no_quotes) { 'foo bar baz' }
1864
1915
  let(:single_quotes) { "foo 'bar' baz" }
1865
1916
  let(:double_quotes) { 'foo "bar" baz' }
@@ -1869,13 +1920,14 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
1869
1920
  expect(provider.escape_quotes(no_quotes)).to eq(no_quotes)
1870
1921
  expect(provider.escape_quotes(double_quotes)).to eq(double_quotes)
1871
1922
  end
1923
+
1872
1924
  it "replaces single ' with '' in a given string" do
1873
1925
  expect(provider.escape_quotes(single_quotes)).to eq("foo ''bar'' baz")
1874
1926
  expect(provider.escape_quotes(mixed_quotes)).to eq("''foo'' \"bar\" ''\"baz\"''")
1875
1927
  end
1876
1928
  end
1877
1929
 
1878
- context '.redact_secrets' do
1930
+ describe '.redact_secrets' do
1879
1931
  let(:unsensitive_string) { 'some very unsecret text' }
1880
1932
  let(:sensitive_string) { "$foo = New-PSCredential -User foo -Password 'foo#PuppetSensitive'" }
1881
1933
  let(:redacted_string) { "$foo = New-PSCredential -User foo -Password '#<Sensitive [value redacted]>'" }
@@ -1929,19 +1981,21 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
1929
1981
  it 'does not modify a string without any secrets' do
1930
1982
  expect(provider.redact_secrets(unsensitive_string)).to eq(unsensitive_string)
1931
1983
  end
1984
+
1932
1985
  it 'replaces any unwrapped secret with "#<Sensitive [Value redacted]>"' do
1933
1986
  expect(provider.redact_secrets(sensitive_string)).to eq(redacted_string)
1934
1987
  expect(provider.redact_secrets(sensitive_array)).to eq(redacted_array)
1935
1988
  expect(provider.redact_secrets(sensitive_hash)).to eq(redacted_hash)
1936
1989
  expect(provider.redact_secrets(sensitive_complex)).to eq(redacted_complex)
1937
1990
  end
1991
+
1938
1992
  it 'replaces unwrapped secrets in a multiline string' do
1939
1993
  expect(provider.redact_secrets(multiline_sensitive_string)).to eq(multiline_redacted_string)
1940
1994
  expect(provider.redact_secrets(multiline_sensitive_complex)).to eq(multiline_redacted_complex)
1941
1995
  end
1942
1996
  end
1943
1997
 
1944
- context '.remove_secret_identifiers' do
1998
+ describe '.remove_secret_identifiers' do
1945
1999
  let(:unsensitive_string) { 'some very unsecret text' }
1946
2000
  let(:sensitive_string) { "$foo = New-PSCredential -User foo -Password 'foo#PuppetSensitive'" }
1947
2001
  let(:redacted_string) { "$foo = New-PSCredential -User foo -Password 'foo'" }
@@ -1995,28 +2049,32 @@ RSpec.describe Puppet::Provider::DscBaseProvider do
1995
2049
  it 'does not modify a string without any secrets' do
1996
2050
  expect(provider.remove_secret_identifiers(unsensitive_string)).to eq(unsensitive_string)
1997
2051
  end
2052
+
1998
2053
  it 'removes the secret identifier from any unwrapped secret' do
1999
2054
  expect(provider.remove_secret_identifiers(sensitive_string)).to eq(redacted_string)
2000
2055
  expect(provider.remove_secret_identifiers(sensitive_array)).to eq(redacted_array)
2001
2056
  expect(provider.remove_secret_identifiers(sensitive_hash)).to eq(redacted_hash)
2002
2057
  expect(provider.remove_secret_identifiers(sensitive_complex)).to eq(redacted_complex)
2003
2058
  end
2059
+
2004
2060
  it 'removes the secret identifier from any unwrapped secrets in a multiline string' do
2005
2061
  expect(provider.remove_secret_identifiers(multiline_sensitive_string)).to eq(multiline_redacted_string)
2006
2062
  expect(provider.remove_secret_identifiers(multiline_sensitive_complex)).to eq(multiline_redacted_complex)
2007
2063
  end
2008
2064
  end
2009
2065
 
2010
- context '.ps_manager' do
2011
- before(:each) do
2066
+ describe '.ps_manager' do
2067
+ before do
2012
2068
  allow(Pwsh::Manager).to receive(:powershell_path).and_return('pwsh')
2013
2069
  allow(Pwsh::Manager).to receive(:powershell_args).and_return('args')
2014
2070
  end
2071
+
2015
2072
  it 'Initializes an instance of the Pwsh::Manager' do
2016
2073
  expect(Puppet::Util::Log).to receive(:level).and_return(:normal)
2017
2074
  expect(Pwsh::Manager).to receive(:instance).with('pwsh', 'args', debug: false)
2018
2075
  expect { provider.ps_manager }.not_to raise_error
2019
2076
  end
2077
+
2020
2078
  it 'passes debug as true if Puppet::Util::Log.level is debug' do
2021
2079
  expect(Puppet::Util::Log).to receive(:level).and_return(:debug)
2022
2080
  expect(Pwsh::Manager).to receive(:instance).with('pwsh', 'args', debug: true)