Skip to content

Commit 2aca2e9

Browse files
committed
(CAT-2432) Troubleshoot deferred resources in DSC
Implementing new test cases to test deferred values to DSC resources.
1 parent 5213ae0 commit 2aca2e9

File tree

8 files changed

+170
-2
lines changed

8 files changed

+170
-2
lines changed

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
/junit/
1616
/log/
1717
/pkg/
18-
/spec/fixtures/manifests/
1918
/spec/fixtures/modules/*
2019
/tmp/
2120
/vendor/

.rubocop_todo.yml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
# This configuration was generated by
22
# `rubocop --auto-gen-config`
3-
# on 2025-10-01 08:51:22 UTC using RuboCop version 1.73.2.
3+
# on 2025-10-08 10:43:51 UTC using RuboCop version 1.73.2.
44
# The point is for the user to remove these configuration records
55
# one by one as the offenses are removed from the code base.
66
# Note that changes in the inspected code, or installation of new
77
# versions of RuboCop, may require this file to be generated again.
88

9+
# Offense count: 2
10+
# This cop supports safe autocorrection (--autocorrect).
11+
RSpec/ExpectActual:
12+
Exclude:
13+
- '**/spec/routing/**/*'
14+
- 'spec/acceptance/deferred_spec.rb'
15+
916
# Offense count: 2
1017
# Configuration parameters: Include, CustomTransform, IgnoreMethods, IgnoreMetadata.
1118
# Include: **/*_spec.rb

