puppet 4.3.1 → 4.3.2

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 (128) hide show
  1. checksums.yaml +4 -4
  2. data/ext/build_defaults.yaml +1 -1
  3. data/lib/hiera/scope.rb +1 -1
  4. data/lib/puppet/application/lookup.rb +41 -43
  5. data/lib/puppet/data_providers/lookup_adapter.rb +73 -26
  6. data/lib/puppet/functions/lookup.rb +126 -150
  7. data/lib/puppet/functions/match.rb +1 -0
  8. data/lib/puppet/indirector/hiera.rb +3 -1
  9. data/lib/puppet/indirector/indirection.rb +6 -2
  10. data/lib/puppet/indirector/json.rb +2 -2
  11. data/lib/puppet/module.rb +3 -2
  12. data/lib/puppet/node.rb +11 -2
  13. data/lib/puppet/parser/compiler.rb +1 -8
  14. data/lib/puppet/parser/functions/lookup.rb +128 -149
  15. data/lib/puppet/parser/functions/match.rb +1 -0
  16. data/lib/puppet/plugins/data_providers/data_provider.rb +3 -2
  17. data/lib/puppet/pops/adapters.rb +43 -0
  18. data/lib/puppet/pops/evaluator/access_operator.rb +3 -3
  19. data/lib/puppet/pops/evaluator/closure.rb +51 -51
  20. data/lib/puppet/pops/evaluator/collector_transformer.rb +16 -0
  21. data/lib/puppet/pops/evaluator/runtime3_support.rb +11 -2
  22. data/lib/puppet/pops/functions/function.rb +6 -2
  23. data/lib/puppet/pops/issues.rb +16 -0
  24. data/lib/puppet/pops/loader/puppet_function_instantiator.rb +3 -2
  25. data/lib/puppet/pops/lookup.rb +3 -0
  26. data/lib/puppet/pops/lookup/explainer.rb +73 -3
  27. data/lib/puppet/pops/lookup/invocation.rb +21 -19
  28. data/lib/puppet/pops/model/factory.rb +153 -155
  29. data/lib/puppet/pops/model/model.rb +9 -0
  30. data/lib/puppet/pops/model/model_label_provider.rb +1 -0
  31. data/lib/puppet/pops/parser/evaluating_parser.rb +3 -3
  32. data/lib/puppet/pops/parser/lexer2.rb +411 -393
  33. data/lib/puppet/pops/parser/slurp_support.rb +5 -1
  34. data/lib/puppet/pops/types/type_calculator.rb +2 -6
  35. data/lib/puppet/pops/types/types.rb +3 -9
  36. data/lib/puppet/pops/validation/checker4_0.rb +36 -12
  37. data/lib/puppet/provider/group/windows_adsi.rb +2 -2
  38. data/lib/puppet/provider/package/pip.rb +11 -1
  39. data/lib/puppet/provider/package/rpm.rb +0 -1
  40. data/lib/puppet/provider/package/yum.rb +1 -1
  41. data/lib/puppet/provider/service/debian.rb +5 -18
  42. data/lib/puppet/provider/service/init.rb +7 -0
  43. data/lib/puppet/provider/service/launchd.rb +6 -0
  44. data/lib/puppet/provider/service/systemd.rb +1 -1
  45. data/lib/puppet/provider/user/windows_adsi.rb +2 -2
  46. data/lib/puppet/provider/yumrepo/inifile.rb +6 -3
  47. data/lib/puppet/resource/type.rb +2 -1
  48. data/lib/puppet/transaction/additional_resource_generator.rb +17 -3
  49. data/lib/puppet/type/group.rb +6 -2
  50. data/lib/puppet/util/windows.rb +4 -0
  51. data/lib/puppet/util/windows/adsi.rb +61 -24
  52. data/lib/puppet/util/windows/principal.rb +181 -0
  53. data/lib/puppet/util/windows/registry.rb +21 -15
  54. data/lib/puppet/util/windows/sid.rb +42 -11
  55. data/lib/puppet/version.rb +1 -1
  56. data/spec/fixtures/unit/application/environments/production/data/common.yaml +4 -0
  57. data/spec/fixtures/unit/application/environments/production/manifests/site.pp +1 -0
  58. data/spec/fixtures/unit/application/environments/puppet_func_provider/environment.conf +1 -0
  59. data/spec/fixtures/unit/application/environments/puppet_func_provider/functions/data.pp +10 -0
  60. data/spec/fixtures/unit/application/environments/puppet_func_provider/manifests/site.pp +1 -0
  61. data/spec/fixtures/unit/data_providers/environments/hiera_module_config/data/common.yaml +4 -0
  62. data/spec/fixtures/unit/data_providers/environments/hiera_module_config/data/specific.yaml +4 -0
  63. data/spec/fixtures/unit/data_providers/environments/hiera_module_config/hiera.yaml +7 -0
  64. data/spec/fixtures/unit/data_providers/environments/hiera_modules/data/common.yaml +4 -0
  65. data/spec/fixtures/unit/data_providers/environments/hiera_modules/data/specific.yaml +4 -0
  66. data/spec/fixtures/unit/data_providers/environments/hiera_modules/environment.conf +2 -0
  67. data/spec/fixtures/unit/data_providers/environments/hiera_modules/hiera.yaml +7 -0
  68. data/spec/fixtures/unit/data_providers/environments/hiera_modules/manifests/site.pp +1 -0
  69. data/spec/fixtures/unit/data_providers/environments/hiera_modules/modules/one/data/common.yaml +6 -0
  70. data/spec/fixtures/unit/data_providers/environments/hiera_modules/modules/one/hiera.yaml +5 -0
  71. data/spec/fixtures/unit/data_providers/environments/hiera_modules/modules/one/manifests/init.pp +2 -0
  72. data/spec/fixtures/unit/data_providers/environments/hiera_modules/modules/one/metadata.json +9 -0
  73. data/spec/fixtures/unit/data_providers/environments/hiera_modules/modules/two/data/common.yaml +4 -0
  74. data/spec/fixtures/unit/data_providers/environments/hiera_modules/modules/two/hiera.yaml +5 -0
  75. data/spec/fixtures/unit/data_providers/environments/hiera_modules/modules/two/manifests/init.pp +3 -0
  76. data/spec/fixtures/unit/data_providers/environments/hiera_modules/modules/two/metadata.json +9 -0
  77. data/spec/fixtures/unit/pops/loaders/loaders/dependent_modules_with_metadata/modules/usee/functions/usee_puppet.pp +3 -0
  78. data/spec/fixtures/unit/pops/loaders/loaders/dependent_modules_with_metadata/{usee → modules/usee}/lib/puppet/functions/usee/callee.rb +0 -0
  79. data/spec/fixtures/unit/pops/loaders/loaders/dependent_modules_with_metadata/modules/usee/lib/puppet/functions/usee/usee_ruby.rb +6 -0
  80. data/spec/fixtures/unit/pops/loaders/loaders/dependent_modules_with_metadata/modules/usee/manifests/init.pp +6 -0
  81. data/spec/fixtures/unit/pops/loaders/loaders/dependent_modules_with_metadata/modules/usee2/lib/puppet/functions/usee2/callee.rb +5 -0
  82. data/spec/fixtures/unit/pops/loaders/loaders/dependent_modules_with_metadata/modules/user/functions/puppet_calling_puppet.pp +5 -0
  83. data/spec/fixtures/unit/pops/loaders/loaders/dependent_modules_with_metadata/modules/user/functions/puppet_calling_puppet_init.pp +5 -0
  84. data/spec/fixtures/unit/pops/loaders/loaders/dependent_modules_with_metadata/modules/user/functions/puppet_calling_ruby.pp +5 -0
  85. data/spec/fixtures/unit/pops/loaders/loaders/dependent_modules_with_metadata/{user → modules/user}/lib/puppet/functions/user/caller.rb +0 -0
  86. data/spec/fixtures/unit/pops/loaders/loaders/dependent_modules_with_metadata/modules/user/lib/puppet/functions/user/caller2.rb +5 -0
  87. data/spec/fixtures/unit/pops/loaders/loaders/dependent_modules_with_metadata/modules/user/lib/puppet/functions/user/ruby_calling_puppet.rb +5 -0
  88. data/spec/fixtures/unit/pops/loaders/loaders/dependent_modules_with_metadata/modules/user/lib/puppet/functions/user/ruby_calling_puppet_init.rb +5 -0
  89. data/spec/fixtures/unit/pops/loaders/loaders/dependent_modules_with_metadata/modules/user/lib/puppet/functions/user/ruby_calling_ruby.rb +5 -0
  90. data/spec/fixtures/unit/pops/loaders/loaders/dependent_modules_with_metadata/modules/user/manifests/init.pp +81 -0
  91. data/spec/fixtures/unit/pops/loaders/loaders/dependent_modules_with_metadata/{user → modules/user}/metadata.json +2 -1
  92. data/spec/integration/parser/collection_spec.rb +8 -0
  93. data/spec/integration/util/windows/principal_spec.rb +115 -0
  94. data/spec/{unit → integration}/util/windows/registry_spec.rb +91 -1
  95. data/spec/integration/util/windows/security_spec.rb +2 -2
  96. data/spec/unit/application/lookup_spec.rb +138 -28
  97. data/spec/unit/data_providers/hiera_data_provider_spec.rb +182 -5
  98. data/spec/unit/face/epp_face_spec.rb +2 -2
  99. data/spec/unit/functions/epp_spec.rb +6 -6
  100. data/spec/unit/functions/inline_epp_spec.rb +4 -4
  101. data/spec/unit/functions/lookup_spec.rb +30 -3
  102. data/spec/unit/functions4_spec.rb +1 -1
  103. data/spec/unit/hiera/scope_spec.rb +5 -2
  104. data/spec/unit/indirector/json_spec.rb +1 -1
  105. data/spec/unit/node_spec.rb +8 -0
  106. data/spec/unit/parser/compiler_spec.rb +0 -18
  107. data/spec/unit/pops/evaluator/access_ops_spec.rb +4 -4
  108. data/spec/unit/pops/evaluator/evaluating_parser_spec.rb +1 -1
  109. data/spec/unit/pops/loaders/loaders_spec.rb +84 -2
  110. data/spec/unit/pops/parser/lexer2_spec.rb +6 -0
  111. data/spec/unit/pops/parser/parser_rspec_helper.rb +5 -0
  112. data/spec/unit/pops/types/type_calculator_spec.rb +0 -17
  113. data/spec/unit/pops/validator/validator_spec.rb +87 -0
  114. data/spec/unit/provider/group/windows_adsi_spec.rb +8 -8
  115. data/spec/unit/provider/package/pip_spec.rb +41 -13
  116. data/spec/unit/provider/package/rpm_spec.rb +2 -25
  117. data/spec/unit/provider/package/yum_spec.rb +1 -1
  118. data/spec/unit/provider/service/debian_spec.rb +6 -24
  119. data/spec/unit/provider/service/init_spec.rb +11 -1
  120. data/spec/unit/provider/service/launchd_spec.rb +11 -0
  121. data/spec/unit/provider/service/systemd_spec.rb +18 -12
  122. data/spec/unit/provider/service/upstart_spec.rb +57 -0
  123. data/spec/unit/provider/user/windows_adsi_spec.rb +5 -5
  124. data/spec/unit/provider/yumrepo/inifile_spec.rb +16 -0
  125. data/spec/unit/resource_spec.rb +12 -2
  126. data/spec/unit/util/windows/adsi_spec.rb +44 -36
  127. data/spec/unit/util/windows/sid_spec.rb +47 -10
  128. metadata +77 -10
