ruby-pwsh 0.10.3 → 0.11.0.rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +16 -38
- data/lib/puppet/provider/dsc_base_provider/dsc_base_provider.rb +20 -20
- data/lib/pwsh/version.rb +1 -1
- data/lib/pwsh/windows_powershell.rb +2 -2
- data/lib/pwsh.rb +31 -34
- data/spec/acceptance/dsc/basic.rb +4 -0
- data/spec/acceptance/dsc/cim_instances.rb +3 -4
- data/spec/acceptance/dsc/class.rb +3 -3
- data/spec/acceptance/dsc/complex.rb +2 -2
- data/spec/acceptance/support/setup_winrm.ps1 +6 -0
- data/spec/unit/puppet/provider/dsc_base_provider/dsc_base_provider_spec.rb +171 -113
- data/spec/unit/pwsh/util_spec.rb +100 -93
- data/spec/unit/pwsh/version_spec.rb +2 -2
- data/spec/unit/pwsh/windows_powershell_spec.rb +18 -13
- data/spec/unit/pwsh_spec.rb +61 -63
- metadata +6 -5
@@ -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(
|
12
|
-
let(:type) { instance_double(
|
13
|
-
let(:ps_manager) { instance_double(
|
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
|
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
|
-
|
25
|
-
before
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
-
|
234
|
-
after
|
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
|
-
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
-
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
-
|
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
|
-
|
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
|
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
|
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
|
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
|
-
|
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
|
-
|
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
|
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
|
-
|
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
|
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
|
-
|
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
|
-
|
964
|
-
subject(:result) { provider.invoke_test_method(context, name,
|
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(:
|
968
|
-
let(:test_properties) {
|
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
|
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
|
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
|
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
|
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
|
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
|
-
|
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).
|
1041
|
+
expect(provider.random_variable_name).not_to match(/-/)
|
1021
1042
|
end
|
1022
1043
|
end
|
1023
1044
|
|
1024
|
-
|
1025
|
-
after
|
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
|
-
|
1039
|
-
after
|
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
|
-
|
1051
|
-
let(:good_password) { instance_double(
|
1052
|
-
let(:bad_password) { instance_double(
|
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
|
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
|
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
|
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
|
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
|
1101
|
+
expect(provider.logon_failed_already?(bad_credential_hash)).to be(true)
|
1079
1102
|
end
|
1080
1103
|
end
|
1081
1104
|
end
|
1082
1105
|
|
1083
|
-
|
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
|
-
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
-
|
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
|
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
|
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
|
-
|
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(
|
1464
|
-
let(:bar_password) { instance_double(
|
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
|
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
|
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
|
-
|
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
|
-
|
1543
|
+
describe '.prepare_cim_instances' do
|
1511
1544
|
subject(:result) { provider.prepare_cim_instances(test_resource) }
|
1512
1545
|
|
1513
|
-
after
|
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
|
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
|
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
|
-
|
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
|
-
|
1621
|
-
after
|
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
|
-
|
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 =
|
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(
|
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(
|
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
|
-
|
1752
|
-
let(:gem_root) { File.expand_path('
|
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(
|
1755
|
-
let(:preamble_file_handle) { instance_double(
|
1756
|
-
let(:postscript_file_handle) { instance_double(
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
2011
|
-
before
|
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)
|