ruby-pwsh 0.10.1 → 0.10.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bdcbcec4cceaa40f4fabaad50f9d7409382c14eb1a98a345af5770aa1ae78f31
4
- data.tar.gz: 48f16a70a2305b398a9098d453ae743a6c2630a94cdc8d6716250e1e4ee83464
3
+ metadata.gz: adc4879de83f4b7756c10664ab59c44ab3b34e93e848ebedcefb049c969137f8
4
+ data.tar.gz: 7ffc7b8c36775a252075fe3c0bffbb60c8b2e287bcbec65d61c1594f6ff4522a
5
5
  SHA512:
6
- metadata.gz: 7c19486fd5452d81c71e7939fddaa78c66972ddb425806fc894b1aeecf0cb94b917955d29245130095ee5c4c85d63f2ba12176b6ef8fe4ce7e6f9f653bb0224c
7
- data.tar.gz: b12c1ab52269745152a29ce446876a3e06f3b9f9aab1d254157d8f93c6cccb1e7f997c118488229e22d8800a1a1a17af0557a8c0af2ea386d3e80e80c2f5bfd0
6
+ metadata.gz: 638fb1d09d7c0ec4fe29ee0473dba74cdbf2aa142a730eed6c43b0e472ec2f3a7452a87e18ff8c36a4dd95f0897ec8388d30357406481aea8772d409087183b7
7
+ data.tar.gz: d5de2cb597e68c7c911b36c1cd92cbfc50a13916570f744bc8674b138ed62c30cc728ac2dba8f50a2856e6915ceb48ceede851c6f11a91cf8cca1af2d6cdfe9c
data/README.md CHANGED
@@ -74,47 +74,51 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
74
74
 
75
75
  Steps to release an update to the gem and module include:
76
76
 
77
- 1. Ensure that the release branch is up to date with the main:
77
+ 1. From main, checkout a new working branch for the release prep (where xyz is the appropriate version, sans periods):
78
78
  ```bash
79
- git push upstream upstream/main:release --force
79
+ git checkout -b maint-release_prep_xyz
80
80
  ```
81
- 1. Checkout a new working branch for the release prep (where xyz is the appropriate version, sans periods):
82
- ```bash
83
- git checkout -b maint/release/prep-xyz upstream/release
84
- ```
85
- 1. Update the version in `lib/pwsh/version.rb` and `metadata.json` to the appropriate version for the new release.
86
- 1. Run the changelog update task (make sure to verify the changelog, correctly tagging PRs as needed):
81
+
82
+ 2. Update the version in `lib/pwsh/version.rb` and `metadata.json` to the appropriate version for the new release.
83
+
84
+ 3. Run the changelog update task (make sure to verify the changelog, correctly tagging PRs as needed):
87
85
  ```bash
88
86
  bundle exec rake changelog
89
87
  ```
90
- 1. Commit your changes with a short, sensible commit message, like:
91
- ```text
88
+
89
+ 4. Commit your changes with a short, sensible commit message, like:
90
+ ```bash
92
91
  git add lib/pwsh/version.rb
93
92
  git add metadata.json
94
93
  git add CHANGELOG.md
95
94
  git commit -m '(MAINT) Prep for x.y.z release'
96
95
  ```
97
- 1. Push your changes and submit a pull request for review _against the **release** branch_:
98
- ```bash
99
- git push -u origin maint/release/prep-xyz
100
- ```
101
- 1. Ensure tests pass and the code is merged to `release`.
102
- 1. Grab the commit hash from the merge commit on release, use that as the tag for the version (replacing `x.y.z` with the appropriate version and `commithash` with the relevant one), then push the tags to upstream:
96
+
97
+ 5. Push your changes and submit a pull request for review _against main:
103
98
  ```bash
104
- bundle exec rake tag['x.y.z', 'commithash']
99
+ git push -u origin maint_release_prep_xyz
105
100
  ```
106
- 1. Build the Ruby gem and publish:
101
+
102
+ 6. Ensure tests pass and the code is merged to `main`.
103
+
104
+ 7. Once the release_prep PR has been merged, checkout main and pull down the latests changes.
107
105
  ```bash
