diff --git a/lib/puppet/parser/functions/contain.rb b/lib/puppet/parser/functions/contain.rb index 8eb514561..114fb5079 100644 --- a/lib/puppet/parser/functions/contain.rb +++ b/lib/puppet/parser/functions/contain.rb @@ -1,26 +1,28 @@ # Called within a class definition, establishes a containment # relationship with another class Puppet::Parser::Functions::newfunction( :contain, :arity => -2, :doc => "Contain one or more classes inside the current class. If any of these classes are undeclared, they will be declared as if called with the `include` function. Accepts a class name, an array of class names, or a comma-separated list of class names. A contained class will not be applied before the containing class is begun, and will be finished before the containing class is finished. " ) do |classes| scope = self scope.function_include(classes) classes.each do |class_name| - class_resource = scope.catalog.resource("Class", class_name) + # Remove global anchor since it is not part of the resource title and what was just + # included is then not found. + class_resource = scope.catalog.resource("Class", class_name.sub(/^::/, '')) if ! scope.catalog.edge?(scope.resource, class_resource) scope.catalog.add_edge(scope.resource, class_resource) end end end diff --git a/spec/unit/parser/functions/contain_spec.rb b/spec/unit/parser/functions/contain_spec.rb index 3150e0c8e..6db9c4e3d 100644 --- a/spec/unit/parser/functions/contain_spec.rb +++ b/spec/unit/parser/functions/contain_spec.rb @@ -1,185 +1,201 @@ #! /usr/bin/env ruby require 'spec_helper' require 'puppet_spec/compiler' require 'puppet/parser/functions' require 'matchers/containment_matchers' require 'matchers/include_in_order' describe 'The "contain" function' do include PuppetSpec::Compiler include ContainmentMatchers it "includes the class" do catalog = compile_to_catalog(<<-MANIFEST) class contained { notify { "contained": } } class container { contain contained } include container MANIFEST expect(catalog.classes).to include("contained") end + it "includes the class when using a fully qualified anchored name" do + catalog = compile_to_catalog(<<-MANIFEST) + class contained { + notify { "contained": } + } + + class container { + contain ::contained + } + + include container + MANIFEST + + expect(catalog.classes).to include("contained") + end + it "makes the class contained in the current class" do catalog = compile_to_catalog(<<-MANIFEST) class contained { notify { "contained": } } class container { contain contained } include container MANIFEST expect(catalog).to contain_class("contained").in("container") end it "can contain multiple classes" do catalog = compile_to_catalog(<<-MANIFEST) class a { notify { "a": } } class b { notify { "b": } } class container { contain a, b } include container MANIFEST expect(catalog).to contain_class("a").in("container") expect(catalog).to contain_class("b").in("container") end context "when containing a class in multiple classes" do it "creates a catalog with all containment edges" do catalog = compile_to_catalog(<<-MANIFEST) class contained { notify { "contained": } } class container { contain contained } class another { contain contained } include container include another MANIFEST expect(catalog).to contain_class("contained").in("container") expect(catalog).to contain_class("contained").in("another") end it "and there are no dependencies applies successfully" do manifest = <<-MANIFEST class contained { notify { "contained": } } class container { contain contained } class another { contain contained } include container include another MANIFEST expect { apply_compiled_manifest(manifest) }.not_to raise_error end it "and there are explicit dependencies on the containing class causes a dependency cycle" do manifest = <<-MANIFEST class contained { notify { "contained": } } class container { contain contained } class another { contain contained } include container include another Class["container"] -> Class["another"] MANIFEST expect { apply_compiled_manifest(manifest) }.to raise_error( Puppet::Error, /Found 1 dependency cycle/ ) end end it "does not create duplicate edges" do catalog = compile_to_catalog(<<-MANIFEST) class contained { notify { "contained": } } class container { contain contained contain contained } include container MANIFEST contained = catalog.resource("Class", "contained") container = catalog.resource("Class", "container") expect(catalog.edges_between(container, contained)).to have(1).item end context "when a containing class has a dependency order" do it "the contained class is applied in that order" do catalog = compile_to_relationship_graph(<<-MANIFEST) class contained { notify { "contained": } } class container { contain contained } class first { notify { "first": } } class last { notify { "last": } } include container, first, last Class["first"] -> Class["container"] -> Class["last"] MANIFEST expect(order_resources_traversed_in(catalog)).to include_in_order( "Notify[first]", "Notify[contained]", "Notify[last]" ) end end end