Skip to content

Commit 5be1dd7

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 5be1dd7

10 files changed

+224
-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: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
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_control_manifest_epp) { read_fixture('01b_file_deferred_with_epp.pp') }
23+
let(:dsc_deferred_direct) { read_fixture('02_dsc_deferred_direct.pp') }
24+
let(:dsc_deferred_inline) { read_fixture('02b_dsc_deferred_inline.pp') } # ← NEW
25+
let(:dsc_deferred_epp_inline) { read_fixture('02c_dsc_deferred_epp_inline.pp') } # ← NEW
26+
let(:dsc_deferred_stringified) { read_fixture('03a_dsc_deferred_stringified.pp') }
27+
let(:dsc_deferred_bad_unwrap) { read_fixture('03b_dsc_deferred_bad_unwrap.pp') }
28+
29+
it 'control (01): native file + Deferred resolves to hello-file' do
30+
result = idempotent_apply(control_manifest)
31+
expect(result.exit_code).to eq(0)
32+
out = read_win_file_if_exists('C:/Temp/deferred_ok.txt')
33+
expect(out[:exists]).to be(true)
34+
expect(out[:content].strip).to eq('hello-file')
35+
end
36+
37+
it 'control (01b): native file + Deferred resolves to hello-file (EPP)' do
38+
result = idempotent_apply_debug(dsc_control_manifest_epp)
39+
expect(result.exit_code).to eq(0)
40+
out = read_win_file_if_exists('C:/Temp/deferred_ok.txt')
41+
expect(out[:exists]).to be(true)
42+
expect(out[:content].strip).to eq('hello-file')
43+
end
44+
45+
it '02: passing Deferred via variable to DSC resolves to hello-dsc (otherwise flag bug)' do
46+
apply = apply_manifest(dsc_deferred_direct)
47+
out = read_win_file_if_exists('C:/Temp/from_dsc.txt')
48+
content = out[:content].strip
49+
if out[:exists] && content == 'hello-dsc'
50+
expect(true).to be(true)
51+
elsif out[:exists] && content =~ %r{Deferred\s*\(|Puppet::Pops::Types::Deferred}i
52+
raise "BUG: 02 wrote stringified Deferred: #{content.inspect}\nApply:\n#{apply.stdout}#{apply.stderr}"
53+
else
54+
raise "Unexpected 02 outcome. Exists=#{out[:exists]} Content=#{content.inspect}\nApply:\n#{apply.stdout}#{apply.stderr}"
55+
end
56+
end
57+
58+
# NEW 02b: inline Deferred on the DSC property (no variable intermediary)
59+
it '02b: passing Deferred inline to DSC resolves to hello-dsc-inline (otherwise flag bug)' do
60+
apply = apply_manifest(dsc_deferred_inline)
61+
out = read_win_file_if_exists('C:/Temp/from_dsc_inline.txt')
62+
content = out[:content].strip
63+
if out[:exists] && content == 'hello-dsc-inline'
64+
expect(true).to be(true)
65+
elsif out[:exists] && content =~ %r{Deferred\s*\(|Puppet::Pops::Types::Deferred}i
66+
raise "BUG: 02b wrote stringified Deferred: #{content.inspect}\nApply:\n#{apply.stdout}#{apply.stderr}"
67+
else
68+
raise "Unexpected 02b outcome. Exists=#{out[:exists]} Content=#{content.inspect}\nApply:\n#{apply.stdout}#{apply.stderr}"
69+
end
70+
end
71+
72+
# NEW 02c: inline Deferred on the DSC property (no variable intermediary)
73+
it '02c: passing a Deferred inline while calling an epp' do
74+
apply = apply_manifest_debug(dsc_deferred_epp_inline)
75+
out = read_win_file_if_exists('C:/Temp/from_dsc_inline.txt')
76+
content = out[:content].strip
77+
if out[:exists] && content == 'hello-dsc-epp'
78+
expect(true).to be(true)
79+
elsif out[:exists] && content =~ %r{Deferred\s*\(|Puppet::Pops::Types::Deferred}i
80+
raise "BUG: 02c wrote stringified Deferred: #{content.inspect}\nApply:\n#{apply.stdout}#{apply.stderr}"
81+
else
82+
raise "Unexpected 02c outcome. Exists=#{out[:exists]} Content=#{content.inspect}\nApply:\n#{apply.stdout}#{apply.stderr}"
83+
end
84+
end
85+
86+
it '03a: stringifying a Deferred writes the function form (reproduces customer report)' do
87+
apply_manifest(dsc_deferred_stringified)
88+
out = read_win_file_if_exists('C:/Temp/from_dsc_var_string.txt')
89+
expect(out[:exists]).to be(true)
90+
expect(out[:content]).to match(%r{Deferred\s*\(|Puppet::Pops::Types::Deferred}i)
91+
expect(out[:content]).not_to match(%r{\bhello-var\b})
92+
end
93+
94+
it '03b: unwrap on a non‑Sensitive is a no‑op; also writes the function form' do
95+
apply_manifest(dsc_deferred_bad_unwrap)
96+
out = read_win_file_if_exists('C:/Temp/from_dsc_var_bad_unwrap.txt')
97+
out = read_win_file_if_exists('C:/Temp/from_dsc_var.txt') unless out[:exists]
98+
expect(out[:exists]).to be(true)
99+
expect(out[:content]).to match(%r{Deferred\s*\(|Puppet::Pops::Types::Deferred}i)
100+
expect(out[:content]).not_to match(%r{\bhello-var\b})
101+
end
102+
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: 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('inline_epp', ['<%= $content.unwrap %>', { 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: 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', '-', 'epp'], ''])
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('inline_epp', ['<%= $content.unwrap %>', { content => $deferred }]),
16+
},
17+
require => File['C:/Temp'],
18+
}
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)