puppet 4.10.1 → 4.10.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of puppet might be problematic. Click here for more details.

Files changed (120) hide show
  1. data/ext/project_data.yaml +1 -1
  2. data/lib/puppet.rb +40 -28
  3. data/lib/puppet/application/agent.rb +1 -1
  4. data/lib/puppet/application/apply.rb +1 -1
  5. data/lib/puppet/application/cert.rb +1 -1
  6. data/lib/puppet/application/describe.rb +1 -1
  7. data/lib/puppet/application/device.rb +1 -1
  8. data/lib/puppet/application/doc.rb +3 -3
  9. data/lib/puppet/application/filebucket.rb +1 -1
  10. data/lib/puppet/application/inspect.rb +2 -2
  11. data/lib/puppet/application/lookup.rb +1 -1
  12. data/lib/puppet/application/master.rb +1 -1
  13. data/lib/puppet/application/resource.rb +7 -7
  14. data/lib/puppet/defaults.rb +1 -1
  15. data/lib/puppet/etc.rb +75 -39
  16. data/lib/puppet/face/ca.rb +1 -1
  17. data/lib/puppet/face/catalog.rb +1 -1
  18. data/lib/puppet/face/certificate.rb +1 -1
  19. data/lib/puppet/face/certificate_request.rb +1 -1
  20. data/lib/puppet/face/certificate_revocation_list.rb +1 -1
  21. data/lib/puppet/face/config.rb +1 -1
  22. data/lib/puppet/face/epp.rb +1 -1
  23. data/lib/puppet/face/facts.rb +1 -1
  24. data/lib/puppet/face/file.rb +1 -1
  25. data/lib/puppet/face/help.rb +1 -1
  26. data/lib/puppet/face/key.rb +1 -1
  27. data/lib/puppet/face/man.rb +2 -2
  28. data/lib/puppet/face/module.rb +1 -1
  29. data/lib/puppet/face/node.rb +1 -1
  30. data/lib/puppet/face/parser.rb +1 -1
  31. data/lib/puppet/face/plugin.rb +1 -1
  32. data/lib/puppet/face/report.rb +1 -1
  33. data/lib/puppet/face/resource.rb +1 -1
  34. data/lib/puppet/face/resource_type.rb +1 -1
  35. data/lib/puppet/face/status.rb +1 -1
  36. data/lib/puppet/feature/base.rb +1 -1
  37. data/lib/puppet/functions/eyaml_lookup_key.rb +16 -12
  38. data/lib/puppet/functions/hiera.rb +9 -2
  39. data/lib/puppet/functions/hiera_array.rb +9 -2
  40. data/lib/puppet/functions/hiera_hash.rb +10 -2
  41. data/lib/puppet/functions/hiera_include.rb +17 -3
  42. data/lib/puppet/functions/hocon_data.rb +6 -0
  43. data/lib/puppet/functions/json_data.rb +4 -0
  44. data/lib/puppet/functions/yaml_data.rb +4 -0
  45. data/lib/puppet/generate/models/type/type.rb +6 -5
  46. data/lib/puppet/generate/templates/type/pcore.erb +1 -1
  47. data/lib/puppet/module_tool/skeleton/templates/generator/examples/init.pp.erb +1 -1
  48. data/lib/puppet/parser/functions/create_resources.rb +8 -0
  49. data/lib/puppet/parser/scope.rb +2 -2
  50. data/lib/puppet/pops/adapters.rb +10 -4
  51. data/lib/puppet/pops/evaluator/runtime3_resource_support.rb +0 -2
  52. data/lib/puppet/pops/evaluator/runtime3_support.rb +31 -0
  53. data/lib/puppet/pops/issues.rb +8 -0
  54. data/lib/puppet/pops/loader/loader.rb +4 -0
  55. data/lib/puppet/pops/loader/module_loaders.rb +0 -2
  56. data/lib/puppet/pops/loader/static_loader.rb +1 -1
  57. data/lib/puppet/pops/loader/type_definition_instantiator.rb +1 -1
  58. data/lib/puppet/pops/loader/typed_name.rb +1 -0
  59. data/lib/puppet/pops/loaders.rb +7 -15
  60. data/lib/puppet/pops/lookup/environment_data_provider.rb +1 -1
  61. data/lib/puppet/pops/lookup/hiera_config.rb +3 -1
  62. data/lib/puppet/pops/lookup/interpolation.rb +2 -1
  63. data/lib/puppet/pops/lookup/lookup_key.rb +1 -1
  64. data/lib/puppet/pops/lookup/module_data_provider.rb +10 -2
  65. data/lib/puppet/pops/lookup/sub_lookup.rb +10 -9
  66. data/lib/puppet/pops/parser/lexer2.rb +20 -3
  67. data/lib/puppet/pops/pcore.rb +2 -2
  68. data/lib/puppet/pops/resource/resource_type_impl.rb +2 -2
  69. data/lib/puppet/pops/semantic_error.rb +12 -0
  70. data/lib/puppet/pops/serialization/deserializer.rb +7 -4
  71. data/lib/puppet/pops/types/p_type_set_type.rb +2 -2
  72. data/lib/puppet/pops/types/string_converter.rb +5 -17
  73. data/lib/puppet/pops/types/type_set_reference.rb +1 -1
  74. data/lib/puppet/pops/validation/checker4_0.rb +4 -0
  75. data/lib/puppet/pops/validation/validator_factory_4_0.rb +1 -0
  76. data/lib/puppet/provider/nameservice.rb +12 -4
  77. data/lib/puppet/provider/package/yum.rb +8 -8
  78. data/lib/puppet/provider/user/useradd.rb +1 -1
  79. data/lib/puppet/reference/configuration.rb +1 -1
  80. data/lib/puppet/resource.rb +9 -11
  81. data/lib/puppet/resource/type_collection.rb +1 -0
  82. data/lib/puppet/type/exec.rb +32 -26
  83. data/lib/puppet/type/file/mode.rb +4 -0
  84. data/lib/puppet/util/character_encoding.rb +77 -74
  85. data/lib/puppet/util/monkey_patches.rb +3 -1
  86. data/lib/puppet/util/windows/api_types.rb +3 -0
  87. data/lib/puppet/util/windows/file.rb +1 -1
  88. data/lib/puppet/version.rb +1 -1
  89. data/locales/puppet.pot +31 -7
  90. data/spec/integration/faces/documentation_spec.rb +2 -2
  91. data/spec/integration/parser/pcore_resource_spec.rb +15 -0
  92. data/spec/integration/resource/type_collection_spec.rb +6 -0
  93. data/spec/lib/puppet/face/1.0.0/huzzah.rb +1 -1
  94. data/spec/lib/puppet/face/basetest.rb +1 -1
  95. data/spec/lib/puppet/face/huzzah.rb +1 -1
  96. data/spec/lib/puppet/face/version_matching.rb +1 -1
  97. data/spec/lib/puppet_spec/character_encoding.rb +12 -0
  98. data/spec/lib/puppet_spec/compiler.rb +7 -0
  99. data/spec/shared_examples/rhel_package_provider.rb +10 -11
  100. data/spec/unit/application/resource_spec.rb +22 -1
  101. data/spec/unit/configurer/fact_handler_spec.rb +2 -1
  102. data/spec/unit/etc_spec.rb +361 -153
  103. data/spec/unit/functions/lookup_spec.rb +118 -2
  104. data/spec/unit/parser/functions/create_resources_spec.rb +47 -6
  105. data/spec/unit/parser/scope_spec.rb +8 -0
  106. data/spec/unit/pops/evaluator/evaluating_parser_spec.rb +40 -0
  107. data/spec/unit/pops/loaders/loaders_spec.rb +141 -79
  108. data/spec/unit/pops/lookup/interpolation_spec.rb +49 -9
  109. data/spec/unit/pops/lookup/lookup_spec.rb +32 -0
  110. data/spec/unit/pops/parser/lexer2_spec.rb +28 -0
  111. data/spec/unit/pops/types/p_object_type_spec.rb +1 -1
  112. data/spec/unit/pops/types/p_type_set_type_spec.rb +1 -1
  113. data/spec/unit/pops/types/string_converter_spec.rb +21 -0
  114. data/spec/unit/pops/validator/validator_spec.rb +43 -0
  115. data/spec/unit/provider/nameservice/directoryservice_spec.rb +2 -0
  116. data/spec/unit/provider/nameservice_spec.rb +113 -3
  117. data/spec/unit/provider/user/useradd_spec.rb +13 -0
  118. data/spec/unit/resource/catalog_spec.rb +21 -0
  119. data/spec/unit/util/character_encoding_spec.rb +193 -52
  120. metadata +4 -2