@@ -44,15 +44,15 @@ describe "the epp function" do
44
44
  it "raises an error if required variable is not given" do
45
45
  scope['x'] = 'wrong one'
46
46
  expect do
47
- eval_template_with_args("<%-| $x |-%><%= $x == correct %>", 'y' => 'correct')
48
- end.to raise_error(/no value given for required parameters x/)
47
+ eval_template("<%-| $x |-%><%= $x == correct %>")
48
+ end.to raise_error(/expects a value for parameter 'x'/)
49
49
  end
50
50
 
51
- it "raises an error if too many arguments are given" do
51
+ it 'raises an error if invalid arguments are given' do
52
52
  scope['x'] = 'wrong one'
53
53
  expect do
54
54
  eval_template_with_args("<%-| $x |-%><%= $x == correct %>", 'x' => 'correct', 'y' => 'surplus')
55
- end.to raise_error(/Too many arguments: 2 for 1/)
55
+ end.to raise_error(/has no parameter named 'y'/)
56
56
  end
57
57
  end
58
58
 
@@ -80,13 +80,13 @@ describe "the epp function" do
80
80
  it "raises an error when the passed value does not match the parameter's type" do
81
81
  expect do
82
82
  eval_template_with_args("<%-|Integer $x|-%><%= $x %>", 'x' => 'incorrect')
