@@ -7,80 +7,82 @@ def read_fixture(name)
77 File . read ( File . join ( __dir__ , '..' , 'fixtures' , 'manifests' , name ) )
88end
99
10- def read_win_file ( path )
11- run_shell ( %(powershell.exe -NoProfile -NonInteractive -Command "(Get-Content -Raw '#{ path } ')" ) )
10+ # Returns a struct-like Hash: { exists: true|false, content: String }
11+ def read_win_file_if_exists ( path )
12+ # Always exit 0; emit a marker if the file is missing
13+ ps = %{$p='#{ path } '; if (Test-Path -LiteralPath $p) { Get-Content -Raw -LiteralPath $p } else { '<<<FILE_NOT_FOUND>>>' }}
14+ r = run_shell ( %(powershell.exe -NoProfile -NonInteractive -Command "#{ ps } ") )
15+ body = ( r . stdout || '' ) . to_s
16+ missing = body . include? ( '<<<FILE_NOT_FOUND>>>' )
17+ { exists : !missing , content : ( missing ? '' : body ) }
1218end
1319
1420describe 'deferred values with dsc_lite' do
15- let ( :control_manifest ) { read_fixture ( '01_file_deferred.pp' ) }
16- let ( :dsc_deferred_direct ) { read_fixture ( '02_dsc_deferred_direct.pp' ) }
17- let ( :dsc_deferred_stringified ) { read_fixture ( '03a_dsc_deferred_stringified.pp' ) }
18- let ( :dsc_deferred_bad_unwrap ) { read_fixture ( '03b_dsc_deferred_bad_unwrap.pp' ) }
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_stringified ) { read_fixture ( '03a_dsc_deferred_stringified.pp' ) }
24+ let ( :dsc_deferred_bad_unwrap ) { read_fixture ( '03b_dsc_deferred_bad_unwrap.pp' ) }
1925
20- it 'control: native file + Deferred resolves to hello-file' do
26+ it 'control (01) : native file + Deferred resolves to hello-file' do
2127 result = idempotent_apply ( control_manifest )
2228 expect ( result . exit_code ) . to eq ( 0 )
2329
24- r = read_win_file ( 'C:/Temp/deferred_ok.txt' )
25- expect ( r . exit_code ) . to eq ( 0 )
26- # Your 01 manifest writes "hello-file"
27- expect ( r . stdout . strip ) . to eq ( 'hello-file' )
30+ r = read_win_file_if_exists ( 'C:/Temp/deferred_ok.txt' )
31+ expect ( r [ :exists ] ) . to be ( true ) , 'C:/Temp/deferred_ok.txt was not created'
32+ expect ( r [ :content ] . strip ) . to eq ( 'hello-file' )
2833 end
2934
3035 context 'dsc_lite with Deferred' do
31- it '02: passing Deferred directly to DSC resolves to hello-dsc (otherwise flag the bug)' do
32- result = apply_manifest ( dsc_deferred_direct ) # no expect_failures
36+ it '02: passing Deferred directly to DSC resolves to hello-dsc (otherwise flag bug with diagnostics)' do
37+ apply = apply_manifest ( dsc_deferred_direct ) # not expecting failures by default
38+ apply_output = ( apply . stdout . to_s + apply . stderr . to_s )
3339
34- # We still verify end state regardless of exit code, but this helps failure messaging
35- apply_output = ( result . stdout . to_s + result . stderr . to_s )
40+ r = read_win_file_if_exists ( 'C:/Temp/from_dsc.txt' )
3641
37- r = read_win_file ( 'C:/Temp/from_dsc.txt' )
38- content = r . stdout . to_s . strip
39-
40- if r . exit_code . zero? && content == 'hello-dsc'
41- # ✅ Success: DSC got the resolved value from the agent
42- expect ( content ) . to eq ( 'hello-dsc' )
43- elsif r . exit_code . zero? && content =~ %r{Deferred\s *\( |Puppet::Pops::Types::Deferred}i
44- # ❌ Bug reproduced: provider/stringification allowed the wrapper through
42+ if r [ :exists ] && r [ :content ] . strip == 'hello-dsc'
43+ # ✅ good case
44+ expect ( true ) . to be ( true )
45+ elsif r [ :exists ] && r [ :content ] =~ %r{Deferred\s *\( |Puppet::Pops::Types::Deferred}i
46+ # ❌ bug: stringified wrapper made it through to DSC
4547 raise <<~MSG
4648 BUG: DSC wrote a stringified Deferred instead of the resolved value.
47- Got content :
48- #{ content . inspect }
49- Apply output:
49+ Content :
50+ #{ r [ : content] . inspect }
51+ Puppet apply output:
5052 #{ apply_output }
5153 MSG
5254 else
53- # ❌ Some other failure/ unexpected content
55+ # ❌ file missing or unexpected content
5456 raise <<~MSG
5557 Unexpected outcome for 02_dsc_deferred_direct.
56- Exit: #{ result . exit_code }
57- File content : #{ content . inspect }
58- Apply output:
58+ File exists? #{ r [ :exists ] }
59+ Content (trimmed) : #{ r [ : content] . strip . inspect }
60+ Puppet apply output:
5961 #{ apply_output }
6062 MSG
6163 end
6264 end
6365
6466 it '03a: stringifying a Deferred writes the function form (reproduces customer report)' do
65- result = apply_manifest ( dsc_deferred_stringified ) # no expect_failures
66- expect ( result . exit_code ) . to eq ( 0 )
67-
68- r = read_win_file ( 'C:/Temp/from_dsc_var_string.txt' )
69- expect ( r . exit_code ) . to eq ( 0 )
67+ apply = apply_manifest ( dsc_deferred_stringified )
68+ expect ( apply . exit_code ) . to eq ( 2 ) . or eq ( 0 ) # change or noop is fine
7069
71- body = r . stdout . to_s
72- # Should look like a stringified wrapper, NOT the resolved "hello-var"
73- expect ( body ) . to match ( %r{Deferred\s *\( |Puppet::Pops::Types::Deferred}i )
74- expect ( body ) . not_to match ( %r{\b hello-var\b } )
70+ r = read_win_file_if_exists ( 'C:/Temp/from_dsc_var_string.txt' )
71+ expect ( r [ :exists ] ) . to be ( true ) , 'C:/Temp/from_dsc_var_string.txt was not created'
72+ expect ( r [ :content ] ) . to match ( %r{Deferred\s *\( |Puppet::Pops::Types::Deferred}i )
73+ expect ( r [ :content ] ) . not_to match ( %r{\b hello-var\b } )
7574 end
7675
77- it '03b: bad unwrap on a Deferred fails to compile with an unwrap/dispatch error' do
78- # This scenario is expected to fail at compile time because unwrap applies to Sensitive, not Deferred.
79- result = apply_manifest ( dsc_deferred_bad_unwrap , expect_failures : true )
80- combined = ( result . stdout . to_s + result . stderr . to_s )
76+ it '03b: bad unwrap on a Deferred does NOT fail compilation; it also writes the function form' do
77+ # unwrap on non-Sensitive returns the argument unchanged, so this will NOT fail compilation.
78+ # It will stringify the Deferred and write that text via DSC (same symptom as 03a). [1](https://docs.huihoo.com/puppet/puppet/2.7/reference/lang_resources.html)
79+ apply = apply_manifest ( dsc_deferred_bad_unwrap )
80+ expect ( apply . exit_code ) . to eq ( 2 ) . or eq ( 0 )
8181
82- # Be generous on the match to cover different Puppet versions/wordings
83- expect ( combined ) . to match ( %r{unwrap|NoMethodError|dispatch|undefined method}i )
82+ r = read_win_file_if_exists ( 'C:/Temp/from_dsc_var_bad_unwrap.txt' )
83+ expect ( r [ :exists ] ) . to be ( true ) , 'C:/Temp/from_dsc_var_bad_unwrap.txt was not created'
84+ expect ( r [ :content ] ) . to match ( %r{Deferred\s *\( |Puppet::Pops::Types::Deferred}i )
85+ expect ( r [ :content ] ) . not_to match ( %r{\b hello-var\b } )
8486 end
8587 end
8688end
0 commit comments