@@ -101,7 +101,9 @@ class OpenSSL::SSL::SSLContext
101
101
  else
102
102
  DEFAULT_PARAMS[:options] = OpenSSL::SSL::OP_NO_SSLv2 | OpenSSL::SSL::OP_NO_SSLv3
103
103
  end
104
- DEFAULT_PARAMS[:ciphers] << ':!SSLv2'
104
+ if DEFAULT_PARAMS[:ciphers]
105
+ DEFAULT_PARAMS[:ciphers] << ':!SSLv2'
106
+ end
105
107
 
106
108
  alias __original_initialize initialize
107
109
  private :__original_initialize
@@ -165,6 +165,9 @@ module Puppet::Util::Windows::APITypes
165
165
  # https://blogs.msdn.com/b/oldnewthing/archive/2011/03/28/10146459.aspx
166
166
  FFI.typedef :int32, :win32_bool
167
167
 
168
+ # BOOLEAN (unlike BOOL) is a BYTE - typedef unsigned char BYTE;
169
+ FFI.typedef :uchar, :boolean
170
+
168
171
  # Same as a LONG, a 32-bit signed integer
169
172
  FFI.typedef :int32, :hresult
170
173
 
@@ -397,7 +397,7 @@ module Puppet::Util::Windows::File
397
397
  begin
398
398
  ffi_lib :kernel32
399
399
  attach_function_private :CreateSymbolicLinkW,
400
- [:lpwstr, :lpwstr, :dword], :win32_bool
400
+ [:lpwstr, :lpwstr, :dword], :boolean
401
401
  rescue LoadError
402
402
  end
403
403
 
@@ -6,7 +6,7 @@
6
6
  # Raketasks and such to set the version based on the output of `git describe`
7
7
 
8
8
  module Puppet
9
- PUPPETVERSION = '4.10.1'
9
+ PUPPETVERSION = '4.10.4'
10
10
 
11
11
  ##
12
12
  # version is a public API method intended to always provide a fast and
@@ -6,11 +6,11 @@
6
6
  #, fuzzy
7
7
  msgid ""
8
8
  msgstr ""
9
- "Project-Id-Version: Puppet automation framework 4.10.0-45-gb0ff2a9\n"
9
+ "Project-Id-Version: Puppet automation framework 4.10.1-82-gd7074ee\n"
10
10
  "\n"
11
11
  "Report-Msgid-Bugs-To: https://tickets.puppetlabs.com\n"
12
- "POT-Creation-Date: 2017-04-18 09:07-0700\n"
13
- "PO-Revision-Date: 2017-04-18 09:07-0700\n"
12
+ "POT-Creation-Date: 2017-05-25 21:24+0000\n"
13
+ "PO-Revision-Date: 2017-05-25 21:24+0000\n"
14
14
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
15
15
  "Language-Team: LANGUAGE <LL@li.org>\n"
16
16
  "Language: \n"
@@ -23,11 +23,11 @@ msgstr ""
23
23
  msgid "`puppet %{name}` is deprecated and will be removed in a future release."
24
24
  msgstr ""
25
25
 
26
- #: ../lib/puppet/defaults.rb:1698
26
+ #: ../lib/puppet/defaults.rb:1720
27
27
  msgid "Setting 'archive_files' is deprecated. It will be removed in a future release along with the `inspect` command."
28
28
  msgstr ""
29
29
 
30
- #: ../lib/puppet/defaults.rb:1707
30
+ #: ../lib/puppet/defaults.rb:1729
31
31
  msgid "Setting 'archive_file_server' is deprecated. It will be removed in a future release along with the `inspect` command."
32
32
  msgstr ""
33
33
 
@@ -106,6 +106,10 @@ msgstr ""
106
106
  msgid "! Subcommand unavailable due to error. Check error logs."
107
107
  msgstr ""
108
108
 
109
+ #: ../lib/puppet/generate/models/type/type.rb:46
110
+ msgid "title patterns that use procs are not supported."
111
+ msgstr ""
112
+
109
113
  #: ../lib/puppet/indirector/file_bucket_file/file.rb:169
110
114
  msgid "Unable to verify existing FileBucket backup at '%{path}'."
111
115
  msgstr ""
@@ -118,6 +122,18 @@ msgstr ""
118
122
  msgid "Existing backup does not match its expected sum, %{sum}. Overwriting corrupted backup."
119
123
  msgstr ""
120
124
 
125
+ #: ../lib/puppet/pops/lookup/environment_data_provider.rb:20
126
+ msgid "hiera.yaml version 3 found at the environment root was ignored"
127
+ msgstr ""
128
+
129
+ #: ../lib/puppet/pops/lookup/module_data_provider.rb:69
130
+ msgid "hiera.yaml version 3 found at module root was ignored"
131
+ msgstr ""
132
+
133
+ #: ../lib/puppet/provider/nameservice.rb:56
134
+ msgid "listbyname is deprecated and will be removed in a future release of Puppet. Please use `self.instances` to obtain a list of users."
135
+ msgstr ""
136
+
121
137
  #: ../lib/puppet/resource.rb:81
122
138
  msgid "Unable to deserialize non-Data value for parameter %{param} unless rich data is enabled"
123
139
  msgstr ""
@@ -130,8 +146,16 @@ msgstr ""
130
146
  msgid "The `audit` metaparameter is deprecated and will be ignored in a future release."
131
147
  msgstr ""
132
148
 
133
- #: ../lib/puppet/util/character_encoding.rb:75
134
- msgid "%{error}: %{value} is not valid UTF-8 and cannot be transcoded by Puppet."
149
+ #: ../lib/puppet/util/character_encoding.rb:22
150
+ msgid "%{value} is already labeled as UTF-8 but this encoding is invalid. It cannot be transcoded by Puppet."
151
+ msgstr ""
152
+
153
+ #: ../lib/puppet/util/character_encoding.rb:43
154
+ msgid "%{error}: %{value} cannot be transcoded by Puppet."
155
+ msgstr ""
156
+
157
+ #: ../lib/puppet/util/character_encoding.rb:70
158
+ msgid "%{value} is not valid UTF-8 and result of overriding encoding would be invalid."
135
159
  msgstr ""