83
- end.to raise_error(/block parameter 'x' expects an Integer value, got String/)
83
+ end.to raise_error(/parameter 'x' expects an Integer value, got String/)
84
84
  end
85
85
 
86
86
  it "raises an error when the default value does not match the parameter's type" do
87
87
  expect do
88
88
  eval_template("<%-|Integer $x = 'nope'|-%><%= $x %>")
89
- end.to raise_error(/block parameter 'x' expects an Integer value, got String/)
89
+ end.to raise_error(/parameter 'x' expects an Integer value, got String/)
90
90
  end
91
91
 
92
92
  it "allows an parameter to default to undef" do
@@ -36,15 +36,15 @@ describe "the inline_epp function" do
36
36
  it "raises an error if required variable is not given" do
37
37
  scope['x'] = 'wrong one'
38
38
  expect {
39
- eval_template_with_args("<%-| $x |-%><%= $x == correct %>", 'y' => 'correct')
40
- }.to raise_error(/no value given for required parameters x/)
39
+ eval_template_with_args("<%-| $x |-%><%= $x == correct %>", {})
40
+ }.to raise_error(/expects a value for parameter 'x'/)
41
41
  end
42
42
 
43
- it "raises an error if too many arguments are given" do
43
+ it 'raises an error if unexpected arguments are given' do
44
44
  scope['x'] = 'wrong one'