108
- bundle exec rake build
109
- bundle exec rake push['ruby-pwsh-x.y.z.gem']
106
+ git checkout main
107
+ git pull
110
108
  ```
111
- 1. Verify that the correct version now exists on [RubyGems](https://rubygems.org/search?query=ruby-pwsh)
112
- 1. Build the Puppet module:
109
+
110
+ 8. Assuming that the release_prep merge commit is at the HEAD of main we can simply create and push a tag as follows (replacing xyz with the appropriate version).
113
111
  ```bash
114
- bundle exec rake build_module
112
+ git tag -a xyx -m "Release xyz"
113
+ git push --follow-tags
115
114
  ```
116
- 1. Publish the updated module version (found in the `pkg` folder) to [the Forge](https://forge.puppet.com/puppetlabs/pwshlib).
117
- 1. Submit the [mergeback PR from the release branch to main](https://github.com/puppetlabs/ruby-pwsh/compare/main...release).
115
+
116
+ 9. Execute the publish workflow. This will:
117
+ - Create a GitHub release
118
+ - Build and publish the Gem
119
+ - Build and publish the Puppet module
120
+
121
+ 10. Finally check that the expected versions are present on rubygems.org and the Forge.
118
122
 
119
123
  ## Known Issues
120
124
 
@@ -79,6 +79,9 @@ class Puppet::Provider::DscBaseProvider
79
79
  end
80
80
  downcased_result = recursively_downcase(canonicalized)
81
81
  downcased_resource = recursively_downcase(r)
82
+ # Ensure that metaparameters are preserved when we canonicalize the resource.
83
+ metaparams = downcased_resource.select { |key, _value| Puppet::Type.metaparam?(key) }
84
+ canonicalized.merge!(metaparams) unless metaparams.nil?
82
85
  downcased_result.each do |key, value|
83
86
  # Canonicalize to the manifest value unless the downcased strings match and the attribute is not an enum:
84
87
  # - When the values don't match at all, the manifest value is desired;
data/lib/pwsh/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Pwsh
4
4
  # The version of the ruby-pwsh gem
5
- VERSION = '0.10.1'
5
+ VERSION = '0.10.3'
6
6
  end
data/lib/pwsh.rb CHANGED
@@ -406,7 +406,7 @@ Invoke-PowerShellUserCode @params
406
406
  #
407
407
  # @return[String] Unique string representing the manager instance.
408
408
  def self.instance_key(cmd, args, options)
409
- cmd + args.join(' ') + options[:debug].to_s
409
+ cmd + args.join(' ') + options.to_s
410
410
  end
411
411
 
412
412
  # Return whether or not a particular stream is valid and readable
@@ -35,8 +35,18 @@ $global:ourFunctions = @'
35
35
  function Reset-ProcessEnvironmentVariables {
36
36
  param($CachedEnvironmentVariables)
37
37
 
38
+ # When Protected Event Logging and PowerShell Script Block logging are enabled together
39
+ # the SystemRoot environment variable is a requirement. If it is removed as part of this purge
40
+ # it causes the PowerShell process to crash, therefore breaking the pipe between Ruby and the
41
+ # remote PowerShell session.
42
+ # The least descructive way to avoid this is to filter out SystemRoot when pulling our current list
43
+ # of environment variables. Then we can continue safely with the removal.
44
+ $CurrentEnvironmentVariables = Get-ChildItem -Path Env:\* |
45
+ Where-Object {$_.Name -ne "SystemRoot"}
46
+
38
47
  # Delete existing environment variables
39
- Remove-Item -Path Env:\* -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Recurse
48
+ $CurrentEnvironmentVariables |
49
+ ForEach-Object -Process { Remove-Item -Path "ENV:\$($_.Name)" -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Recurse }
40
50
 
41
51
  # Re-add the cached environment variables
42
52
  $CachedEnvironmentVariables |
@@ -0,0 +1,205 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'ruby-pwsh'
5
+ require 'securerandom'
6
+
7
+ powershell = Pwsh::Manager.instance(Pwsh::Manager.powershell_path, Pwsh::Manager.powershell_args)
8
+ module_path = File.expand_path('../../fixtures/modules', File.dirname(__FILE__))
9
+ powershellget_path = File.expand_path('powershellget/lib/puppet_x/powershellget/dsc_resources/PowerShellGet', module_path)
10
+ local_user = ['dsc', SecureRandom.uuid.slice(0, 7)].join('_')
11
+ local_pw = SecureRandom.uuid
12
+
13
+ def execute_reset_command(reset_command)
14
+ manager = Pwsh::Manager.instance(Pwsh::Manager.powershell_path, Pwsh::Manager.powershell_args)
15
+ result = manager.execute(reset_command)
16
+ raise result[:errormessage] unless result[:errormessage].nil?
17
+ end
18
+
19
+ RSpec.describe 'DSC Acceptance: Basic' do
20
+ let(:puppet_apply) do
21
+ "bundle exec puppet apply --modulepath #{module_path} --detailed-exitcodes --debug --trace"
22
+ end
23
+ let(:command) { "#{puppet_apply} -e \"#{manifest}\"" }
24
+
25
+ context 'Updating' do
26
+ let(:manifest) do
27
+ # This very awkward pattern is because we're not writing
28
+ # manifest files and need to pass them directly to puppet apply.
29
+ [
30
+ "dsc_psrepository { 'Trust PSGallery':",
31
+ "dsc_name => 'PSGallery',",
32
+ "dsc_ensure => 'Present',",
33
+ "dsc_installationpolicy => 'Trusted'",
34
+ '}'
35
+ ].join(' ')
36
+ end
37
+
38
+ before(:all) do
39
+ reset_command = <<~RESET_COMMAND
40
+ $ErrorActionPreference = 'Stop'
41
+ Import-Module PowerShellGet
42
+ $ResetParameters = @{
43
+ Name = 'PSRepository'
44
+ ModuleName = '#{powershellget_path}'
45
+ Method = 'Set'
46
+ Property = @{
47
+ Name = 'PSGallery'
48
+ Ensure = 'Present'
49
+ InstallationPolicy = 'Untrusted'
50
+ }
51
+ }
52
+ Invoke-DscResource @ResetParameters | ConvertTo-Json -Compress
53
+ RESET_COMMAND
54
+ execute_reset_command(reset_command)
55
+ end
56
+
57
+ it 'applies idempotently' do
58
+ first_run_result = powershell.execute(command)
59
+ expect(first_run_result[:exitcode]).to be(2)
60
+ expect(first_run_result[:native_stdout]).to match(/dsc_installationpolicy changed 'Untrusted' to 'Trusted'/)
61
+ expect(first_run_result[:native_stdout]).to match(/Updating: Finished/)
62
+ expect(first_run_result[:native_stdout]).to match(/Applied catalog/)
63
+ second_run_result = powershell.execute(command)
64
+ expect(second_run_result[:exitcode]).to be(0)
65
+ end
66
+ end
67
+ context 'Creating' do
68
+ let(:manifest) do
69
+ [
70
+ "dsc_psmodule { 'Install BurntToast':",
71
+ "dsc_name => 'BurntToast',",
72
+ "dsc_ensure => 'Present',",
73
+ '}'
74
+ ].join(' ')
75
+ end
76
+
77
+ before(:all) do
78
+ reset_command = <<~RESET_COMMAND
79
+ $ErrorActionPreference = 'Stop'
80
+ Import-Module PowerShellGet
81
+ Get-InstalledModule -Name BurntToast -ErrorAction SilentlyContinue |
82
+ Uninstall-Module -Force
83
+ RESET_COMMAND
84
+ execute_reset_command(reset_command)
85
+ end
86
+
87
+ it 'applies idempotently' do
88
+ first_run_result = powershell.execute(command)
89
+ expect(first_run_result[:exitcode]).to be(2)
90
+ expect(first_run_result[:native_stdout]).to match(/dsc_ensure changed 'Absent' to 'Present'/)
91
+ expect(first_run_result[:native_stdout]).to match(/Creating: Finished/)
92
+ expect(first_run_result[:native_stdout]).to match(/Applied catalog/)
93
+ second_run_result = powershell.execute(command)
94
+ expect(second_run_result[:exitcode]).to be(0)
95
+ end
96
+ end
97
+
98
+ context 'Deleting' do
99
+ let(:manifest) do
100
+ [
101
+ "dsc_psmodule { 'Install BurntToast':",
102
+ "dsc_name => 'BurntToast',",
103
+ "dsc_ensure => 'Absent',",
104
+ '}'
105
+ ].join(' ')
106
+ end
107
+
108
+ before(:all) do
109
+ reset_command = <<~RESET_COMMAND
110
+ $ErrorActionPreference = 'Stop'
111
+ Import-Module PowerShellGet
112
+ $Installed = Get-InstalledModule -Name BurntToast -ErrorAction SilentlyContinue
113
+ If($null -eq $Installed) {
114
+ Install-Module -Name BurntToast -Scope AllUsers -Force
115
+ }
116
+ RESET_COMMAND
117
+ execute_reset_command(reset_command)
118
+ end
119
+
120
+ it 'applies idempotently' do
121
+ first_run_result = powershell.execute(command)
122
+ expect(first_run_result[:exitcode]).to be(2)
123
+ expect(first_run_result[:native_stdout]).to match(/dsc_ensure changed 'Present' to 'Absent'/)
124
+ expect(first_run_result[:native_stdout]).to match(/Deleting: Finished/)
125
+ expect(first_run_result[:native_stdout]).to match(/Applied catalog/)
126
+ second_run_result = powershell.execute(command)
127
+ expect(second_run_result[:exitcode]).to be(0)
128
+ end
129
+ end
130
+ context 'PSDscRunAsCredential' do
131
+ before(:all) do
132
+ prep_command = <<~PREP_USER.strip
133
+ $ErrorActionPreference = 'Stop'
134
+ $User = Get-LocalUser -Name #{local_user} -ErrorAction SilentlyContinue
135
+ If ($null -eq $User) {
136
+ $Secure = ConvertTo-SecureString -String '#{local_pw}' -AsPlainText -Force
137
+ $User = New-LocalUser -Name #{local_user} -Password $Secure -Verbose
138
+ }
139
+ If ($User.Name -notin (Get-LocalGroupMember -Group Administrators).Name) {
140
+ Add-LocalGroupMember -Group Administrators -Member $User -Verbose
141
+ }
142
+ Get-LocalGroupMember -Group Administrators |
143
+ Where-Object Name -match '#{local_user}'
144
+ PREP_USER
145
+ execute_reset_command(prep_command)
146
+ end
147
+ after(:all) do
148
+ cleanup_command = <<~CLEANUP_USER.strip
149
+ Remove-LocalUser -Name #{local_user} -ErrorAction Stop
150
+ CLEANUP_USER
151
+ execute_reset_command(cleanup_command)
152
+ end
153
+
154
+ context 'with a valid credential' do
155
+ let(:manifest) do
156
+ [
157
+ "dsc_psrepository { 'Trust PSGallery':",
158
+ "dsc_name => 'PSGallery',",
159
+ "dsc_ensure => 'Present',",
160
+ "dsc_installationpolicy => 'Trusted',",
161
+ 'dsc_psdscrunascredential => {',
162
+ "'user' => '#{local_user}',",
163
+ "'password' => Sensitive('#{local_pw}')",
164
+ '}',
165
+ '}'
166
+ ].join(' ')
167
+ end
168
+
169
+ it 'applies idempotently without leaking secrets' do
170
+ first_run_result = powershell.execute(command)
171
+ expect(first_run_result[:exitcode]).to be(2)
172
+ expect(first_run_result[:native_stdout]).to match(/dsc_installationpolicy changed 'Untrusted' to 'Trusted'/)
173
+ expect(first_run_result[:native_stdout]).to match(/Updating: Finished/)
174
+ expect(first_run_result[:native_stdout]).to match(/Applied catalog/)
175
+ expect(first_run_result[:native_stdout]).to match(/'#<Sensitive \[value redacted\]>'/)
176
+ expect(first_run_result[:native_stdout]).not_to match(local_pw)
177
+ second_run_result = powershell.execute(command)
178
+ expect(second_run_result[:exitcode]).to be(0)
179
+ end
180
+ end
181
+ context 'with an invalid credential' do
182
+ let(:manifest) do
183
+ [
184
+ "dsc_psrepository { 'Trust PSGallery':",
185
+ "dsc_name => 'PSGallery',",
186
+ "dsc_ensure => 'Present',",
187
+ "dsc_installationpolicy => 'Trusted',",
188
+ 'dsc_psdscrunascredential => {',
189
+ "'user' => 'definitely_do_not_exist_here',",
190
+ "'password' => Sensitive('#{local_pw}')",
191
+ '}',
192
+ '}'
193
+ ].join(' ')
194
+ end
195
+
196
+ it 'errors loudly without leaking secrets' do
197
+ first_run_result = powershell.execute(command)
198
+ expect(first_run_result[:exitcode]).to be(4)
199
+ expect(first_run_result[:stderr].first).to match(/dsc_psrepository: The user name or password is incorrect/)
200
+ expect(first_run_result[:native_stdout]).to match(/'#<Sensitive \[value redacted\]>'/)
201
+ expect(first_run_result[:native_stdout]).not_to match(local_pw)
202
+ end
203
+ end
204
+ end
205
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+ # TODO: Test against mcollera/AccessControlDsc for CIM instance behavior
3
+ # 1. Make sure valid nested CIM instances can be passed to Invoke-DscResource
4
+ # 2. Make sure nested CIM instances can be read back from Invoke-DscResource
5
+
6
+ # frozen_string_literal: true
7
+
8
+ require 'spec_helper'
9
+ require 'ruby-pwsh'
10
+
11
+ # Needs to be declared here so it is usable in before and it blocks alike
12
+ test_manifest = File.expand_path('../../fixtures/test.pp', File.dirname(__FILE__))
13
+ fixtures_path = File.expand_path('../../fixtures', File.dirname(__FILE__))
14
+
15
+ def execute_reset_command(reset_command)
16
+ manager = Pwsh::Manager.instance(Pwsh::Manager.powershell_path, Pwsh::Manager.powershell_args)
17
+ result = manager.execute(reset_command)
18
+ raise result[:errormessage] unless result[:errormessage].nil?
19
+ end
20
+
21
+ RSpec.describe 'DSC Acceptance: Complex' do
22
+ let(:powershell) { Pwsh::Manager.instance(Pwsh::Manager.powershell_path, Pwsh::Manager.powershell_args) }
23
+ let(:module_path) { File.expand_path('../../fixtures/modules', File.dirname(__FILE__)) }
24
+ let(:puppet_apply) do
25
+ "bundle exec puppet apply #{test_manifest} --modulepath #{module_path} --detailed-exitcodes --trace"
26
+ end
27
+
28
+ context 'Managing the access control list of a folder' do
29
+ before(:each) do
30
+ reset_command = <<~RESET_COMMAND
31
+ $TestFolderPath = Join-Path -Path "#{fixtures_path}" -Childpath access_control
32
+ # Delete the test folder if it exists (to clear access control modifications)
33
+ If (Test-Path -Path $TestFolderPath -PathType Container) {
34
+ Remove-Item $TestFolderPath -Recurse -Force
35
+ }
36
+ # Create the test folder
37
+ New-Item $TestFolderPath -ItemType Directory
38
+ RESET_COMMAND
39
+ execute_reset_command(reset_command)
40
+ end
41
+
42
+ it 'applies idempotently' do
43
+ content = <<~MANIFEST.strip
44
+ $test_folder_path = "#{fixtures_path}/access_control"
45
+ # Configure access to the test folder
46
+ dsc_ntfsaccessentry {'Test':
47
+ dsc_path => $test_folder_path,
48
+ dsc_accesscontrollist => [
49
+ {
50
+ principal => 'Everyone',
51
+ forceprincipal => true,
52
+ accesscontrolentry => [
53
+ {
54
+ accesscontroltype => 'Allow',
55
+ filesystemrights => ['FullControl'],
56
+ inheritance => 'This folder and files',
57
+ ensure => 'Present',
58
+ cim_instance_type => 'NTFSAccessControlEntry',
59
+ }
60
+ ]
61
+ }
62
+ ]
63
+ }
64
+ MANIFEST
65
+ File.open(test_manifest, 'w') { |file| file.write(content) }
66
+ # Apply the test manifest
67
+ first_run_result = powershell.execute(puppet_apply)
68
+ expect(first_run_result[:exitcode]).to be(2)
69
+ # Access Control Set
70
+ expect(first_run_result[:native_stdout]).to match(/dsc_accesscontrollist: dsc_accesscontrollist changed/)
71
+ expect(first_run_result[:native_stdout]).to match(%r{dsc_ntfsaccessentry\[{:name=>"Test", :dsc_path=>".+/spec/fixtures/access_control"}\]: Updating: Finished})
72
+ expect(first_run_result[:stderr]).not_to match(/Error/)
73
+ expect(first_run_result[:stderr]).not_to match(/Warning: Provider returned data that does not match the Type Schema/)
74
+ expect(first_run_result[:stderr]).not_to match(/Value type mismatch/)
75
+ # Run finished
76
+ expect(first_run_result[:native_stdout]).to match(/Applied catalog/)
77
+ # Second run is idempotent
78
+ second_run_result = powershell.execute(puppet_apply)
79
+ expect(second_run_result[:exitcode]).to be(0)
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,129 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'ruby-pwsh'
5
+
6
+ powershell = Pwsh::Manager.instance(Pwsh::Manager.powershell_path, Pwsh::Manager.powershell_args)
7
+ module_path = File.expand_path('../../fixtures/modules', File.dirname(__FILE__))
8
+ psrc_path = File.expand_path('../../fixtures/example.psrc', File.dirname(__FILE__))
9
+
10
+ def execute_reset_command(reset_command)
11
+ manager = Pwsh::Manager.instance(Pwsh::Manager.powershell_path, Pwsh::Manager.powershell_args)
12
+ result = manager.execute(reset_command)
13
+ raise result[:errormessage] unless result[:errormessage].nil?
14
+ end
15
+
16
+ RSpec.describe 'DSC Acceptance: Class-Based Resource' do
17
+ let(:puppet_apply) do
18
+ "bundle exec puppet apply --modulepath #{module_path} --detailed-exitcodes --debug --trace"
19
+ end
20
+ let(:command) { "#{puppet_apply} -e \"#{manifest}\"" }
21
+
22
+ context 'Creating' do
23
+ let(:manifest) do
24
+ # This very awkward pattern is because we're not writing
25
+ # manifest files and need to pass them directly to puppet apply.
26
+ [
27
+ "dsc_jearolecapabilities { 'ExampleRoleCapability':",
28
+ "dsc_ensure => 'Present',",
29
+ "dsc_path => '#{psrc_path}',",
30
+ "dsc_description => 'Example role capability file'",
31
+ '}'
32
+ ].join(' ')
33
+ end
34
+
35
+ before(:each) do
36
+ reset_command = <<~RESET_COMMAND
37
+ $PsrcPath = '#{psrc_path}'
38
+ # Delete the test PSRC fixture if it exists
39
+ If (Test-Path -Path $PsrcPath -PathType Leaf) {
40
+ Remove-Item $PsrcPath -Force
41
+ }
42
+ RESET_COMMAND
43
+ execute_reset_command(reset_command)
44
+ end
45
+
46
+ it 'applies idempotently' do
47
+ first_run_result = powershell.execute(command)
48
+ expect(first_run_result[:exitcode]).to be(2)
49
+ expect(first_run_result[:native_stdout]).to match(//)
50
+ expect(first_run_result[:native_stdout]).to match(/dsc_description changed to 'Example role capability file'/)
51
+ expect(first_run_result[:native_stdout]).to match(/Creating: Finished/)
52
+ expect(first_run_result[:native_stdout]).to match(/Applied catalog/)
53
+ second_run_result = powershell.execute(command)
54
+ expect(second_run_result[:exitcode]).to be(0)
55
+ end
56
+ end
57
+
58
+ context 'Updating' do
59
+ let(:manifest) do
60
+ # This very awkward pattern is because we're not writing
61
+ # manifest files and need to pass them directly to puppet apply.
62
+ [
63
+ "dsc_jearolecapabilities { 'ExampleRoleCapability':",
64
+ "dsc_ensure => 'Present',",
65
+ "dsc_path => '#{psrc_path}',",
66
+ "dsc_description => 'Updated role capability file'",
67
+ '}'
68
+ ].join(' ')
69
+ end
70
+
71
+ before(:each) do
72
+ reset_command = <<~RESET_COMMAND
73
+ $PsrcPath = '#{psrc_path}'
74
+ # Delete the test PSRC fixture if it exists
75
+ If (Test-Path -Path $PsrcPath -PathType Leaf) {
76
+ Remove-Item $PsrcPath -Force
77
+ }
78
+ # Create the test PSRC fixture
79
+ New-Item $PsrcPath -ItemType File -Value "@{'Description' = 'Example role capability file'}"
80
+ RESET_COMMAND
81
+ execute_reset_command(reset_command)
82
+ end
83
+
84
+ it 'applies idempotently' do
85
+ first_run_result = powershell.execute(command)
86
+ expect(first_run_result[:exitcode]).to be(2)
87
+ expect(first_run_result[:native_stdout]).to match(/dsc_description changed 'Example role capability file' to 'Updated role capability file'/)
88
+ expect(first_run_result[:native_stdout]).to match(/Updating: Finished/)
89
+ expect(first_run_result[:native_stdout]).to match(/Applied catalog/)
90
+ second_run_result = powershell.execute(command)
91
+ expect(second_run_result[:exitcode]).to be(0)
92
+ end
93
+ end
94
+
95
+ context 'Deleting' do
96
+ let(:manifest) do
97
+ # This very awkward pattern is because we're not writing
98
+ # manifest files and need to pass them directly to puppet apply.
99
+ [
100
+ "dsc_jearolecapabilities { 'ExampleRoleCapability':",
101
+ "dsc_ensure => 'Absent',",
102
+ "dsc_path => '#{psrc_path}'",
103
+ '}'
104
+ ].join(' ')
105
+ end
106
+
107
+ before(:each) do
108
+ reset_command = <<~RESET_COMMAND
109
+ $PsrcPath = '#{psrc_path}'
110
+ # Delete the test PSRC fixture if it exists
111
+ If (!(Test-Path -Path $PsrcPath -PathType Leaf)) {
112
+ # Create the test PSRC fixture
113
+ New-Item $PsrcPath -ItemType File -Value "@{'Description' = 'Updated'}"
114
+ }
115
+ RESET_COMMAND
116
+ execute_reset_command(reset_command)
117
+ end
118
+
119
+ it 'applies idempotently' do
120
+ first_run_result = powershell.execute(command)
121
+ expect(first_run_result[:exitcode]).to be(2)
122
+ expect(first_run_result[:native_stdout]).to match(/dsc_ensure changed 'Present' to 'Absent'/)
123
+ expect(first_run_result[:native_stdout]).to match(/Deleting: Finished/)
124
+ expect(first_run_result[:native_stdout]).to match(/Applied catalog/)
125
+ second_run_result = powershell.execute(command)
126
+ expect(second_run_result[:exitcode]).to be(0)
127
+ end
128
+ end
129
+ end