spec/acceptance/deferred_spec.rb

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# spec/acceptance/deferred_spec.rb
2+
# frozen_string_literal: true
3+
4+
require 'spec_helper_acceptance'
5+
6+
def read_fixture(name)
7+
File.read(File.join(__dir__, '..', 'fixtures', 'manifests', name))
8+
end
9+
10+
def read_win_file_if_exists(path)
11+
# Use a script block with literals; avoid $variables to prevent transport/quoting expansion
12+
# Also keep exit 0 regardless of existence so run_shell doesn't raise.
13+
ps = %{& { if (Test-Path -LiteralPath '#{path}') { Get-Content -Raw -LiteralPath '#{path}' } else { '<<<FILE_NOT_FOUND>>>' } } }
14+
r = run_shell(%(powershell.exe -NoProfile -NonInteractive -Command "#{ps}"))
15+
body = (r.stdout || '').to_s
16+
exists = !body.include?('<<<FILE_NOT_FOUND>>>')
17+
{ exists: exists, content: exists ? body : '' }
18+
end
19+
20+
describe 'deferred values with dsc_lite' do
21+
let(:control_manifest) { read_fixture('01_file_deferred.pp') }
22+
let(:dsc_deferred_direct) { read_fixture('02_dsc_deferred_direct.pp') }
23+
let(:dsc_deferred_inline) { read_fixture('02b_dsc_deferred_inline.pp') } # <— NEW
24+
let(:dsc_deferred_stringified) { read_fixture('03a_dsc_deferred_stringified.pp') }
25+
let(:dsc_deferred_bad_unwrap) { read_fixture('03b_dsc_deferred_bad_unwrap.pp') }
26+
27+
it 'control (01): native file + Deferred resolves to hello-file' do
28+
result = idempotent_apply(control_manifest)
29+
expect(result.exit_code).to eq(0)
30+
out = read_win_file_if_exists('C:/Temp/deferred_ok.txt')
31+
expect(out[:exists]).to be(true)
32+
expect(out[:content].strip).to eq('hello-file')
33+
end
34+
35+
it '02: passing Deferred via variable to DSC resolves to hello-dsc (otherwise flag bug)' do
36+
apply = apply_manifest(dsc_deferred_direct)
37+
out = read_win_file_if_exists('C:/Temp/from_dsc.txt')
38+
content = out[:content].strip
39+
if out[:exists] && content == 'hello-dsc'
40+
expect(true).to be(true)
41+
elsif out[:exists] && content =~ %r{Deferred\s*\(|Puppet::Pops::Types::Deferred}i
42+
raise "BUG: 02 wrote stringified Deferred: #{content.inspect}\nApply:\n#{apply.stdout}#{apply.stderr}"
43+
else
44+
raise "Unexpected 02 outcome. Exists=#{out[:exists]} Content=#{content.inspect}\nApply:\n#{apply.stdout}#{apply.stderr}"
45+
end
46+
end
47+
48+
# NEW 02b: inline Deferred on the DSC property (no variable intermediary)
49+
it '02b: passing Deferred inline to DSC resolves to hello-dsc-inline (otherwise flag bug)' do
50+
apply = apply_manifest(dsc_deferred_inline)
51+
out = read_win_file_if_exists('C:/Temp/from_dsc_inline.txt')
52+
content = out[:content].strip
53+
if out[:exists] && content == 'hello-dsc-inline'
54+
expect(true).to be(true)
55+
elsif out[:exists] && content =~ %r{Deferred\s*\(|Puppet::Pops::Types::Deferred}i
56+
raise "BUG: 02b wrote stringified Deferred: #{content.inspect}\nApply:\n#{apply.stdout}#{apply.stderr}"
57+
else
58+
raise "Unexpected 02b outcome. Exists=#{out[:exists]} Content=#{content.inspect}\nApply:\n#{apply.stdout}#{apply.stderr}"
59+
end
60+
end
61+
62+
it '03a: stringifying a Deferred writes the function form (reproduces customer report)' do
63+
apply_manifest(dsc_deferred_stringified)
64+
out = read_win_file_if_exists('C:/Temp/from_dsc_var_string.txt')
65+
expect(out[:exists]).to be(true)
66+
expect(out[:content]).to match(%r{Deferred\s*\(|Puppet::Pops::Types::Deferred}i)
67+
expect(out[:content]).not_to match(%r{\bhello-var\b})
68+
end
69+
70+
it '03b: unwrap on a non‑Sensitive is a no‑op; also writes the function form' do
71+
apply_manifest(dsc_deferred_bad_unwrap)
72+
out = read_win_file_if_exists('C:/Temp/from_dsc_var_bad_unwrap.txt')
73+
out = read_win_file_if_exists('C:/Temp/from_dsc_var.txt') unless out[:exists]
74+
expect(out[:exists]).to be(true)
75+
expect(out[:content]).to match(%r{Deferred\s*\(|Puppet::Pops::Types::Deferred}i)
76+
expect(out[:content]).not_to match(%r{\bhello-var\b})
77+
end
78+
end
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# spec/fixtures/manifests/01_file_deferred.pp
2+
file { 'C:/Temp':
3+
ensure => directory,
4+
}
5+
6+
$deferred = Deferred('join', [['hello','-','file'], ''])
7+
8+
file { 'C:/Temp/deferred_ok.txt':
9+
ensure => file,
10+
content => $deferred,
11+
require => File['C:/Temp'],
12+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# spec/fixtures/manifests/02_dsc_deferred_direct.pp
2+
file { 'C:/Temp':
3+
ensure => directory,
4+
}
5+
6+
$deferred = Deferred('join', [['hello','-','dsc'], ''])
7+
8+
dsc { 'WriteFileViaDSC':
9+
resource_name => 'File',
10+
module => 'PSDesiredStateConfiguration',
11+
properties => {
12+
'DestinationPath' => 'C:\Temp\from_dsc.txt',
13+
'Type' => 'File',
14+
'Ensure' => 'Present',
15+
'Contents' => $deferred,
16+
},
17+
require => File['C:/Temp'],
18+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# spec/fixtures/manifests/02b_dsc_deferred_inline.pp
2+
file { 'C:/Temp':
3+
ensure => directory,
4+
}
5+
6+
dsc { 'WriteFileViaDSCInline':
7+
resource_name => 'File',
8+
module => 'PSDesiredStateConfiguration',
9+
properties => {
10+
'DestinationPath' => 'C:\Temp\from_dsc_inline.txt',
11+
'Type' => 'File',
12+
'Ensure' => 'Present',
13+
'Contents' => Deferred('join', [['hello','-','dsc-inline'], '']),
14+
},
15+
require => File['C:/Temp'],
16+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# spec/fixtures/manifests/03a_dsc_deferred_stringified.pp
2+
file { 'C:/Temp': ensure => directory }
3+
4+
$deferred = Deferred('join', [['hello','-','var'], ''])
5+
6+
# WRONG on purpose: coerces Deferred to a String at compile time
7+
$stringified = String($deferred)
8+
9+
dsc { 'WriteFileViaDSCVarStringified':
10+
resource_name => 'File',
11+
module => 'PSDesiredStateConfiguration',
12+
properties => {
13+
'DestinationPath' => 'C:\Temp\from_dsc_var_string.txt',
14+
'Type' => 'File',
15+
'Ensure' => 'Present',
16+
'Contents' => $stringified,
17+
},
18+
require => File['C:/Temp'],
19+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# spec/fixtures/manifests/03b_dsc_deferred_bad_unwrap.pp
2+
file { 'C:/Temp': ensure => directory }
3+
4+
$deferred = Deferred('join', [['hello','-','var'], ''])
5+
6+
# WRONG: unwrap applies to Sensitive, not Deferred; this should compile-fail
7+
$unwrapped_deferred = String($deferred.unwrap)
8+
9+
dsc { 'WriteFileViaDSCVarBadUnwrap':
10+
resource_name => 'File',
11+
module => 'PSDesiredStateConfiguration',
12+
properties => {
13+
'DestinationPath' => 'C:\Temp\from_dsc_var_bad_unwrap.txt',
14+
'Type' => 'File',
15+
'Ensure' => 'Present',
16+
'Contents' => $unwrapped_deferred,
17+
},
18+
require => File['C:/Temp'],
19+
}

0 commit comments

Comments
 (0)