45
45
  expect {
46
46
  eval_template_with_args("<%-| $x |-%><%= $x == correct %>", 'x' => 'correct', 'y' => 'surplus')
47
- }.to raise_error(/Too many arguments: 2 for 1/)
47
+ }.to raise_error(/has no parameter named 'y'/)
48
48
  end
49
49
  end
50
50
 
@@ -486,7 +486,7 @@ EOS
486
486
  end
487
487
  end
488
488
 
489
- it 'will handle path merge with not found correctly' do
489
+ it 'will handle path merge when some entries are not found correctly' do
490
490
  assemble_and_compile('${r}', "'hieraprovider::test::param_a'") do |scope|
491
491
  lookup_invocation = Puppet::Pops::Lookup::Invocation.new(scope, {}, {}, true)
492
492
  begin
@@ -504,10 +504,10 @@ Merge strategy first
504
504
  Data Provider "two paths"
505
505
  Merge strategy first
506
506
  Path "#{environmentpath}/production/modules/hieraprovider/data/first.json"
507
- Original path: first
507
+ Original path: "first"
508
508
  No such key: "hieraprovider::test::not_found"
509
509
  Path "#{environmentpath}/production/modules/hieraprovider/data/second_not_present.json"
510
- Original path: second_not_present
510
+ Original path: "second_not_present"
511
511
  Path not found
512
512
  EOS
513
513
  end
@@ -551,5 +551,32 @@ EOS
551
551
  )
552
552
  end
553
553
  end
554
+
555
+ it 'will explain that "lookup_options" is an invalid key' do
556
+ assemble_and_compile('${r}', "'abc::a'") do |scope|
557
+ lookup_invocation = Puppet::Pops::Lookup::Invocation.new(scope, {}, {}, true)
558
+ begin
559
+ Puppet::Pops::Lookup.lookup('lookup_options', nil, nil, false, nil, lookup_invocation)
560
+ rescue Puppet::Error
561
+ end
562
+ expect(lookup_invocation.explainer.to_s).to eq(<<EOS)
563
+ Invalid key "lookup_options"
564
+ EOS
565
+ end
566
+ end
567
+
568
+ it 'will explain that "lookup_options" is an invalid key for any key starting with "lookup_options."' do
569
+ assemble_and_compile('${r}', "'abc::a'") do |scope|
570
+ lookup_invocation = Puppet::Pops::Lookup::Invocation.new(scope, {}, {}, true)
571
+ begin
572
+ Puppet::Pops::Lookup.lookup('lookup_options.subkey', nil, nil, false, nil, lookup_invocation)
573
+ rescue Puppet::Error
574
+ end
575
+ expect(lookup_invocation.explainer.to_s).to eq(<<EOS)
576
+ Invalid key "lookup_options"
577
+ EOS
578
+ end
579
+ end
580
+
554
581
  end
555
582
  end
@@ -420,7 +420,7 @@ describe 'the 4x function api' do
420
420
  end
421
421
  # initiate the function the same way the loader initiates it
422
422
  f = fc.new(:closure_scope, Puppet.lookup(:loaders).puppet_system_loader)
423
- expect{f.call({})}.to raise_error(ArgumentError, "Function test(): cannot call function 'no_such_function' - not found")
423
+ expect{f.call({})}.to raise_error(ArgumentError, "Function test(): Unknown function: 'no_such_function'")
424
424
  end
425
425
  end
426
426
 
@@ -76,9 +76,12 @@ describe Hiera::Scope do
76
76
 
77
77
  describe "#include?" do
78
78
  it "should correctly report missing data" do
79
- real["foo"] = ""
79
+ real["nil_value"] = nil
80
+ real["blank_value"] = ""
80
81
 
81
- expect(scope.include?("foo")).to eq(false)
82
+ expect(scope.include?("nil_value")).to eq(true)
83
+ expect(scope.include?("blank_value")).to eq(true)
84
+ expect(scope.include?("missing_value")).to eq(false)
82
85
  end
83
86
 
84
87
  it "should always return true for calling_class and calling_module" do
@@ -81,7 +81,7 @@ describe Puppet::Indirector::JSON do
81
81
  # I don't like this, but there isn't a credible alternative that
82
82
  # also works on Windows, so a stub it is. At least the expectation
83
83
  # will fail if the implementation changes. Sorry to the next dev.
