diff --git a/acceptance/tests/apply/virtual/should_realize_complex_query.rb b/acceptance/tests/apply/virtual/should_realize_complex_query.rb deleted file mode 100755 index 512b5cbfc..000000000 --- a/acceptance/tests/apply/virtual/should_realize_complex_query.rb +++ /dev/null @@ -1,39 +0,0 @@ -test_name "should realize with complex query" - -agents.each do |agent| - out = agent.tmpfile('should_realize_complex_query') - name = "test-#{Time.new.to_i}-host" - -manifest = %Q{ - @host { '#{name}1': - ip => '127.0.0.2', - target => '#{out}', - host_aliases => ['one', 'two', 'three'], - ensure => present, - } - @host { '#{name}2': - ip => '127.0.0.3', - target => '#{out}', - host_aliases => 'two', - ensure => present, - } - Host<| host_aliases == 'two' and ip == '127.0.0.3' |> -} - - step "clean up target system for test" - on agent, "rm -f #{out}" - - step "run the manifest" - apply_manifest_on agent, manifest - - step "verify the file output" - on(agent, "cat #{out}") do - fail_test "second host not found in output" unless - stdout.include? "#{name}2" - fail_test "first host was found in output" if - stdout.include? "#{name}1" - end - - step "clean up system after testing" - on agent, "rm -f #{out}" -end diff --git a/acceptance/tests/apply/virtual/should_realize_query_array.rb b/acceptance/tests/apply/virtual/should_realize_query_array.rb deleted file mode 100755 index c2fa8f6ea..000000000 --- a/acceptance/tests/apply/virtual/should_realize_query_array.rb +++ /dev/null @@ -1,27 +0,0 @@ -test_name "should realize query array" - -agents.each do |agent| - out = agent.tmpfile('should_realize_query_array') - name = "test-#{Time.new.to_i}-host" - -manifest = %Q{ - @host { '#{name}': - ip => '127.0.0.2', - target => '#{out}', - host_aliases => ['one', 'two', 'three'], - ensure => present, - } - Host<| host_aliases == 'two' |> -} - - step "clean up target system for test" - on agent, "rm -f #{out}" - - step "run the manifest" - apply_manifest_on agent, manifest - - step "verify the file output" - on(agent, "cat #{out}") do - fail_test "host not found in output" unless stdout.include? name - end -end diff --git a/lib/puppet/parser/ast/collexpr.rb b/lib/puppet/parser/ast/collexpr.rb index 481c14b20..92f9cc10f 100644 --- a/lib/puppet/parser/ast/collexpr.rb +++ b/lib/puppet/parser/ast/collexpr.rb @@ -1,109 +1,109 @@ require 'puppet' require 'puppet/parser/ast/branch' require 'puppet/parser/collector' # An object that collects stored objects from the central cache and returns # them to the current host, yo. class Puppet::Parser::AST class CollExpr < AST::Branch attr_accessor :test1, :test2, :oper, :form, :type, :parens def evaluate(scope) if Puppet[:parser] == 'future' evaluate4x(scope) else evaluate3x(scope) end end # We return an object that does a late-binding evaluation. def evaluate3x(scope) # Make sure our contained expressions have all the info they need. [@test1, @test2].each do |t| if t.is_a?(self.class) t.form ||= self.form t.type ||= self.type end end # The code is only used for virtual lookups match1, code1 = @test1.safeevaluate scope match2, code2 = @test2.safeevaluate scope # First build up the virtual code. # If we're a conjunction operator, then we're calling code. I did # some speed comparisons, and it's at least twice as fast doing these # case statements as doing an eval here. code = proc do |resource| case @oper when "and"; code1.call(resource) and code2.call(resource) when "or"; code1.call(resource) or code2.call(resource) when "==" if match1 == "tag" resource.tagged?(match2) else if resource[match1].is_a?(Array) resource[match1].include?(match2) else resource[match1] == match2 end end when "!="; resource[match1] != match2 end end match = [match1, @oper, match2] return match, code end # Late binding evaluation of a collect expression (as done in 3x), but with proper Puppet Language # semantics for equals and include # def evaluate4x(scope) # Make sure our contained expressions have all the info they need. [@test1, @test2].each do |t| if t.is_a?(self.class) t.form ||= self.form t.type ||= self.type end end # The code is only used for virtual lookups match1, code1 = @test1.safeevaluate scope match2, code2 = @test2.safeevaluate scope # First build up the virtual code. # If we're a conjunction operator, then we're calling code. I did # some speed comparisons, and it's at least twice as fast doing these # case statements as doing an eval here. code = proc do |resource| case @oper when "and"; code1.call(resource) and code2.call(resource) when "or"; code1.call(resource) or code2.call(resource) when "==" if match1 == "tag" resource.tagged?(match2) else if resource[match1].is_a?(Array) - @@compare_operator.include?(resource[match1], match2) + @@compare_operator.include?(resource[match1], match2, scope) else @@compare_operator.equals(resource[match1], match2) end end when "!="; ! @@compare_operator.equals(resource[match1], match2) end end match = [match1, @oper, match2] return match, code end def initialize(hash = {}) super if Puppet[:parser] == "future" @@compare_operator ||= Puppet::Pops::Evaluator::CompareOperator.new end raise ArgumentError, "Invalid operator #{@oper}" unless %w{== != and or}.include?(@oper) end end end diff --git a/spec/integration/parser/collector_spec.rb b/spec/integration/parser/collector_spec.rb index 49ce74583..2e698da1b 100755 --- a/spec/integration/parser/collector_spec.rb +++ b/spec/integration/parser/collector_spec.rb @@ -1,117 +1,144 @@ #! /usr/bin/env ruby require 'spec_helper' require 'puppet_spec/compiler' require 'puppet/parser/collector' describe Puppet::Parser::Collector do include PuppetSpec::Compiler def expect_the_message_to_be(expected_messages, code, node = Puppet::Node.new('the node')) catalog = compile_to_catalog(code, node) messages = catalog.resources.find_all { |resource| resource.type == 'Notify' }. collect { |notify| notify[:message] } messages.should include(*expected_messages) end - it "matches on title" do - expect_the_message_to_be(["the message"], <<-MANIFEST) - @notify { "testing": message => "the message" } + shared_examples_for "virtual resource collection" do + it "matches on title" do + expect_the_message_to_be(["the message"], <<-MANIFEST) + @notify { "testing": message => "the message" } - Notify <| title == "testing" |> - MANIFEST - end + Notify <| title == "testing" |> + MANIFEST + end - it "matches on other parameters" do - expect_the_message_to_be(["the message"], <<-MANIFEST) - @notify { "testing": message => "the message" } - @notify { "other testing": message => "the wrong message" } + it "matches on other parameters" do + expect_the_message_to_be(["the message"], <<-MANIFEST) + @notify { "testing": message => "the message" } + @notify { "other testing": message => "the wrong message" } - Notify <| message == "the message" |> - MANIFEST - end + Notify <| message == "the message" |> + MANIFEST + end - it "allows criteria to be combined with 'and'" do - expect_the_message_to_be(["the message"], <<-MANIFEST) - @notify { "testing": message => "the message" } - @notify { "other": message => "the message" } + it "matches against elements of an array valued parameter" do + expect_the_message_to_be([["the", "message"]], <<-MANIFEST) + @notify { "testing": message => ["the", "message"] } + @notify { "other testing": message => ["not", "here"] } - Notify <| title == "testing" and message == "the message" |> - MANIFEST - end + Notify <| message == "message" |> + MANIFEST + end - it "allows criteria to be combined with 'or'" do - expect_the_message_to_be(["the message", "other message"], <<-MANIFEST) - @notify { "testing": message => "the message" } - @notify { "other": message => "other message" } - @notify { "yet another": message => "different message" } + it "allows criteria to be combined with 'and'" do + expect_the_message_to_be(["the message"], <<-MANIFEST) + @notify { "testing": message => "the message" } + @notify { "other": message => "the message" } - Notify <| title == "testing" or message == "other message" |> - MANIFEST - end + Notify <| title == "testing" and message == "the message" |> + MANIFEST + end - it "allows criteria to be combined with 'or'" do - expect_the_message_to_be(["the message", "other message"], <<-MANIFEST) - @notify { "testing": message => "the message" } - @notify { "other": message => "other message" } - @notify { "yet another": message => "different message" } + it "allows criteria to be combined with 'or'" do + expect_the_message_to_be(["the message", "other message"], <<-MANIFEST) + @notify { "testing": message => "the message" } + @notify { "other": message => "other message" } + @notify { "yet another": message => "different message" } - Notify <| title == "testing" or message == "other message" |> - MANIFEST - end + Notify <| title == "testing" or message == "other message" |> + MANIFEST + end - it "allows criteria to be grouped with parens" do - expect_the_message_to_be(["the message", "different message"], <<-MANIFEST) - @notify { "testing": message => "different message", withpath => true } - @notify { "other": message => "the message" } - @notify { "yet another": message => "the message", withpath => true } + it "allows criteria to be combined with 'or'" do + expect_the_message_to_be(["the message", "other message"], <<-MANIFEST) + @notify { "testing": message => "the message" } + @notify { "other": message => "other message" } + @notify { "yet another": message => "different message" } - Notify <| (title == "testing" or message == "the message") and withpath == true |> - MANIFEST - end + Notify <| title == "testing" or message == "other message" |> + MANIFEST + end - it "does not do anything if nothing matches" do - expect_the_message_to_be([], <<-MANIFEST) - @notify { "testing": message => "different message" } + it "allows criteria to be grouped with parens" do + expect_the_message_to_be(["the message", "different message"], <<-MANIFEST) + @notify { "testing": message => "different message", withpath => true } + @notify { "other": message => "the message" } + @notify { "yet another": message => "the message", withpath => true } - Notify <| title == "does not exist" |> - MANIFEST - end + Notify <| (title == "testing" or message == "the message") and withpath == true |> + MANIFEST + end - it "excludes items with inequalities" do - expect_the_message_to_be(["good message"], <<-MANIFEST) - @notify { "testing": message => "good message" } - @notify { "the wrong one": message => "bad message" } + it "does not do anything if nothing matches" do + expect_the_message_to_be([], <<-MANIFEST) + @notify { "testing": message => "different message" } - Notify <| title != "the wrong one" |> - MANIFEST - end + Notify <| title == "does not exist" |> + MANIFEST + end - context "issue #10963" do - it "collects with override when inside a class" do - expect_the_message_to_be(["overridden message"], <<-MANIFEST) - @notify { "testing": message => "original message" } + it "excludes items with inequalities" do + expect_the_message_to_be(["good message"], <<-MANIFEST) + @notify { "testing": message => "good message" } + @notify { "the wrong one": message => "bad message" } - include collector_test - class collector_test { - Notify <| |> { - message => "overridden message" - } - } + Notify <| title != "the wrong one" |> MANIFEST end - it "collects with override when inside a define" do - expect_the_message_to_be(["overridden message"], <<-MANIFEST) - @notify { "testing": message => "original message" } + context "issue #10963" do + it "collects with override when inside a class" do + expect_the_message_to_be(["overridden message"], <<-MANIFEST) + @notify { "testing": message => "original message" } - collector_test { testing: } - define collector_test() { - Notify <| |> { - message => "overridden message" + include collector_test + class collector_test { + Notify <| |> { + message => "overridden message" + } } - } - MANIFEST + MANIFEST + end + + it "collects with override when inside a define" do + expect_the_message_to_be(["overridden message"], <<-MANIFEST) + @notify { "testing": message => "original message" } + + collector_test { testing: } + define collector_test() { + Notify <| |> { + message => "overridden message" + } + } + MANIFEST + end end end + + describe "in the current parser" do + before :each do + Puppet[:parser] = 'current' + end + + it_behaves_like "virtual resource collection" + end + + describe "in the future parser" do + before :each do + Puppet[:parser] = 'future' + end + + it_behaves_like "virtual resource collection" + end end