136
160
 
137
161
  #. TRANSLATORS message accompanied by date of generation
@@ -43,10 +43,10 @@ describe "documentation of faces" do
43
43
  ########################################################################
44
44
  # Ensure that we have authorship and copyright information in *our* faces;
45
45
  # if you apply this to third party faces you might well be disappointed.
46
- context "licensing of Puppet Labs face '#{face_name}'" do
46
+ context "licensing of Puppet Inc. face '#{face_name}'" do
47
47
  subject { Puppet::Face[face_name, :current] }
48
48
  its :license do should =~ /Apache\s*2/ end
49
- its :copyright do should =~ /Puppet Labs|Puppet Inc\./ end
49
+ its :copyright do should =~ /Puppet Inc\./ end
50
50
 
51
51
  # REVISIT: This is less that ideal, I think, but right now I am more
52
52
  # comfortable watching us ship with some copyright than without any; we
@@ -57,6 +57,17 @@ describe 'when pcore described resources types are in use' do
57
57
  end
58
58
  end;end
59
59
  EOF
60
+ 'test3.rb' => <<-RUBY,
61
+ Puppet::Type.newtype(:test3) do
62
+ newproperty(:message)
63
+ newparam(:a) { isnamevar }
64
+ newparam(:b) { isnamevar }
65
+ newparam(:c) { isnamevar }
66
+ def self.title_patterns
67
+ [ [ /^((.+)\\/(.*))$/, [[:a], [:b], [:c]]] ]
68
+ end
69
+ end
70
+ RUBY
60
71
  'cap.rb' => <<-EOF
61
72
  module Puppet
62
73
  Type.newtype(:cap, :is_capability => true) do
@@ -112,12 +123,16 @@ describe 'when pcore described resources types are in use' do
112
123
  test2 { 'b':
113
124
  message => 'b works'
114
125
  }
126
+ test3 { 'x/y':
127
+ message => 'x/y works'
128
+ }
115
129
  cap { 'c':
116
130
  message => 'c works'
117
131
  }
118
132
  MANIFEST
119
133
  expect(catalog.resource(:test1, "a")['message']).to eq('a works')
120
134
  expect(catalog.resource(:test2, "b")['message']).to eq('b works')
135
+ expect(catalog.resource(:test3, "x/y")['message']).to eq('x/y works')
121
136
  expect(catalog.resource(:cap, "c")['message']).to eq('c works')
122
137
  end
123
138
 
@@ -83,5 +83,11 @@ describe Puppet::Resource::TypeCollection do
83
83
  mk_module(name, :define => true, :mydefine => ["mymod::mydefine"])
84
84
  expect(@code.find_definition("mymod::mydefine").name).to eq("mymod::mydefine")
85
85
  end
86
+
87
+ it 'should be able to load definitions from their own file using uppercased name' do
88
+ name = 'mymod'
89
+ mk_module(name, :define => true, :mydefine => ['mymod::mydefine'])
90
+ expect(@code.find_definition('Mymod::Mydefine')).not_to be_nil
91
+ end
86
92
  end
87
93
  end
@@ -1,6 +1,6 @@
1
1
  require 'puppet/face'
2
2
  Puppet::Face.define(:huzzah, '1.0.0') do
3
- copyright "Puppet Labs", 2011
3
+ copyright "Puppet Inc.", 2011
4
4
  license "Apache 2 license; see COPYING"
5
5
  summary "life is a thing for celebration"
6
6
  action(:obsolete_in_core) { when_invoked { |_| "you are in obsolete core now!" } }
@@ -1,7 +1,7 @@
1
1
  require 'puppet/face'
2
2
 
3
3
  Puppet::Face.define(:basetest, '0.0.1') do
4
- copyright "Puppet Labs", 2011
4
+ copyright "Puppet Inc.", 2011
5
5
  license "Apache 2 license; see COPYING"
6
6
  summary "This is just so tests don't fail"
7
7
 
@@ -1,6 +1,6 @@
1
1
  require 'puppet/face'
2
2
  Puppet::Face.define(:huzzah, '2.0.1') do
3
- copyright "Puppet Labs", 2011
3
+ copyright "Puppet Inc.", 2011
4
4
  license "Apache 2 license; see COPYING"
5
5
  summary "life is a thing for celebration"
6
6
  action(:bar) { when_invoked { |options| "is where beer comes from" } }
@@ -4,7 +4,7 @@ require 'puppet/face'
4
4
  # change this you need to ensure that is still correct. --daniel 2011-04-21
5
5
  ['1.0.0', '1.0.1', '1.1.0', '1.1.1', '2.0.0'].each do |version|
6
6
  Puppet::Face.define(:version_matching, version) do
7
- copyright "Puppet Labs", 2011
7
+ copyright "Puppet Inc.", 2011
8
8
  license "Apache 2 license; see COPYING"
9
9
  summary "version matching face #{version}"
10
10
  action(:version) { when_invoked { |options| version } }
@@ -0,0 +1,12 @@
1
+ # A support module for testing character encoding
2
+ module PuppetSpec::CharacterEncoding
3
+ def self.with_external_encoding(encoding, &blk)
4
+ original_encoding = Encoding.default_external
5
+ begin
6
+ Encoding.default_external = encoding
7
+ yield
8
+ ensure
9
+ Encoding.default_external = original_encoding
10
+ end
11
+ end
12
+ end
@@ -7,6 +7,13 @@ module PuppetSpec::Compiler
7
7
  Puppet::Parser::Compiler.compile(node).filter { |r| r.virtual? }
8
8
  end
9
9
 
10
+ # Does not removed virtual resources in compiled catalog (i.e. keeps unrealized)
11
+ def compile_to_catalog_unfiltered(string, node = Puppet::Node.new('test'))
12
+ Puppet[:code] = string
13
+ # see lib/puppet/indirector/catalog/compiler.rb#filter
14
+ Puppet::Parser::Compiler.compile(node)
15
+ end
16
+
10
17
  def compile_to_ral(manifest, node = Puppet::Node.new('test'))
11
18
  catalog = compile_to_catalog(manifest, node)
12
19
  ral = catalog.to_ral
@@ -178,7 +178,7 @@ shared_examples "RHEL package provider" do |provider_class, provider_name|
178
178
  {'--enablerepo' => 'centosplus'},
179
179
  ]
180
180
  provider.stubs(:properties).returns({:ensure => '3.4.5'})
181
- described_class.expects(:latest_package_version).with(name, ['contrib', 'centosplus'], [], [])
181
+ described_class.expects(:latest_package_version).with(name, [], ['contrib', 'centosplus'], [])
182
182
  provider.latest
183
183
  end
184
184
  it "passes the value of disablerepo install_options when querying" do
@@ -187,7 +187,7 @@ shared_examples "RHEL package provider" do |provider_class, provider_name|
187
187
  {'--disablerepo' => 'centosplus'},
188
188
  ]
189
189
  provider.stubs(:properties).returns({:ensure => '3.4.5'})
190
- described_class.expects(:latest_package_version).with(name, [], ['updates', 'centosplus'], [])
190
+ described_class.expects(:latest_package_version).with(name, ['updates', 'centosplus'], [], [])
191
191
  provider.latest