84
- File.expects(:read).with(file).raises(Errno::EPERM)
84
+ Puppet::FileSystem.expects(:read).with(file).raises(Errno::EPERM)
85
85
  expect { subject.find(request) }.
86
86
  to raise_error Puppet::Error, /Could not read JSON/
87
87
  end
@@ -86,6 +86,14 @@ describe Puppet::Node do
86
86
  )
87
87
  expect(node.to_pson).to validate_against('api/schemas/node.json')
88
88
  end
89
+
90
+ it "should allow its environment parameter to be set by attribute after initialization" do
91
+ node = Puppet::Node.new("foo", { :parameters => { 'environment' => :foo } })
92
+ node.environment_name = :foo
93
+ node.environment = :bar
94
+ expect(node.environment_name).to eq(:bar)
95
+ expect(node.parameters['environment']).to eq(:bar)
96
+ end
89
97
  end
90
98
 
91
99
  describe "when serializing using yaml" do
@@ -194,24 +194,6 @@ describe Puppet::Parser::Compiler do
194
194
  expect(sanitized.trusted_data).to_not eq({ :a => 42 })
195
195
  end
196
196
 
197
- it "should report 'trusted' parameters as trusted_data but as inauthentic if running as non-root" do
198
- node = Puppet::Node.new("mynode")
199
- node.parameters['trusted'] = { 'authenticated' => true,
200
- 'certname' => 'foo',
201
- 'extensions' => 'things' }
202
-
203
- Puppet.features.stubs(:root?).returns(false)
204
-
205
- Puppet.ignore(:trusted_information)
206
- compiler = Puppet::Parser::Compiler.new(node)
207
- Puppet.restore(:trusted_information)
208
-
209
- sanitized = compiler.node
210
- expect(sanitized.trusted_data).to eq({ 'authenticated' => false,
211
- 'certname' => 'foo',
212
- 'extensions' => 'things' })
213
- end
214
-
215
197
  it "should prefer trusted_data in the node above other plausible sources" do
216
198
  node = Puppet::Node.new("mynode")
217
199
  node.trusted_data = { 'authenticated' => true,
@@ -123,9 +123,9 @@ describe 'Puppet::Pops::Evaluator::EvaluatorImpl/AccessOperator' do
123
123
  expect(evaluate(expr)).to eql(range(1,1))
124
124
  end
125
125
 
126
- it 'produces an Integer[from, <from]' do
126
+ it 'gives an error for Integer[from, <from]' do
127
127
  expr = fqr('Integer')[1,0]
128
- expect(evaluate(expr)).to eql(range(1,0))
128
+ expect{evaluate(expr)}.to raise_error(/'from' must be less or equal to 'to'/)
129
129
  end
130
130
 
131
131
  it 'produces an error for Integer[] if there are more than 2 keys' do
@@ -154,9 +154,9 @@ describe 'Puppet::Pops::Evaluator::EvaluatorImpl/AccessOperator' do
154
154
  expect(evaluate(expr)).to eql(float_range(1.0,1.0))
155
155
  end
156
156
 
157
- it 'produces a Float[from, <from]' do
157
+ it 'gives an error for Float[from, <from]' do
158
158
  expr = fqr('Float')[1.0,0.0]
159
- expect(evaluate(expr)).to eql(float_range(1.0,0.0))
159
+ expect{evaluate(expr)}.to raise_error(/'from' must be less or equal to 'to'/)
160
160
  end
161
161
 
162
162
  it 'produces an error for Float[] if there are more than 2 keys' do
@@ -960,7 +960,7 @@ describe 'Puppet::Pops::Evaluator::EvaluatorImpl' do
960
960
  end
961
961
 
962
962
  it "provides location information on error in unparenthesized call logic" do
963
- expect{parser.evaluate_string(scope, "include non_existing_class", __FILE__)}.to raise_error(Puppet::ParseError, /line 1\:1/)
963
+ expect{parser.evaluate_string(scope, "include non_existing_class", __FILE__)}.to raise_error(Puppet::ParseError, /:1:1/)
964
964
  end
965
965
 
966
966
  it 'defaults can be given in a lambda and used only when arg is missing' do
@@ -31,6 +31,8 @@ describe 'loaders' do
31
31
  let(:mix_4x_and_3x_functions) { config_dir('mix_4x_and_3x_functions') }
32
32
  let(:module_with_metadata) { File.join(config_dir('single_module'), 'modules') }
33
33
  let(:dependent_modules_with_metadata) { config_dir('dependent_modules_with_metadata') }
34
+ let(:user_metadata_path) { File.join(dependent_modules_with_metadata, 'modules/user/metadata.json') }
35
+
34
36
  let(:empty_test_env) { environment_for() }
35
37
 
36
38
  # Loaders caches the puppet_system_loader, must reset between tests
@@ -103,7 +105,9 @@ describe 'loaders' do
103
105
  end
104
106
 
105
107
  it 'loader allows loading a function more than once' do
106
- env = environment_for(dependent_modules_with_metadata)
108
+ File.stubs(:read).with(user_metadata_path).returns ''
109
+
110
+ env = environment_for(File.join(dependent_modules_with_metadata, 'modules'))
107
111
  loaders = Puppet::Pops::Loaders.new(env)
108
112
 
109
113
  moduleb_loader = loaders.private_loader_for_module('user')
@@ -116,16 +120,94 @@ describe 'loaders' do
116
120
  end
117
121
 
118
122
  context 'when loading from a module with metadata' do
123
+ let(:env) { environment_for(File.join(dependent_modules_with_metadata, 'modules')) }
124
+ let(:scope) { Puppet::Parser::Compiler.new(Puppet::Node.new("test", :environment => env)).newscope(nil) }
125
+
126
+ let(:environmentpath) { my_fixture_dir }
127
+ let(:node) { Puppet::Node.new('test', :facts => Puppet::Node::Facts.new('facts', {}), :environment => 'dependent_modules_with_metadata') }
128
+ let(:compiler) { Puppet::Parser::Compiler.new(node) }
129
+
130
+ let(:user_metadata) {
131
+ {
132
+ 'name' => 'test-user',
133
+ 'author' => 'test',
134
+ 'description' => '',
135
+ 'license' => '',
136
+ 'source' => '',
137
+ 'version' => '1.0.0',
138
+ 'dependencies' => []
139
+ }
140
+ }
141
+
142
+ def compile_and_get_notifications(code)
143
+ Puppet[:code] = code
144
+ catalog = block_given? ? compiler.compile { |catalog| yield(compiler.topscope); catalog } : compiler.compile
145
+ catalog.resources.map(&:ref).select { |r| r.start_with?('Notify[') }.map { |r| r[7..-2] }
146
+ end
147
+
148
+ around(:each) do |example|
149
+ # Initialize settings to get a full compile as close as possible to a real
150
+ # environment load
151
+ Puppet.settings.initialize_global_settings
152
+
153
+ # Initialize loaders based on the environmentpath. It does not work to
154
+ # just set the setting environmentpath for some reason - this achieves the same:
155
+ # - first a loader is created, loading directory environments from the fixture (there is
156
+ # one environment, 'sample', which will be loaded since the node references this
157
+ # environment by name).
158
+ # - secondly, the created env loader is set as 'environments' in the puppet context.
159
+ #
160
+ environments = Puppet::Environments::Directories.new(environmentpath, [])
161
+ Puppet.override(:environments => environments) do
162
+ example.run
163
+ end
164
+ end
165
+
119
166
  it 'all dependent modules are visible' do
120
- env = environment_for(dependent_modules_with_metadata)
167
+ File.stubs(:read).with(user_metadata_path).returns user_metadata.merge('dependencies' => [ { 'name' => 'test-usee'}, { 'name' => 'test-usee2'} ]).to_pson
121
168
  loaders = Puppet::Pops::Loaders.new(env)
122
169
 
123
170
  moduleb_loader = loaders.private_loader_for_module('user')
124
171
  function = moduleb_loader.load_typed(typed_name(:function, 'user::caller')).value
125
172
  expect(function.call({})).to eql("usee::callee() was told 'passed value' + I am user::caller()")
173
+
174
+ function = moduleb_loader.load_typed(typed_name(:function, 'user::caller2')).value
175
+ expect(function.call({})).to eql("usee2::callee() was told 'passed value' + I am user::caller2()")
176
+ end
177
+
178
+ [ 'outside a function', 'a puppet function declared under functions', 'a puppet function declared in init.pp', 'a ruby function'].each_with_index do |from, from_idx|
179
+ [ {:from => from, :called => 'a puppet function declared under functions', :expects => "I'm the function usee::usee_puppet()"},
180
+ {:from => from, :called => 'a puppet function declared in init.pp', :expects => "I'm the function usee::usee_puppet_init()"},
181
+ {:from => from, :called => 'a ruby function', :expects => "I'm the function usee::usee_ruby()"} ].each_with_index do |desc, called_idx|
182
+ case_number = from_idx * 3 + called_idx + 1
183
+ it "can call #{desc[:called]} from #{desc[:from]} when dependency is present in metadata.json" do
184
+ File.stubs(:read).with(user_metadata_path).returns user_metadata.merge('dependencies' => [ { 'name' => 'test-usee'} ]).to_pson
185
+ Puppet[:code] = "$case_number = #{case_number}\ninclude ::user"
186
+ catalog = compiler.compile
187
+ resource = catalog.resource('Notify', "case_#{case_number}")
188
+ expect(resource).not_to be_nil
189
+ expect(resource['message']).to eq(desc[:expects])
190
+ end
191
+
192
+ it "can call #{desc[:called]} from #{desc[:from]} when no metadata is present" do
193
+ Puppet::Module.any_instance.expects('has_metadata?').at_least_once.returns(false)
194
+ Puppet[:code] = "$case_number = #{case_number}\ninclude ::user"
195
+ catalog = compiler.compile
196
+ resource = catalog.resource('Notify', "case_#{case_number}")
197
+ expect(resource).not_to be_nil
198
+ expect(resource['message']).to eq(desc[:expects])
199
+ end
200
+
201
+ it 'can not call ruby function in a dependent module from outside a function if dependency is missing in existing metadata.json' do
202
+ File.stubs(:read).with(user_metadata_path).returns user_metadata.merge('dependencies' => []).to_pson
203
+ Puppet[:code] = "$case_number = #{case_number}\ninclude ::user"
204
+ expect { catalog = compiler.compile }.to raise_error(Puppet::Error, /Unknown function/)
205
+ end
206
+ end
126
207
  end
127
208
  end
128
209
 
210
+
129
211
  context 'when loading from a module without metadata' do
130
212
  it 'loads a ruby function with a qualified name' do
131
213
  loaders = Puppet::Pops::Loaders.new(environment_for(module_without_metadata))
@@ -329,6 +329,12 @@ describe 'Lexer2' do
329
329
  end
330
330
  end
331
331
 
332
+ it 'detects unterminated multiline comment' do
333
+ expect { tokens_scanned_from("/* not terminated\nmultiline\ncomment") }.to raise_error(Puppet::ParseErrorWithIssue) { |e|
334
+ expect(e.issue_code).to be(Puppet::Pops::Issues::UNCLOSED_MLCOMMENT.issue_code)
335
+ }
336
+ end
337
+
332
338
  { "=~" => [:MATCH, "=~ /./"],
333
339
  "!~" => [:NOMATCH, "!~ /./"],
334
340
  "," => [:COMMA, ", /./"],
@@ -13,4 +13,9 @@ module ParserRspecHelper
13
13
  parser = Puppet::Pops::Parser::Parser.new()
14
14
  parser.parse_string(code)
15
15
  end
16
+
17
+ def parse_epp(code)
18
+ parser = Puppet::Pops::Parser::EppParser.new()
19
+ parser.parse_string(code)
20
+ end
16
21
  end
@@ -970,35 +970,18 @@ describe 'The type calculator' do
970
970
  expect(calculator.assignable?(range_t(2,5), range_t(2,5))).to eq(true)
971
971
  end
972
972
 
973
- it 'should accept an equal reverse range' do
974
- expect(calculator.assignable?(range_t(2,5), range_t(5,2))).to eq(true)
975
- end
976
-
977
973
  it 'should accept a narrower range' do
978
974
  expect(calculator.assignable?(range_t(2,10), range_t(3,5))).to eq(true)
979
975
  end
980
976
 
981
- it 'should accept a narrower reverse range' do
982
- expect(calculator.assignable?(range_t(2,10), range_t(5,3))).to eq(true)
983
- end
984
-
985
977
  it 'should reject a wider range' do
986
978
  expect(calculator.assignable?(range_t(3,5), range_t(2,10))).to eq(false)
987
979
  end
988
980
 
989
- it 'should reject a wider reverse range' do
990
- expect(calculator.assignable?(range_t(3,5), range_t(10,2))).to eq(false)
991
- end
992
-
993
981
  it 'should reject a partially overlapping range' do
994
982
  expect(calculator.assignable?(range_t(3,5), range_t(2,4))).to eq(false)
995
983
  expect(calculator.assignable?(range_t(3,5), range_t(4,6))).to eq(false)
996
984
  end
997
-
998
- it 'should reject a partially overlapping reverse range' do
999
- expect(calculator.assignable?(range_t(3,5), range_t(4,2))).to eq(false)
1000
- expect(calculator.assignable?(range_t(3,5), range_t(6,4))).to eq(false)
1001
- end
1002
985
  end
1003
986
 
1004
987
  context 'when dealing with patterns' do
@@ -107,6 +107,46 @@ describe "validating 4x" do
107
107
  SOURCE
108
108
  expect(validate(parse(source))).to have_issue(Puppet::Pops::Issues::IDEM_NOT_ALLOWED_LAST)
109
109
  end
110
+
111
+ it "detects a resource declared without title in #{type} when it is the only declaration present" do
112
+ source = <<-SOURCE
113
+ #{type} nope {
114
+ notify { message => 'Nope' }
115
+ }
116
+ SOURCE
117
+ expect(validate(parse(source))).to have_issue(Puppet::Pops::Issues::RESOURCE_WITHOUT_TITLE)
118
+ end
119
+
120
+ it "detects a resource declared without title in #{type} when it is in between other declarations" do
121
+ source = <<-SOURCE
122
+ #{type} nope {
123
+ notify { succ: message => 'Nope' }
124
+ notify { message => 'Nope' }
125
+ notify { pred: message => 'Nope' }
126
+ }
127
+ SOURCE
128
+ expect(validate(parse(source))).to have_issue(Puppet::Pops::Issues::RESOURCE_WITHOUT_TITLE)
129
+ end
130
+
131
+ it "detects a resource declared without title in #{type} when it is declarated first" do
132
+ source = <<-SOURCE
133
+ #{type} nope {
134
+ notify { message => 'Nope' }
135
+ notify { pred: message => 'Nope' }
136
+ }
137
+ SOURCE
138
+ expect(validate(parse(source))).to have_issue(Puppet::Pops::Issues::RESOURCE_WITHOUT_TITLE)
139
+ end
140
+
141
+ it "detects a resource declared without title in #{type} when it is declarated last" do
142
+ source = <<-SOURCE
143
+ #{type} nope {
144
+ notify { succ: message => 'Nope' }
145
+ notify { message => 'Nope' }
146
+ }
147
+ SOURCE
148
+ expect(validate(parse(source))).to have_issue(Puppet::Pops::Issues::RESOURCE_WITHOUT_TITLE)
149
+ end
110
150
  end