192
192
  end
193
193
  it "passes the value of disableexcludes install_options when querying" do
@@ -270,15 +270,15 @@ shared_examples "RHEL package provider" do |provider_class, provider_name|
270
270
  expect(version).to eq mypackage_version
271
271
  }
272
272
  end
273
- it "caches separate lists for each combination of 'enablerepo' and 'disablerepo' and 'disableexcludes'" do
273
+ it "caches separate lists for each combination of 'disablerepo' and 'enablerepo' and 'disableexcludes'" do
274
274
  described_class.expects(:check_updates).with([], [], []).once.returns(latest_versions)
275
- described_class.expects(:check_updates).with(['enabled'], ['disabled'], ['disableexcludes']).once.returns(enabled_versions)
275
+ described_class.expects(:check_updates).with(['disabled'], ['enabled'], ['disableexcludes']).once.returns(enabled_versions)
276
276
  2.times {
277
277
  version = described_class.latest_package_version(name, [], [], [])
278
278
  expect(version).to eq mypackage_version
279
279
  }
280
280
  2.times {
281
- version = described_class.latest_package_version(name, ['enabled'], ['disabled'], ['disableexcludes'])
281
+ version = described_class.latest_package_version(name, ['disabled'], ['enabled'], ['disableexcludes'])
282
282
  expect(version).to eq(mypackage_newerversion)
283
283
  }
284
284
  end
@@ -288,19 +288,19 @@ shared_examples "RHEL package provider" do |provider_class, provider_name|
288
288
  Puppet::Util::Execution.expects(:execute).with do |args, *rest|