111
151
  end
112
152
 
@@ -177,6 +217,18 @@ describe "validating 4x" do
177
217
  end
178
218
  end
179
219
 
220
+ context 'for parameter names' do
221
+ ['class', 'define'].each do |word|
222
+ it "should require that #{word} parameter names are unique" do
223
+ expect(validate(parse("#{word} foo($a = 10, $a = 20) {}"))).to have_issue(Puppet::Pops::Issues::DUPLICATE_PARAMETER)
224
+ end
225
+ end
226
+
227
+ it "should require that template parameter names are unique" do
228
+ expect(validate(parse_epp("<%-| $a, $a |-%><%= $a == doh %>"))).to have_issue(Puppet::Pops::Issues::DUPLICATE_PARAMETER)
229
+ end
230
+ end
231
+
180
232
  context 'for reserved parameter names' do
181
233
  ['name', 'title'].each do |word|
182
234
  it "produces an error when $#{word} is used as a parameter in a class" do
@@ -241,6 +293,41 @@ describe "validating 4x" do
241
293
  expect(validate(parse(source))).to have_issue(Puppet::Pops::Issues::NOT_TOP_LEVEL)
242
294
  end
243
295
  end
296
+
297
+ ['class', 'define', 'node'].each do |word|
298
+ it "produces an error when $#{word} is nested in an function" do
299
+ source = "function y() { #{word} x {} }"
300
+ expect(validate(parse(source))).to have_issue(Puppet::Pops::Issues::NOT_TOP_LEVEL)
301
+ end
302
+ end
303
+
304
+ it 'produces an error when a function is nested in an function' do
305
+ source = 'function y() { function x() {} }'
306
+ expect(validate(parse(source))).to have_issue(Puppet::Pops::Issues::NOT_ABSOLUTE_TOP_LEVEL)
307
+ end
308
+
309
+ ['class', 'define', 'node'].each do |word|
310
+ it "produces an error when function is nested in a #{word}" do
311
+ source = "#{word} x { function y() {} }"
312
+ expect(validate(parse(source))).to have_issue(Puppet::Pops::Issues::NOT_ABSOLUTE_TOP_LEVEL)
313
+ end
314
+ end
315
+
316
+ it 'does not produce an error when function is at top level script' do
317
+ source = 'function y() {}'
318
+ expect(validate(parse(source))).not_to have_issue(Puppet::Pops::Issues::NOT_ABSOLUTE_TOP_LEVEL)
319
+ end
320
+
321
+ it 'does not produce an error when function is at top level file' do
322
+ source = 'function y() {}'
323
+
324
+ # We simulate a file by inserting a block between the program and the contained function
325
+ program = parse(source).current
326
+ function = program.body
327
+ program.body = Puppet::Pops::Model::BlockExpression.new
328
+ program.body.addStatements(function)
329
+ expect(validate(program)).not_to have_issue(Puppet::Pops::Issues::NOT_ABSOLUTE_TOP_LEVEL)
330
+ end
244
331
  end
245
332
 
246
333
  context "capability annotations" do