289
289
  expect(args).to eq %W[/usr/bin/#{provider_name} check-update --enablerepo=updates --enablerepo=centosplus]
290
290
  end.returns(stub(:exitstatus => 0))
291
- described_class.check_updates(%W[updates centosplus], [], [])
291
+ described_class.check_updates([], %W[updates centosplus], [])
292
292
  end
293
293
  it "passes repos to disable to '#{provider_name} check-update'" do
294
294
  Puppet::Util::Execution.expects(:execute).with do |args, *rest|
295
295
  expect(args).to eq %W[/usr/bin/#{provider_name} check-update --disablerepo=updates --disablerepo=centosplus]
296
296
  end.returns(stub(:exitstatus => 0))
297
- described_class.check_updates([],%W[updates centosplus], [])
297
+ described_class.check_updates(%W[updates centosplus], [], [])
298
298
  end
299
299
  it "passes a combination of repos to enable and disable to '#{provider_name} check-update'" do
300
300
  Puppet::Util::Execution.expects(:execute).with do |args, *rest|
301
- expect(args).to eq %W[/usr/bin/#{provider_name} check-update --enablerepo=os --enablerepo=contrib --disablerepo=updates --disablerepo=centosplus]
301
+ expect(args).to eq %W[/usr/bin/#{provider_name} check-update --disablerepo=updates --disablerepo=centosplus --enablerepo=os --enablerepo=contrib ]
302
302
  end.returns(stub(:exitstatus => 0))
303
- described_class.check_updates(%W[os contrib], %W[updates centosplus], [])
303
+ described_class.check_updates(%W[updates centosplus], %W[os contrib], [])
304
304
  end
305
305
  it "passes disableexcludes to '#{provider_name} check-update'" do
306
306
  Puppet::Util::Execution.expects(:execute).with do |args, *rest|
@@ -310,8 +310,7 @@ shared_examples "RHEL package provider" do |provider_class, provider_name|
310
310
  end
311
311
  it "passes all options to '#{provider_name} check-update'" do
312
312
  Puppet::Util::Execution.expects(:execute).with do |args, *rest|
313
- expect(args).to eq %W[/usr/bin/#{provider_name} check-update --enablerepo=a --enablerepo=b --disablerepo=c
314
- --disablerepo=d --disableexcludes=e --disableexcludes=f]
313
+ expect(args).to eq %W[/usr/bin/#{provider_name} check-update --disablerepo=a --disablerepo=b --enablerepo=c --enablerepo=d --disableexcludes=e --disableexcludes=f]
315
314
  end.returns(stub(:exitstatus => 0))
316
315
  described_class.check_updates(%W[a b], %W[c d], %W[e f])
317
316
  end
@@ -2,6 +2,7 @@
2
2
  require 'spec_helper'
3
3
 
4
4
  require 'puppet/application/resource'
5
+ require 'puppet_spec/character_encoding'
5
6
 
6
7
  describe Puppet::Application::Resource do
7
8
  include PuppetSpec::Files
@@ -50,7 +51,7 @@ describe Puppet::Application::Resource do
50
51
  # provider is a parameter that should always be available
51
52
  @resource_app.extra_params = [ :provider ]
52
53
 
53
- expect { @resource_app.main }.to have_printed /provider\s+=>/
54
+ expect { @resource_app.main }.to have_printed(/provider\s+=>/)
54
55
  end
55
56
  end
56
57
 
@@ -88,6 +89,7 @@ describe Puppet::Application::Resource do
88
89
 
89
90
  @res = stub_everything "resource"
90
91
  @res.stubs(:prune_parameters).returns(@res)
92
+ @res.stubs(:to_manifest).returns("resource")
91
93
  @report = stub_everything "report"
92
94
 
93
95
  @resource_app.stubs(:puts)
@@ -129,6 +131,25 @@ describe Puppet::Application::Resource do
129
131
  end
130
132
  end
131
133
 
134
+ describe "when printing output" do
135
+ it "should ensure all values to be printed are in the external encoding" do
136
+ resources = [
137
+ Puppet::Type.type(:user).new(:name => "\u2603".force_encoding(Encoding::UTF_8)).to_resource,
138
+ Puppet::Type.type(:user).new(:name => "Jos\xE9".force_encoding(Encoding::ISO_8859_1)).to_resource
139
+ ]
140
+ Puppet::Resource.indirection.expects(:search).with('user/', {}).returns(resources)
141
+ @resource_app.command_line.stubs(:args).returns(['user'])
142
+
143
+ # All of our output should be in external encoding
144
+ @resource_app.expects(:puts).with { |args| expect(args.encoding).to eq(Encoding::ISO_8859_1) }
145
+
146
+ # This would raise an error if we weren't handling it
147
+ PuppetSpec::CharacterEncoding.with_external_encoding(Encoding::ISO_8859_1) do
148
+ expect { @resource_app.main }.not_to raise_error
149
+ end
150
+ end
151
+ end
152
+
132
153
  describe "when handling file type" do
133
154
  before :each do
134
155
  Facter.stubs(:loadfacts)
@@ -78,7 +78,8 @@ describe Puppet::Configurer::FactHandler do
78
78
  end
79
79
 
80
80
  it "should properly accept facts containing a '+'" do
81
- facts = Puppet::Node::Facts.new('foo', 'afact' => 'a+b')
81
+ fact_hash = { 'afact' => 'a+b' }
82
+ facts = Puppet::Node::Facts.new(Puppet[:node_name_value], fact_hash)
82
83
  Puppet::Node::Facts.indirection.save(facts)
83
84
  text = CGI.escape(facthandler.find_facts.render(:pson))
84
85
 
@@ -1,234 +1,442 @@
1
1
  require 'puppet'
2
2
  require 'spec_helper'
3
+ require 'puppet_spec/character_encoding'
3
4
 
4
5
  # The Ruby::Etc module is largely non-functional on Windows - many methods
5
6
  # simply return nil regardless of input, the Etc::Group struct is not defined,
6
7
  # and Etc::Passwd is missing fields
7
- describe Puppet::Etc, :if => !Puppet.features.microsoft_windows? do
8
- let(:bin) { 'bin'.force_encoding(Encoding::ISO_8859_1) }
9
- let(:root) { 'root'.force_encoding(Encoding::ISO_8859_1) }
10
- let(:x) { 'x'.force_encoding(Encoding::ISO_8859_1) }
11
- let(:daemon) { 'daemon'.force_encoding(Encoding::ISO_8859_1) }
12
- let(:root_comment) { 'i am the root user'.force_encoding(Encoding::ISO_8859_1) }
13
- let(:user_struct_iso_8859_1) { Etc::Passwd.new(root, x, 0, 0, root_comment) }
14
- let(:group_struct_iso_8859_1) { Etc::Group.new(bin, x, 1, [root, bin, daemon]) }
8
+ # We want to test that:
9
+ # - We correctly set external encoding values IF they're valid UTF-8 bytes
10
+ # - We do not modify non-UTF-8 values if they're NOT valid UTF-8 bytes
15
11
 
12
+ describe Puppet::Etc, :if => !Puppet.features.microsoft_windows? do
16
13
  # http://www.fileformat.info/info/unicode/char/5e0c/index.htm
17
14
  # 希 Han Character 'rare; hope, expect, strive for'
18
15
  # In EUC_KR: \xfd \xf1 - 253 241
19
- # Not convertible to UTF-8, likely to be read in as BINARY by Ruby unless system is in EUC_KR
20
- let(:not_convertible) { [254, 241].pack('C*') }
16
+ # In UTF-8: \u5e0c - \xe5 \xb8 \x8c - 229 184 140
17
+ let(:euc_kr) { [253, 241].pack('C*').force_encoding(Encoding::EUC_KR) } # valid_encoding? == true
18
+ let(:euc_kr_as_binary) { [253, 241].pack('C*') } # valid_encoding? == true
19
+ let(:euc_kr_as_utf_8) { [253, 241].pack('C*').force_encoding(Encoding::UTF_8) } # valid_encoding? == false
21
20
 
22
21
  # characters representing different UTF-8 widths
23
22
  # 1-byte A
24
23
  # 2-byte ۿ - http://www.fileformat.info/info/unicode/char/06ff/index.htm - 0xDB 0xBF / 219 191
25
24
  # 3-byte ᚠ - http://www.fileformat.info/info/unicode/char/16A0/index.htm - 0xE1 0x9A 0xA0 / 225 154 160
26
25
  # 4-byte 𠜎 - http://www.fileformat.info/info/unicode/char/2070E/index.htm - 0xF0 0xA0 0x9C 0x8E / 240 160 156 142
27
- #
28
- # Should all convert cleanly to UTF-8
29
- # Unless the system is in UTF-8, these will likely be read in as BINARY by Ruby
30
- let(:convertible_utf8) { "A\u06FF\u16A0\u{2070E}" } # Aۿᚠ𠜎
31
- let(:convertible_binary) { "A\u06FF\u16A0\u{2070E}".force_encoding(Encoding::BINARY) }
32
-
33
- # For the methods described which actually expect an encoding conversion, we
34
- # only superficially test via #force_encoding - the deeper level testing is in
35
- # character_encoding_spec.rb which handles testing transcoding etc.
36
-
37
- describe "getgrent" do
38
- context "given an original system Etc Group struct with ISO-8850-1 string values" do
39
- before { Etc.expects(:getgrent).returns(group_struct_iso_8859_1) }
40
- let(:converted) { Puppet::Etc.getgrent }
41
-
42
- it "should return a struct with :name and :passwd field values converted to UTF-8" do
43
- [converted.name, converted.passwd].each do |value|
44
- expect(value.encoding).to eq(Encoding::UTF_8)
45
- end
46
- end
26
+ let(:mixed_utf_8) { "A\u06FF\u16A0\u{2070E}".force_encoding(Encoding::UTF_8) } # Aۿᚠ𠜎
27
+ let(:mixed_utf_8_as_binary) { "A\u06FF\u16A0\u{2070E}".force_encoding(Encoding::BINARY) }
28
+ let(:mixed_utf_8_as_euc_kr) { "A\u06FF\u16A0\u{2070E}".force_encoding(Encoding::EUC_KR) }
29
+
30
+ # An uninteresting value that ruby might return in an Etc struct.
31
+ let(:root) { 'root' }
32
+
33
+ # Set up example Etc Group structs with values representative of what we would
34
+ # get back in these encodings
35
+
36
+ let(:utf_8_group_struct) do
37
+ group = Etc::Group.new
38
+ # In a UTF-8 environment, these values will come back as UTF-8, even if
39
+ # they're not valid UTF-8. We do not modify anything about either the
40
+ # valid or invalid UTF-8 strings.
41
+
42
+ # Group member contains a mix of valid and invalid UTF-8-labeled strings
43
+ group.mem = [mixed_utf_8, root.dup.force_encoding(Encoding::UTF_8), euc_kr_as_utf_8]
44
+ # group name contains same EUC_KR bytes labeled as UTF-8
45
+ group.name = euc_kr_as_utf_8
46
+ # group passwd field is valid UTF-8
47
+ group.passwd = mixed_utf_8
48
+ group.gid = 12345
49
+ group
50
+ end
47
51
 
48
- it "should return a struct with a :mem array with all field values converted to UTF-8" do
49
- converted.mem.each { |elem| expect(elem.encoding).to eq(Encoding::UTF_8) }
50
- end
52
+ let(:euc_kr_group_struct) do
53
+ # In an EUC_KR environment, values will come back as EUC_KR, even if they're
54
+ # not valid in that encoding. For values that are valid in UTF-8 we expect
55
+ # their external encoding to be set to UTF-8 by Puppet::Etc. For values that
56
+ # are invalid in UTF-8, we expect the string to be kept intact, unmodified,
57
+ # as we can't transcode it.
58
+ group = Etc::Group.new
59
+ group.mem = [euc_kr, root.dup.force_encoding(Encoding::EUC_KR), mixed_utf_8_as_euc_kr]
60
+ group.name = euc_kr
61
+ group.passwd = mixed_utf_8_as_euc_kr
62
+ group.gid = 12345
63
+ group
64
+ end
65
+
66
+ let(:ascii_group_struct) do
67
+ # In a POSIX environment, any strings containing only values under
68
+ # code-point 128 will be returned as ASCII, whereas anything above that
69
+ # point will be returned as BINARY. In either case we override the encoding
70
+ # to UTF-8 if that would be valid.
71
+ group = Etc::Group.new
72
+ group.mem = [euc_kr_as_binary, root.dup.force_encoding(Encoding::ASCII), mixed_utf_8_as_binary]
73
+ group.name = euc_kr_as_binary
74
+ group.passwd = mixed_utf_8_as_binary
75
+ group.gid = 12345
76
+ group
77
+ end
78
+
79
+ let(:utf_8_user_struct) do
80
+ user = Etc::Passwd.new
81
+ # user name contains same EUC_KR bytes labeled as UTF-8
82
+ user.name = euc_kr_as_utf_8
83
+ # group passwd field is valid UTF-8
84
+ user.passwd = mixed_utf_8
85
+ user.uid = 12345
86
+ user
87
+ end
88
+
89
+ let(:euc_kr_user_struct) do
90
+ user = Etc::Passwd.new
91
+ user.name = euc_kr
92
+ user.passwd = mixed_utf_8_as_euc_kr
93
+ user.uid = 12345
94
+ user
95
+ end
96
+
97
+ let(:ascii_user_struct) do
98
+ user = Etc::Passwd.new
99
+ user.name = euc_kr_as_binary
100
+ user.passwd = mixed_utf_8_as_binary
101
+ user.uid = 12345
102
+ user
103
+ end
104
+
105
+ shared_examples "methods that return an overridden group struct from Etc" do |params|
106
+
107
+ it "should return a new Struct object with corresponding canonical_ members" do
108
+ group = Etc::Group.new
109
+ Etc.expects(subject).with(*params).returns(group)
110
+ puppet_group = Puppet::Etc.send(subject, *params)
111
+
112
+ expect(puppet_group.members).to include(*group.members)
113
+ expect(puppet_group.members).to include(*group.members.map { |mem| "canonical_#{mem}".to_sym })
114
+
115
+ # Confirm we haven't just added the new members to the original struct object, ie this is really a new struct
116
+ expect(group.members.any? { |elem| elem.match(/^canonical_/) }).to be_falsey
51
117
  end
52
118
 
53
- context "given an original Etc::Group struct with field values that cannot be converted to UTF-8" do
54
- let(:group) { Etc::Group.new }
119
+ context "when Encoding.default_external is UTF-8" do
55
120
  before do
56
- # group membership contains valid and invalid UTF-8
57
- group.mem = [convertible_binary, not_convertible]
58
- # group name contains a value that is invalid UTF-8
59
- group.name = not_convertible
60
- # group passwd field is valid UTF-8
61
- group.passwd = convertible_binary
121
+ Etc.expects(subject).with(*params).returns(utf_8_group_struct)
122
+ end
62
123
 
63
- Etc.expects(:getgrent).returns(group)
124
+ let(:overridden) {
125
+ PuppetSpec::CharacterEncoding.with_external_encoding(Encoding::UTF_8) do
126
+ Puppet::Etc.send(subject, *params)
127
+ end
128
+ }
129
+
130
+ it "should leave the valid UTF-8 values in arrays unmodified" do
131
+ expect(overridden.mem[0]).to eq(mixed_utf_8)
132
+ expect(overridden.mem[1]).to eq(root)
64
133
  end
65
134
 
66
- let(:converted) { Puppet::Etc.getgrent }
135
+ it "should replace invalid characters with replacement characters in invalid UTF-8 values in arrays" do
136
+ expect(overridden.mem[2]).to eq("\uFFFD\uFFFD")
137
+ end
67
138
 
68
- it "should convert convertible values in arrays to UTF-8" do
69
- expect(converted.mem[0]).to eq("A\u06FF\u16A0\u{2070E}")
70
- expect(converted.mem[0].encoding).to eq(Encoding::UTF_8) # just being explicit
139
+ it "should keep an unmodified version of the invalid UTF-8 values in arrays in the corresponding canonical_ member" do
140
+ expect(overridden.canonical_mem[2]).to eq(euc_kr_as_utf_8)
71
141
  end
72
142
 
73
- it "should leave the unconvertible values unmodified" do
74
- expect(converted.name).to eq([254, 241].pack('C*'))
75
- expect(converted.name.encoding).to eq(Encoding::BINARY) # just being explicit
143
+ it "should leave the valid UTF-8 values unmodified" do
144
+ expect(overridden.passwd).to eq(mixed_utf_8)
76
145
  end
77
146
 
78
- it "should leave unconvertible values in arrays unmodifed" do
79
- expect(converted.mem[1]).to eq([254, 241].pack('C*'))
80
- expect(converted.mem[1].encoding).to eq(Encoding::BINARY) # just being explicit
147
+ it "should replace invalid characters with '?' characters in invalid UTF-8 values" do
148
+ expect(overridden.name).to eq("\uFFFD\uFFFD")
81
149
  end
82
150
 
83
- it "should convert values that can be converted to UTf-8" do
84
- expect(converted.passwd).to eq("A\u06FF\u16A0\u{2070E}")
85
- expect(converted.passwd.encoding).to eq(Encoding::UTF_8) # just being explicit
151
+ it "should keep an unmodified version of the invalid UTF-8 values in the corresponding canonical_ member" do
152
+ expect(overridden.canonical_name).to eq(euc_kr_as_utf_8)
86
153
  end
87
- end
88
- end
89
154
 
90
- describe "endgrent" do
91
- it "should call Etc.getgrent" do
92
- Etc.expects(:getgrent)
93
- Puppet::Etc.getgrent
94
- end
95
- end
155
+ it "should copy all values to the new struct object" do
156
+ # Confirm we've actually copied all the values to the canonical_members
157
+ utf_8_group_struct.each_pair do |member, value|
158
+ expect(overridden["canonical_#{member}"]).to eq(value)
96
159
 
97
- describe "setgrent" do
98
- it "should call Etc.setgrent" do
99
- Etc.expects(:setgrent)
100
- Puppet::Etc.setgrent
160
+ # Confirm we've reassigned all non-string and array values
161
+ if !value.is_a?(String) && !value.is_a?(Array)
162
+ expect(overridden[member]).to eq(value)
163
+ expect(overridden[member].object_id).to eq(value.object_id)
164
+ end
165
+ end
166
+ end
101
167
  end
102
- end
103
168
 
104
- describe "getpwent" do
105
- context "given an original system Etc Passwd struct with ISO-8859-1 string values" do
106
- before { Etc.expects(:getpwent).returns(user_struct_iso_8859_1) }
107
- let(:converted) { Puppet::Etc.getpwent }
169
+ context "when Encoding.default_external is EUC_KR (i.e., neither UTF-8 nor POSIX)" do
170
+ before do
171
+ Etc.expects(subject).with(*params).returns(euc_kr_group_struct)
172
+ end
173
+
174
+ let(:overridden) {
175
+ PuppetSpec::CharacterEncoding.with_external_encoding(Encoding::EUC_KR) do
176
+ Puppet::Etc.send(subject, *params)
177
+ end
178
+ }
179
+
180
+ it "should override EUC_KR-labeled values in arrays to UTF-8 if that would result in valid UTF-8" do
181
+ expect(overridden.mem[2]).to eq(mixed_utf_8)
182
+ expect(overridden.mem[1]).to eq(root)
183
+ end
184
+
185
+ it "should leave valid EUC_KR-labeled values that would not be valid UTF-8 in arrays unmodified" do
186
+ expect(overridden.mem[0]).to eq(euc_kr)
187
+ end
188
+
189
+ it "should override EUC_KR-labeled values to UTF-8 if that would result in valid UTF-8" do
190
+ expect(overridden.passwd).to eq(mixed_utf_8)
191
+ end
192
+
193
+ it "should leave valid EUC_KR-labeled values that would not be valid UTF-8 unmodified" do
194
+ expect(overridden.name).to eq(euc_kr)
195
+ end
108
196
 
109
- it "should return an Etc Passwd struct with field values converted to UTF-8" do
110
- [converted.name, converted.passwd, converted.gecos].each do |value|
111
- expect(value.encoding).to eq(Encoding::UTF_8)
197
+ it "should copy all values to the new struct object" do
198
+ # Confirm we've actually copied all the values to the canonical_members
199
+ euc_kr_group_struct.each_pair do |member, value|
200
+ expect(overridden["canonical_#{member}"]).to eq(value)
201
+
202
+ # Confirm we've reassigned all non-string and array values
203
+ if !value.is_a?(String) && !value.is_a?(Array)
204
+ expect(overridden[member]).to eq(value)
205
+ expect(overridden[member].object_id).to eq(value.object_id)
206
+ end
112
207
  end
113
208
  end
114
209
  end
115
210
 
116
- context "given an original Etc::Passwd struct with field values that cannot be converted to UTF-8" do
117
- let(:user) { Etc::Passwd.new }
211
+ context "when Encoding.default_external is POSIX (ASCII-7bit)" do
118
212
  before do
119
- # user comment field cannot be converted to UTF-8
120
- user.gecos = not_convertible
121
- # user passwd field is valid UTF-8
122
- user.passwd = convertible_binary
213
+ Etc.expects(subject).with(*params).returns(ascii_group_struct)
214
+ end
215
+
216
+ let(:overridden) {
217
+ PuppetSpec::CharacterEncoding.with_external_encoding(Encoding::ASCII) do
218
+ Puppet::Etc.send(subject, *params)
219
+ end
220
+ }
123
221
 
124
- Etc.expects(:getpwent).returns(user)
222
+ it "should not modify binary values in arrays that would be invalid UTF-8" do
223
+ expect(overridden.mem[0]).to eq(euc_kr_as_binary)
125
224
  end
126
225
 
127
- let(:converted) { Puppet::Etc.getpwent }
226
+ it "should set the encoding to UTF-8 on binary values in arrays that would be valid UTF-8" do
227
+ expect(overridden.mem[1]).to eq(root.dup.force_encoding(Encoding::UTF_8))
228
+ expect(overridden.mem[2]).to eq(mixed_utf_8)
229
+ end
128
230
 
129
- it "should leave the unconvertible values unmodified" do
130
- expect(converted.gecos).to eq([254, 241].pack('C*'))
131
- expect(converted.gecos.encoding).to eq(Encoding::BINARY) # just being explicit
231
+ it "should not modify binary values that would be invalid UTF-8" do
232
+ expect(overridden.name).to eq(euc_kr_as_binary)
132
233
  end
133
234
 
134
- it "should convert values that can be converted to UTf-8" do
135
- expect(converted.passwd).to eq("A\u06FF\u16A0\u{2070E}")
136
- expect(converted.passwd.encoding).to eq(Encoding::UTF_8) # just being explicit
235
+ it "should set the encoding to UTF-8 on binary values that would be valid UTF-8" do
236
+ expect(overridden.passwd).to eq(mixed_utf_8)
137
237
  end
138
- end
139
- end
140
238
 
141
- describe "endpwent" do
142
- it "should call Etc.endpwent" do
143
- Etc.expects(:endpwent)
144
- Puppet::Etc.endpwent
239
+ it "should copy all values to the new struct object" do
240
+ # Confirm we've actually copied all the values to the canonical_members
241
+ ascii_group_struct.each_pair do |member, value|
242
+ expect(overridden["canonical_#{member}"]).to eq(value)
243
+
244
+ # Confirm we've reassigned all non-string and array values
245
+ if !value.is_a?(String) && !value.is_a?(Array)
246
+ expect(overridden[member]).to eq(value)
247
+ expect(overridden[member].object_id).to eq(value.object_id)
248
+ end
249
+ end
250
+ end
145
251
  end
146
252
  end
147
253
 
148
- describe "setpwent" do
149
- it "should call Etc.setpwent" do
150
- Etc.expects(:setpwent)
151
- Puppet::Etc.setpwent
254
+ shared_examples "methods that return an overridden user struct from Etc" do |params|
255
+
256
+ it "should return a new Struct object with corresponding canonical_ members" do
257
+ user = Etc::Passwd.new
258
+ Etc.expects(subject).with(*params).returns(user)
259
+ puppet_user = Puppet::Etc.send(subject, *params)
260
+
261
+ expect(puppet_user.members).to include(*user.members)
262
+ expect(puppet_user.members).to include(*user.members.map { |mem| "canonical_#{mem}".to_sym })
263
+ # Confirm we haven't just added the new members to the original struct object, ie this is really a new struct
264
+ expect(user.members.any? { |elem| elem.match(/^canonical_/)}).to be_falsey
152
265
  end
153
- end
154
266
 
155
- describe "getpwnam" do
156
- context "given a username to query" do
157
- it "should call Etc.getpwnam with that username" do
158
- Etc.expects(:getpwnam).with('foo')
159
- Puppet::Etc.getpwnam('foo')
267
+ context "when Encoding.default_external is UTF-8" do
268
+ before do
269
+ Etc.expects(subject).with(*params).returns(utf_8_user_struct)
270
+ end
271
+
272
+ let(:overridden) {
273
+ PuppetSpec::CharacterEncoding.with_external_encoding(Encoding::UTF_8) do
274
+ Puppet::Etc.send(subject, *params)
275
+ end
276
+ }
277
+
278
+ it "should leave the valid UTF-8 values unmodified" do
279
+ expect(overridden.passwd).to eq(mixed_utf_8)
280
+ end
281
+
282
+ it "should replace invalid characters with unicode replacement characters in invalid UTF-8 values" do
283
+ expect(overridden.name).to eq("\uFFFD\uFFFD")
284
+ end
285
+
286
+ it "should keep an unmodified version of the invalid UTF-8 values in the corresponding canonical_ member" do
287
+ expect(overridden.canonical_name).to eq(euc_kr_as_utf_8)
160
288
  end
161
- end
162
289
 
163
- context "given an original system Etc Passwd struct with ISO-8859-1 string values" do
164
- it "should return an Etc Passwd struct with field values converted to UTF-8" do
165
- Etc.expects(:getpwnam).with('root').returns(user_struct_iso_8859_1)
166
- converted = Puppet::Etc.getpwnam('root')
167
- [converted.name, converted.passwd, converted.gecos].each do |value|
168
- expect(value.encoding).to eq(Encoding::UTF_8)
290
+ it "should copy all values to the new struct object" do
291
+ # Confirm we've actually copied all the values to the canonical_members
292
+ utf_8_user_struct.each_pair do |member, value|
293
+ expect(overridden["canonical_#{member}"]).to eq(value)
294
+
295
+ # Confirm we've reassigned all non-string and array values
296
+ if !value.is_a?(String) && !value.is_a?(Array)
297
+ expect(overridden[member]).to eq(value)
298
+ expect(overridden[member].object_id).to eq(value.object_id)
299
+ end
169
300
  end
170
301
  end
171
302
  end
172
- end
173
303
 
174
- describe "getgrnam" do
175
- context "given a group name to query" do
176
- it "should call Etc.getgrnam with that group name" do
177
- Etc.expects(:getgrnam).with('foo')
178
- Puppet::Etc.getgrnam('foo')
304
+ context "when Encoding.default_external is EUC_KR (i.e., neither UTF-8 nor POSIX)" do
305
+ before do
306
+ Etc.expects(subject).with(*params).returns(euc_kr_user_struct)
179
307
  end
180
- end
181
308
 
182
- context "given an original system Etc Group struct with ISO-8859-1 string values" do
183
- it "should return an Etc Group struct with field values converted to UTF-8" do
184
- Etc.expects(:getgrnam).with('bin').returns(group_struct_iso_8859_1)
185
- converted = Puppet::Etc.getgrnam('bin')
186
- [converted.name, converted.passwd].each do |value|
187
- expect(value.encoding).to eq(Encoding::UTF_8)
309
+ let(:overridden) {
310
+ PuppetSpec::CharacterEncoding.with_external_encoding(Encoding::EUC_KR) do
311
+ Puppet::Etc.send(subject, *params)
188
312
  end
189
- converted.mem.each { |elem| expect(elem.encoding).to eq(Encoding::UTF_8) }
313
+ }
314
+
315
+ it "should override valid UTF-8 EUC_KR-labeled values to UTF-8" do
316
+ expect(overridden.passwd).to eq(mixed_utf_8)
317
+ end
318
+
319
+ it "should leave invalid EUC_KR-labeled values unmodified" do
320
+ expect(overridden.name).to eq(euc_kr)
190
321
  end
191
- end
192
- end
193
322
 
194
- describe "getgrgid" do
195
- context "given a group ID to query" do
196
- it "should call Etc.getgrgid with the id" do
197
- Etc.expects(:getgrgid).with(0)
198
- Puppet::Etc.getgrgid(0)
323
+ it "should copy all values to the new struct object" do
324
+ # Confirm we've actually copied all the values to the canonical_members
325
+ euc_kr_user_struct.each_pair do |member, value|
326
+ expect(overridden["canonical_#{member}"]).to eq(value)
327
+
328
+ # Confirm we've reassigned all non-string and array values
329
+ if !value.is_a?(String) && !value.is_a?(Array)
330
+ expect(overridden[member]).to eq(value)
331
+ expect(overridden[member].object_id).to eq(value.object_id)
332
+ end
333
+ end
199
334
  end
200
335
  end
201
336
 
202
- context "given an original Etc Group struct with field values in ISO-8859-1" do
203
- it "should return an Etc Group struct with field values converted to UTF-8" do
204
- Etc.expects(:getgrgid).with(1).returns(group_struct_iso_8859_1)
205
- converted = Puppet::Etc.getgrgid(1)
206
- [converted.name, converted.passwd].each do |value|
207
- expect(value.encoding).to eq(Encoding::UTF_8)
337
+ context "when Encoding.default_external is POSIX (ASCII-7bit)" do
338
+ before do
339
+ Etc.expects(subject).with(*params).returns(ascii_user_struct)
340
+ end
341
+
342
+ let(:overridden) {
343
+ PuppetSpec::CharacterEncoding.with_external_encoding(Encoding::ASCII) do
344
+ Puppet::Etc.send(subject, *params)
345
+ end
346
+ }
347
+
348
+ it "should not modify binary values that would be invalid UTF-8" do
349
+ expect(overridden.name).to eq(euc_kr_as_binary)
350
+ end
351
+
352
+ it "should set the encoding to UTF-8 on binary values that would be valid UTF-8" do
353
+ expect(overridden.passwd).to eq(mixed_utf_8)
354
+ end
355
+
356
+ it "should copy all values to the new struct object" do
357
+ # Confirm we've actually copied all the values to the canonical_members
358
+ ascii_user_struct.each_pair do |member, value|
359
+ expect(overridden["canonical_#{member}"]).to eq(value)
360
+
361
+ # Confirm we've reassigned all non-string and array values
362
+ if !value.is_a?(String) && !value.is_a?(Array)
363
+ expect(overridden[member]).to eq(value)
364
+ expect(overridden[member].object_id).to eq(value.object_id)
365
+ end
208
366
  end
209
- converted.mem.each { |elem| expect(elem.encoding).to eq(Encoding::UTF_8) }
210
367
  end
211
368
  end
212
369
  end
213
370
 
214
- describe "getpwid" do
215
- context "given a UID to query" do
216
- it "should call Etc.getpwuid with the id" do
217
- Etc.expects(:getpwuid).with(2)
218
- Puppet::Etc.getpwuid(2)
219
- end
371
+ describe :getgrent do
372
+ it_should_behave_like "methods that return an overridden group struct from Etc"
373
+ end
374
+
375
+ describe :getgrnam do
376
+ it_should_behave_like "methods that return an overridden group struct from Etc", 'foo'
377
+
378
+ it "should call Etc.getgrnam with the supplied group name" do
379
+ Etc.expects(:getgrnam).with('foo')
380
+ Puppet::Etc.getgrnam('foo')
220
381
  end
221
382
  end
222
383
 
223
- context "given an orginal Etc Passwd struct with field values in ISO-8859-1" do
224
- it "should return an Etc Passwd struct with field values converted to UTF-8" do
225
- Etc.expects(:getpwuid).with(0).returns(user_struct_iso_8859_1)
226
- converted = Puppet::Etc.getpwuid(0)
227
- [converted.name, converted.passwd, converted.gecos].each do |value|
228
- expect(value.encoding).to eq(Encoding::UTF_8)
229
- end
384
+ describe :getgrgid do
385
+ it_should_behave_like "methods that return an overridden group struct from Etc", 0
386
+
387
+ it "should call Etc.getgrgid with supplied group id" do
388
+ Etc.expects(:getgrgid).with(0)
389
+ Puppet::Etc.getgrgid(0)
230
390
  end
231
391
  end
232
392
 
393
+ describe :getpwent do
394
+ it_should_behave_like "methods that return an overridden user struct from Etc"
395
+ end
396
+
397
+ describe :getpwnam do
398
+ it_should_behave_like "methods that return an overridden user struct from Etc", 'foo'
399
+
400
+ it "should call Etc.getpwnam with that username" do
401
+ Etc.expects(:getpwnam).with('foo')
402
+ Puppet::Etc.getpwnam('foo')
403
+ end
404
+ end
405
+
406
+ describe :getpwuid do
407
+ it_should_behave_like "methods that return an overridden user struct from Etc", 2
408
+
409
+ it "should call Etc.getpwuid with the id" do
410
+ Etc.expects(:getpwuid).with(2)
411
+ Puppet::Etc.getpwuid(2)
412
+ end
413
+ end
414
+
415
+ describe "endgrent" do
416
+ it "should call Etc.getgrent" do
417
+ Etc.expects(:getgrent)
418
+ Puppet::Etc.getgrent
419
+ end
420
+ end
421
+
422
+ describe "setgrent" do
423
+ it "should call Etc.setgrent" do
424
+ Etc.expects(:setgrent)
425
+ Puppet::Etc.setgrent
426
+ end
427
+ end
428
+
429
+ describe "endpwent" do
430
+ it "should call Etc.endpwent" do
431
+ Etc.expects(:endpwent)
432
+ Puppet::Etc.endpwent
433
+ end
434
+ end
233
435
 
436
+ describe "setpwent" do
437
+ it "should call Etc.setpwent" do
438
+ Etc.expects(:setpwent)
439
+ Puppet::Etc.setpwent
440
+ end
441
+ end
234
442
  end