diff --git a/lib/puppet/parser/collector.rb b/lib/puppet/parser/collector.rb index 044518793..67bd336bb 100644 --- a/lib/puppet/parser/collector.rb +++ b/lib/puppet/parser/collector.rb @@ -41,9 +41,7 @@ class Puppet::Parser::Collector # overrided those resources objects.each do |res| unless @collected.include?(res.ref) - res = Puppet::Parser::Resource.new( - :type => res.type, - :title => res.title, + newres = Puppet::Parser::Resource.new(res.type, res.title, :params => overrides[:params], :file => overrides[:file], :line => overrides[:line], @@ -51,7 +49,7 @@ class Puppet::Parser::Collector :scope => overrides[:scope] ) - scope.compiler.add_override(res) + scope.compiler.add_override(newres) end end end diff --git a/lib/puppet/parser/resource.rb b/lib/puppet/parser/resource.rb index 36f1fbe93..3f6d73df3 100644 --- a/lib/puppet/parser/resource.rb +++ b/lib/puppet/parser/resource.rb @@ -108,7 +108,9 @@ class Puppet::Parser::Resource < Puppet::Resource end def initialize(type, title, options) - self.type = type + @scope = options[:scope] + + self.relative_type = type self.title = title @params = {} diff --git a/lib/puppet/reports/store.rb b/lib/puppet/reports/store.rb index 04eff82f9..a74527566 100644 --- a/lib/puppet/reports/store.rb +++ b/lib/puppet/reports/store.rb @@ -18,7 +18,8 @@ Puppet::Reports.register_report(:store) do :desc => "Client dir for %s" % client, :owner => 'service', :group => 'service' - } + }, + :noop => [false, "Used by settings internally."] ) config.use("reportclient-#{client}".to_sym) diff --git a/lib/puppet/resource.rb b/lib/puppet/resource.rb index ec1fd2eae..630e8a823 100644 --- a/lib/puppet/resource.rb +++ b/lib/puppet/resource.rb @@ -13,7 +13,8 @@ class Puppet::Resource extend Puppet::Util::Pson include Enumerable attr_accessor :file, :line, :catalog, :exported, :virtual, :validate_parameters - attr_reader :type, :title, :namespaces + attr_reader :title, :namespaces + attr_writer :relative_type require 'puppet/indirector' extend Puppet::Indirector @@ -145,8 +146,6 @@ class Puppet::Resource # Create our resource. def initialize(type, title = nil, attributes = {}) - self.type, self.title = extract_type_and_title(type, title) - @parameters = {} @namespaces = [""] @@ -159,6 +158,13 @@ class Puppet::Resource send(attr.to_s + "=", value) end + # We do namespaces first, and use tmp variables, so our title + # canonicalization works (i.e., namespaces are set and resource + # types can be looked up) + tmp_type, tmp_title = extract_type_and_title(type, title) + self.type = tmp_type + self.title = tmp_title + tag(self.type) tag(self.title) if valid_tag?(self.title) end @@ -174,14 +180,19 @@ class Puppet::Resource end def title=(value) - if @type and klass = Puppet::Type.type(@type.to_s.downcase) + if klass = resource_type and klass.respond_to?(:canonicalize_ref) value = klass.canonicalize_ref(value) end @title = value end + # Canonize the type so we know it's always consistent. + def relative_type + munge_type_name(@relative_type) + end + def resource_type - case type.to_s.downcase + case relative_type.to_s.downcase when "class"; find_hostclass when "node"; find_node else @@ -290,13 +301,18 @@ class Puppet::Resource self end - # Canonize the type so we know it's always consistent. - def type=(value) - if value.nil? or value.to_s.downcase == "component" - @type = "Class" + def type + munge_type_name(if r = resource_type + resource_type.name else - @type = value.to_s.split("::").collect { |s| s.capitalize }.join("::") - end + relative_type + end) + end + + # Only allow people to set the relative type, + # so we force it to be looked up each time. + def type=(value) + @relative_type = value end def valid_parameter?(name) @@ -319,11 +335,11 @@ class Puppet::Resource end def find_builtin_resource_type - Puppet::Type.type(type.to_s.downcase.to_sym) + Puppet::Type.type(relative_type.to_s.downcase.to_sym) end def find_defined_resource_type - known_resource_types.find_definition(namespaces, type.to_s.downcase) + known_resource_types.find_definition(namespaces, relative_type.to_s.downcase) end # Produce a canonical method name. @@ -369,4 +385,14 @@ class Puppet::Resource else raise ArgumentError, "No title provided and #{argtype.inspect} is not a valid resource reference" end end + + def munge_type_name(value) + return :main if value == "" + + if value.nil? or value.to_s.downcase == "component" + "Class" + else + value.to_s.split("::").collect { |s| s.capitalize }.join("::") + end + end end diff --git a/lib/puppet/util/rails/reference_serializer.rb b/lib/puppet/util/rails/reference_serializer.rb index 63f109cec..a23f2cbea 100644 --- a/lib/puppet/util/rails/reference_serializer.rb +++ b/lib/puppet/util/rails/reference_serializer.rb @@ -15,7 +15,7 @@ module Puppet::Util::ReferenceSerializer def serialize_value(val) case val - when Puppet::Parser::Resource::Reference + when Puppet::Resource YAML.dump(val) when true, false # The database does this for us, but I prefer the diff --git a/spec/integration/transaction.rb b/spec/integration/transaction.rb index a387bf7c9..b87bfb3b5 100755 --- a/spec/integration/transaction.rb +++ b/spec/integration/transaction.rb @@ -4,10 +4,17 @@ require File.dirname(__FILE__) + '/../spec_helper' require 'puppet_spec/files' require 'puppet/transaction' +require 'puppet_spec/files' describe Puppet::Transaction do include PuppetSpec::Files + def mk_catalog(*resources) + catalog = Puppet::Resource::Catalog.new(Puppet::Node.new("mynode")) + resources.each { |res| catalog.add_resource res } + catalog + end + it "should not apply generated resources if the parent resource fails" do catalog = Puppet::Resource::Catalog.new resource = Puppet::Type.type(:file).new :path => "/foo/bar", :backup => false @@ -19,7 +26,8 @@ describe Puppet::Transaction do transaction = Puppet::Transaction.new(catalog) - resource.expects(:retrieve).raises "this is a failure" + resource.expects(:evaluate).raises "this is a failure" + resource.stubs(:err) child_resource.expects(:retrieve).never @@ -41,15 +49,13 @@ describe Puppet::Transaction do it "should apply exported resources" do catalog = Puppet::Resource::Catalog.new - resource = Puppet::Type.type(:file).new :path => "/foo/bar", :backup => false + path = tmpfile("exported_files") + resource = Puppet::Type.type(:file).new :path => path, :backup => false, :ensure => :file resource.exported = true catalog.add_resource resource - transaction = Puppet::Transaction.new(catalog) - - resource.expects(:evaluate).never - - transaction.evaluate + catalog.apply + FileTest.should be_exist(path) end it "should not apply virtual exported resources" do @@ -66,119 +72,166 @@ describe Puppet::Transaction do transaction.evaluate end - it "should refresh resources that subscribe to changed resources" do - name = tmpfile("something") - file = Puppet::Type.type(:file).new( - :name => name, - :ensure => "file" - ) - exec = Puppet::Type.type(:exec).new( - :name => "echo true", - :path => "/usr/bin:/bin", - :refreshonly => true, - :subscribe => Puppet::Resource::Reference.new(file.class.name, file.name) - ) + # Verify that one component requiring another causes the contained + # resources in the requiring component to get refreshed. + it "should propagate events from a contained resource through its container to its dependent container's contained resources" do + transaction = nil + file = Puppet::Type.type(:file).new :path => tmpfile("event_propagation"), :ensure => :present + execfile = File.join(tmpdir("exec_event"), "exectestingness2") + exec = Puppet::Type.type(:exec).new :command => "touch #{execfile}", :path => ENV['PATH'] + catalog = mk_catalog(file) - catalog = Puppet::Resource::Catalog.new - catalog.add_resource file, exec + fcomp = Puppet::Type.type(:component).new(:name => "Foo[file]") + catalog.add_resource fcomp + catalog.add_edge(fcomp, file) + + ecomp = Puppet::Type.type(:component).new(:name => "Foo[exec]") + catalog.add_resource ecomp + catalog.add_resource exec + catalog.add_edge(ecomp, exec) + + ecomp[:subscribe] = Puppet::Resource.new(:foo, "file") + exec[:refreshonly] = true exec.expects(:refresh) - catalog.apply end - it "should not refresh resources that only require changed resources" do - name = tmpfile("something") + # Make sure that multiple subscriptions get triggered. + it "should propagate events to all dependent resources" do + path = tmpfile("path") + file1 = tmpfile("file1") + file2 = tmpfile("file2") file = Puppet::Type.type(:file).new( - :name => name, + :path => path, :ensure => "file" ) - exec = Puppet::Type.type(:exec).new( - :name => "echo true", - :path => "/usr/bin:/bin", - :refreshonly => true, - :require => Puppet::Resource::Reference.new(file.class.name, file.name) - ) - - - catalog = Puppet::Resource::Catalog.new - catalog.add_resource file - catalog.add_resource exec - - exec.expects(:refresh).never - - trans = catalog.apply - - trans.events.length.should == 1 - end - - it "should cascade events such that multiple refreshes result" do - files = [] - - 4.times { |i| - files << Puppet::Type.type(:file).new( - :name => tmpfile("something"), - :ensure => "file" - ) - } - - fname = tmpfile("something") - exec = Puppet::Type.type(:exec).new( - :name => "touch %s" % fname, - :path => "/usr/bin:/bin", - :refreshonly => true - ) - - exec[:subscribe] = files.collect { |f| - Puppet::Resource::Reference.new(:file, f.name) - } - - catalog = Puppet::Resource::Catalog.new - catalog.add_resource(exec, *files) - - catalog.apply - FileTest.should be_exist(fname) - end - - # Make sure refreshing happens mid-transaction, rather than at the end. - it "should refresh resources as they're encountered rather than all at the end" do - file = tmpfile("something") - exec1 = Puppet::Type.type(:exec).new( - :title => "one", - :name => "echo one >> %s" % file, - :path => "/usr/bin:/bin" - ) - - exec2 = Puppet::Type.type(:exec).new( - :title => "two", - :name => "echo two >> %s" % file, - :path => "/usr/bin:/bin", + :path => ENV["PATH"], + :command => "touch %s" % file1, :refreshonly => true, - :subscribe => exec1 + :subscribe => Puppet::Resource.new(:file, path) + ) + exec2 = Puppet::Type.type(:exec).new( + :path => ENV["PATH"], + :command => "touch %s" % file2, + :refreshonly => true, + :subscribe => Puppet::Resource.new(:file, path) ) - exec3 = Puppet::Type.type(:exec).new( - :title => "three", - :name => "echo three >> %s" % file, + catalog = mk_catalog(file, exec1, exec2) + catalog.apply + FileTest.should be_exist(file1) + FileTest.should be_exist(file2) + end + + it "should not let one failed refresh result in other refreshes failing" do + path = tmpfile("path") + newfile = tmpfile("file") + file = Puppet::Type.type(:file).new( + :path => path, + :ensure => "file" + ) + exec1 = Puppet::Type.type(:exec).new( + :path => ENV["PATH"], + :command => "touch /this/cannot/possibly/exist", + :logoutput => true, + :refreshonly => true, + :subscribe => file, + :title => "one" + ) + exec2 = Puppet::Type.type(:exec).new( + :path => ENV["PATH"], + :command => "touch %s" % newfile, + :logoutput => true, + :refreshonly => true, + :subscribe => [file, exec1], + :title => "two" + ) + + exec1.stubs(:err) + + catalog = mk_catalog(file, exec1, exec2) + catalog.apply + FileTest.should be_exists(newfile) + end + + it "should still trigger skipped resources" do + catalog = mk_catalog() + catalog.add_resource(*Puppet::Type.type(:schedule).mkdefaultschedules) + + Puppet[:ignoreschedules] = false + file = Puppet::Type.type(:file).new( + :name => tmpfile("file"), + :ensure => "file", + :backup => false + ) + + fname = tmpfile("exec") + exec = Puppet::Type.type(:exec).new( + :name => "touch #{fname}", :path => "/usr/bin:/bin", - :require => exec2 + :schedule => "monthly", + :subscribe => Puppet::Resource.new("file", file.name) ) - execs = [exec1, exec2, exec3] - catalog = Puppet::Resource::Catalog.new - catalog.add_resource(exec1,exec2,exec3) + catalog.add_resource(file, exec) - trans = Puppet::Transaction.new(catalog) - execs.each { |e| catalog.should be_vertex(e) } - trans.prepare - execs.each { |e| catalog.should be_vertex(e) } - reverse = trans.relationship_graph.reversal - execs.each { |e| reverse.should be_vertex(e) } + # Run it once + catalog.apply + FileTest.should be_exists(fname) + + exec.should_not be_scheduled + + # Now remove it, so it can get created again + File.unlink(fname) + + file[:content] = "some content" catalog.apply + FileTest.should be_exists(fname) - FileTest.should be_exist(file) - File.read(file).should == "one\ntwo\nthree\n" + # Now remove it, so it can get created again + File.unlink(fname) + + # And tag our exec + exec.tag("testrun") + + # And our file, so it runs + file.tag("norun") + + Puppet[:tags] = "norun" + + file[:content] = "totally different content" + + catalog.apply + FileTest.should be_exists(fname) + end + + it "should not attempt to evaluate resources with failed dependencies" do + exec = Puppet::Type.type(:exec).new( + :command => "/bin/mkdir /this/path/cannot/possibly/exit", + :title => "mkdir" + ) + + file1 = Puppet::Type.type(:file).new( + :title => "file1", + :path => tmpfile("file1"), + :require => exec, + :ensure => :file + ) + + file2 = Puppet::Type.type(:file).new( + :title => "file2", + :path => tmpfile("file2"), + :require => file1, + :ensure => :file + ) + + catalog = mk_catalog(exec, file1, file2) + catalog.apply + + FileTest.should_not be_exists(file1[:path]) + FileTest.should_not be_exists(file2[:path]) end end diff --git a/spec/unit/parser/ast/resource.rb b/spec/unit/parser/ast/resource.rb index 391f4c770..ef65f4ccd 100755 --- a/spec/unit/parser/ast/resource.rb +++ b/spec/unit/parser/ast/resource.rb @@ -7,7 +7,7 @@ describe Puppet::Parser::AST::Resource do before :each do @title = stub_everything 'title' - @compiler = stub_everything 'compiler' + @compiler = stub_everything 'compiler', :environment => Puppet::Node::Environment.new @scope = Puppet::Parser::Scope.new(:compiler => @compiler) @scope.stubs(:resource).returns(stub_everything) @resource = ast::Resource.new(:title => @title, :type => "Resource", :params => ast::ASTArray.new(:children => []) ) @@ -99,4 +99,38 @@ describe Puppet::Parser::AST::Resource do result[0].should be_virtual result[0].should be_exported end + + # Related to #806, make sure resources always look up the full path to the resource. + describe "when generating qualified resources" do + before do + @scope = Puppet::Parser::Scope.new :compiler => Puppet::Parser::Compiler.new(Puppet::Node.new("mynode")) + @parser = Puppet::Parser::Parser.new(Puppet::Node::Environment.new) + @parser.newdefine "one" + @parser.newdefine "one::two" + @parser.newdefine "three" + @twoscope = @scope.newscope(:namespace => "one") + @twoscope.resource = @scope.resource + end + + def resource(type, params = nil) + params ||= Puppet::Parser::AST::ASTArray.new(:children => []) + Puppet::Parser::AST::Resource.new(:type => type, :title => Puppet::Parser::AST::String.new(:value => "myresource"), :params => params) + end + + it "should be able to generate resources with fully qualified type information" do + resource("two").evaluate(@twoscope)[0].type.should == "One::Two" + end + + it "should be able to generate resources with unqualified type information" do + resource("one").evaluate(@twoscope)[0].type.should == "One" + end + + it "should correctly generate resources that can look up builtin types" do + resource("file").evaluate(@twoscope)[0].type.should == "File" + end + + it "should fail for resource types that do not exist" do + lambda { resource("nosuchtype").evaluate(@twoscope) }.should raise_error(Puppet::ParseError) + end + end end diff --git a/spec/unit/parser/collector.rb b/spec/unit/parser/collector.rb index 9c2d722e5..78d47c63f 100755 --- a/spec/unit/parser/collector.rb +++ b/spec/unit/parser/collector.rb @@ -174,7 +174,7 @@ describe Puppet::Parser::Collector, "when collecting virtual and catalog resourc @collector.evaluate.should == [one] end - it "should create a resource with overriden parameters" do + it "should create a resource with overridden parameters" do one = stub_everything 'one', :type => "Mytype", :virtual? => true, :title => "test" param = stub 'param' @compiler.stubs(:add_override) @@ -182,7 +182,7 @@ describe Puppet::Parser::Collector, "when collecting virtual and catalog resourc @compiler.expects(:resources).returns([one]) @collector.add_override(:params => param ) - Puppet::Parser::Resource.expects(:new).with { |h| + Puppet::Parser::Resource.expects(:new).with { |type, title, h| h[:params] == param } @@ -214,7 +214,7 @@ describe Puppet::Parser::Collector, "when collecting virtual and catalog resourc @compiler.expects(:resources).at_least(2).returns([one]) @collector.add_override(:params => param ) - Puppet::Parser::Resource.expects(:new).once.with { |h| + Puppet::Parser::Resource.expects(:new).once.with { |type, title, h| h[:params] == param } @@ -375,7 +375,7 @@ describe Puppet::Parser::Collector, "when collecting exported resources" do @compiler.stubs(:add_resource) @collector.add_override(:params => param ) - Puppet::Parser::Resource.expects(:new).once.with { |h| + Puppet::Parser::Resource.expects(:new).once.with { |type, title, h| h[:params] == param } diff --git a/spec/unit/parser/resource.rb b/spec/unit/parser/resource.rb index 0c70c817e..ee0c1e089 100755 --- a/spec/unit/parser/resource.rb +++ b/spec/unit/parser/resource.rb @@ -16,12 +16,8 @@ describe Puppet::Parser::Resource do end def mkresource(args = {}) - args[:source] ||= "source" - args[:scope] ||= stub('scope', :source => mock('source')) - - {:source => "source", :scope => "scope"}.each do |param, value| - args[param] ||= value - end + args[:source] ||= @source + args[:scope] ||= @scope params = args[:params] || {:one => "yay", :three => "rah"} if args[:params] == :none @@ -101,18 +97,18 @@ describe Puppet::Parser::Resource do end it "should be able to use the indexing operator to access parameters" do - resource = Puppet::Parser::Resource.new("resource", "testing", :source => "source", :scope => "scope") + resource = Puppet::Parser::Resource.new("resource", "testing", :source => "source", :scope => @scope) resource["foo"] = "bar" resource["foo"].should == "bar" end it "should return the title when asked for a parameter named 'title'" do - Puppet::Parser::Resource.new("resource", "testing", :source => "source", :scope => "scope")[:title].should == "testing" + Puppet::Parser::Resource.new("resource", "testing", :source => @source, :scope => @scope)[:title].should == "testing" end describe "when initializing" do before do - @arguments = {:scope => stub('scope', :source => mock('source'))} + @arguments = {:scope => @scope} end it "should fail unless #{name.to_s} is specified" do @@ -132,17 +128,6 @@ describe Puppet::Parser::Resource do end end - describe "when refering to a resource with name canonicalization" do - before do - @arguments = {:scope => stub('scope', :source => mock('source'))} - end - - it "should canonicalize its own name" do - res = Puppet::Parser::Resource.new("file", "/path/", @arguments) - res.ref.should == "File[/path]" - end - end - describe "when evaluating" do it "should evaluate the associated AST definition" do definition = newdefine "mydefine" @@ -294,7 +279,7 @@ describe Puppet::Parser::Resource do describe "when being tagged" do before do @scope_resource = stub 'scope_resource', :tags => %w{srone srtwo} - @scope = stub 'scope', :resource => @scope_resource + @scope.stubs(:resource).returns @scope_resource @resource = Puppet::Parser::Resource.new("file", "yay", :scope => @scope, :source => mock('source')) end @@ -448,8 +433,7 @@ describe Puppet::Parser::Resource do describe "when being converted to a resource" do before do - @source = stub 'scope', :name => "myscope" - @parser_resource = mkresource :source => @source, :params => {:foo => "bar", :fee => "fum"} + @parser_resource = mkresource :scope => @scope, :params => {:foo => "bar", :fee => "fum"} end it "should create an instance of Puppet::Resource" do @@ -537,7 +521,7 @@ describe Puppet::Parser::Resource do describe "when validating" do it "should check each parameter" do - resource = Puppet::Parser::Resource.new :foo, "bar", :scope => stub("scope"), :source => stub("source") + resource = Puppet::Parser::Resource.new :foo, "bar", :scope => @scope, :source => stub("source") resource[:one] = :two resource[:three] = :four resource.expects(:validate_parameter).with(:one) @@ -546,7 +530,7 @@ describe Puppet::Parser::Resource do end it "should raise a parse error when there's a failure" do - resource = Puppet::Parser::Resource.new :foo, "bar", :scope => stub("scope"), :source => stub("source") + resource = Puppet::Parser::Resource.new :foo, "bar", :scope => @scope, :source => stub("source") resource[:one] = :two resource.expects(:validate_parameter).with(:one).raises ArgumentError lambda { resource.send(:validate) }.should raise_error(Puppet::ParseError) @@ -556,7 +540,7 @@ describe Puppet::Parser::Resource do describe "when setting parameters" do before do @source = newclass "foobar" - @resource = Puppet::Parser::Resource.new :foo, "bar", :scope => stub("scope"), :source => @source + @resource = Puppet::Parser::Resource.new :foo, "bar", :scope => @scope, :source => @source end it "should accept Param instances and add them to the parameter list" do diff --git a/spec/unit/resource.rb b/spec/unit/resource.rb index c97cd634f..834a5b078 100755 --- a/spec/unit/resource.rb +++ b/spec/unit/resource.rb @@ -160,6 +160,21 @@ describe Puppet::Resource do resource.resource_type.should equal(type) end + it "should use its namespaces to set its type name when looking up defined resource types" do + type = Puppet::Resource::Type.new(:definition, "foo::bar") + Puppet::Node::Environment.new.known_resource_types.add type + resource = Puppet::Resource.new("bar", "/my/file", :namespaces => ["foo"]) + resource.type.should == "Foo::Bar" + end + + it "should look up its resource type when set manually" do + type = Puppet::Resource::Type.new(:definition, "foo::bar") + Puppet::Node::Environment.new.known_resource_types.add type + resource = Puppet::Resource.new("foo", "/my/file", :namespaces => ["foo"]) + resource.type = "bar" + resource.type.should == "Foo::Bar" + end + it "should use its namespaces when looking up host classes" do resource = Puppet::Resource.new("class", "bar", :namespaces => ["foo"]) type = Puppet::Resource::Type.new(:hostclass, "foo::bar") @@ -168,6 +183,13 @@ describe Puppet::Resource do resource.resource_type.should equal(type) end + it "should consider a class whose name is an empty string to be the main class" do + type = Puppet::Resource::Type.new(:hostclass, "") + Puppet::Node::Environment.new.known_resource_types.add type + + resource = Puppet::Resource.new("class", "").type.should == :main + end + it "should return nil when looking up resource types that don't exist" do Puppet::Resource.new("foobar", "bar").resource_type.should be_nil end @@ -217,6 +239,17 @@ describe Puppet::Resource do Puppet::Resource.new("file", "/foo").should_not == Puppet::Resource.new("file", "/f") end + describe "when refering to a resource with name canonicalization" do + before do + end + + it "should canonicalize its own name" do + res = Puppet::Resource.new("file", "/path/") + res.title.should == "/path" + res.ref.should == "File[/path]" + end + end + describe "when managing parameters" do before do @resource = Puppet::Resource.new("file", "/my/file") diff --git a/spec/unit/type/resources.rb b/spec/unit/type/resources.rb index 480b6c00d..3e65aec14 100644 --- a/spec/unit/type/resources.rb +++ b/spec/unit/type/resources.rb @@ -52,6 +52,19 @@ describe resources do @resources.generate.collect { |r| r.ref }.should_not include(@host1.ref) end + it "should not include the skipped users" do + res = Puppet::Type.type(:resources).new :name => :user, :purge => true + res.catalog = Puppet::Resource::Catalog.new + + users = [ + Puppet::Type.type(:user).new(:name => "root") + ] + Puppet::Type.type(:user).expects(:instances).returns users + list = res.generate + + names = list.collect { |r| r[:name] } + names.should_not be_include("root") + end describe "when generating a purgeable resource" do it "should be included in the generated resources" do diff --git a/test/language/ast.rb b/test/language/ast.rb index 209bc9863..916c34d45 100755 --- a/test/language/ast.rb +++ b/test/language/ast.rb @@ -56,7 +56,7 @@ class TestAST < Test::Unit::TestCase ref = resourceoverride("file", "/yayness", "owner" => "blah", "group" => "boo") end - Puppet::Parser::Resource.expects(:new).with { |o| o.is_a?(Hash) }.returns(:override) + Puppet::Parser::Resource.expects(:new).with { |type, title, o| o.is_a?(Hash) }.returns(:override) scope.compiler.expects(:add_override).with(:override) ret = nil assert_nothing_raised do diff --git a/test/language/ast/resource.rb b/test/language/ast/resource.rb deleted file mode 100755 index 4124655ca..000000000 --- a/test/language/ast/resource.rb +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env ruby -# -# Created by Luke A. Kanies on 2007-07-8. -# Copyright (c) 2007. All rights reserved. - -require File.dirname(__FILE__) + '/../../lib/puppettest' - -require 'puppettest' -require 'puppettest/parsertesting' - -class TestASTResource< Test::Unit::TestCase - include PuppetTest - include PuppetTest::ParserTesting - AST = Puppet::Parser::AST - - def setup - super - @scope = mkscope - @parser = @scope.compiler.parser - end - - def newdef(type, title, params = nil) - params ||= AST::ASTArray.new(:children => []) - AST::Resource.new(:type => type, :title => AST::String.new(:value => title), :params => params) - end - - # Related to #806, make sure resources always look up the full path to the resource. - def test_scoped_types - @parser.newdefine "one" - @parser.newdefine "one::two" - @parser.newdefine "three" - twoscope = @scope.newscope(:namespace => "one") - twoscope.resource = @scope.resource - assert(twoscope.find_definition("two"), "Could not find 'two' definition") - title = "title" - - # First try a qualified type - assert_equal("One::Two", newdef("two", title).evaluate(twoscope)[0].type, - "Defined type was not made fully qualified") - - # Then try a type that does not need to be qualified - assert_equal("One", newdef("one", title).evaluate(twoscope)[0].type, - "Unqualified defined type was not handled correctly") - - # Then an unqualified type from within the one namespace - assert_equal("Three", newdef("three", title).evaluate(twoscope)[0].type, - "Defined type was not made fully qualified") - - # Then a builtin type - assert_equal("File", newdef("file", title).evaluate(twoscope)[0].type, - "Builtin type was not handled correctly") - - # Now try a type that does not exist, which should throw an error. - assert_raise(Puppet::ParseError, "Did not fail on a missing type in a resource reference") do - newdef("nosuchtype", title).evaluate(twoscope) - end - end -end diff --git a/test/language/ast/resource_reference.rb b/test/language/ast/resource_reference.rb index 325dd2118..5abb0d6e5 100755 --- a/test/language/ast/resource_reference.rb +++ b/test/language/ast/resource_reference.rb @@ -20,7 +20,7 @@ class TestASTResourceReference < Test::Unit::TestCase def setup super @scope = mkscope - @parser = @scope.compiler.parser + @parser = Puppet::Parser::Parser.new(Puppet::Node::Environment.new) end # Related to #706, make sure resource references correctly translate to qualified types. diff --git a/test/language/ast/variable.rb b/test/language/ast/variable.rb index 49b1dbbc2..6a8b028bd 100755 --- a/test/language/ast/variable.rb +++ b/test/language/ast/variable.rb @@ -15,8 +15,7 @@ class TestVariable < Test::Unit::TestCase def setup super - @interp = mkinterp - @scope = mkscope :interp => @interp + @scope = mkscope @name = "myvar" @var = AST::Variable.new(:value => @name) end diff --git a/test/language/snippets.rb b/test/language/snippets.rb index bd0d34872..6aa202640 100755 --- a/test/language/snippets.rb +++ b/test/language/snippets.rb @@ -74,10 +74,6 @@ class TestSnippets < Test::Unit::TestCase end def ast2scope(ast) - interp = Puppet::Parser::Interpreter.new( - :ast => ast, - :client => client() - ) scope = Puppet::Parser::Scope.new() ast.evaluate(scope) diff --git a/test/lib/puppettest.rb b/test/lib/puppettest.rb index 786c37074..32f57f394 100755 --- a/test/lib/puppettest.rb +++ b/test/lib/puppettest.rb @@ -226,6 +226,9 @@ module PuppetTest Puppet[:ignoreschedules] = true #@start = Time.now + + #Facter.stubs(:value).returns "stubbed_value" + #Facter.stubs(:to_hash).returns({}) end def tempfile diff --git a/test/other/provider.rb b/test/other/provider.rb index b0860f634..e746a330a 100755 --- a/test/other/provider.rb +++ b/test/other/provider.rb @@ -33,21 +33,6 @@ class TestImpl < Test::Unit::TestCase return provider end - # Just a quick run-through to see if the basics work - def test_newprovider - assert_nothing_raised do - @provider.confine :operatingsystem => Facter["operatingsystem"].value - @provider.defaultfor :operatingsystem => Facter["operatingsystem"].value - end - - assert(@provider.suitable?, "Implementation was not considered suitable") - assert(@provider.default?, "Implementation was not considered a default") - - assert_equal(@provider, @type.defaultprovider, - "Did not correctly find default provider") - - end - def test_provider_default nondef = nil assert_nothing_raised { diff --git a/test/other/report.rb b/test/other/report.rb index 692ed54b6..147a0eae7 100755 --- a/test/other/report.rb +++ b/test/other/report.rb @@ -32,7 +32,10 @@ class TestReports < Test::Unit::TestCase config.retrieval_duration = 0.001 trans = config.apply - return trans.generate_report + report = Puppet::Transaction::Report.new + trans.add_metrics_to_report(report) + + return report end # Make sure we can use reports as log destinations. @@ -224,10 +227,7 @@ class TestReports < Test::Unit::TestCase def test_summary report = mkreport - summary = nil - assert_nothing_raised("Could not create report summary") do - summary = report.summary - end + summary = report.summary %w{Changes Total Resources}.each do |main| assert(summary.include?(main), "Summary did not include info for %s" % main) diff --git a/test/other/transactions.rb b/test/other/transactions.rb index 6f4f5d913..9a3afbd7a 100755 --- a/test/other/transactions.rb +++ b/test/other/transactions.rb @@ -118,319 +118,6 @@ class TestTransactions < Test::Unit::TestCase assert_equal({inst.title => inst}, $prefetched, "evaluate did not call prefetch") end - def test_refreshes_generate_events - path = tempfile() - firstpath = tempfile() - secondpath = tempfile() - file = Puppet::Type.type(:file).new(:title => "file", :path => path, :content => "yayness") - first = Puppet::Type.type(:exec).new(:title => "first", - :command => "/bin/echo first > #{firstpath}", - :subscribe => Puppet::Resource.new(:file, path), - :refreshonly => true - ) - second = Puppet::Type.type(:exec).new(:title => "second", - :command => "/bin/echo second > #{secondpath}", - :subscribe => Puppet::Resource.new(:exec, "first"), - :refreshonly => true - ) - - assert_apply(file, first, second) - - assert(FileTest.exists?(secondpath), "Refresh did not generate an event") - end - - unless %x{groups}.chomp.split(/ /).length > 1 - $stderr.puts "You must be a member of more than one group to test transactions" - else - def ingroup(gid) - require 'etc' - begin - group = Etc.getgrgid(gid) - rescue => detail - puts "Could not retrieve info for group %s: %s" % [gid, detail] - return nil - end - - return @groups.include?(group.name) - end - - def setup - super - @groups = %x{groups}.chomp.split(/ /) - unless @groups.length > 1 - p @groups - raise "You must be a member of more than one group to test this" - end - end - - def newfile(hash = {}) - tmpfile = tempfile() - File.open(tmpfile, "w") { |f| f.puts rand(100) } - - # XXX now, because os x apparently somehow allows me to make a file - # owned by a group i'm not a member of, i have to verify that - # the file i just created is owned by one of my groups - # grrr - unless ingroup(File.stat(tmpfile).gid) - Puppet.info "Somehow created file in non-member group %s; fixing" % - File.stat(tmpfile).gid - - require 'etc' - firstgr = @groups[0] - unless firstgr.is_a?(Integer) - str = Etc.getgrnam(firstgr) - firstgr = str.gid - end - File.chown(nil, firstgr, tmpfile) - end - - hash[:name] = tmpfile - assert_nothing_raised() { - return Puppet::Type.type(:file).new(hash) - } - end - - def newexec(file) - assert_nothing_raised() { - return Puppet::Type.type(:exec).new( - :name => "touch %s" % file, - :path => "/bin:/usr/bin:/sbin:/usr/sbin", - :returns => 0 - ) - } - end - - # test that services are correctly restarted and that work is done - # in the right order - def test_refreshing - transaction = nil - file = newfile() - execfile = File.join(tmpdir(), "exectestingness") - exec = newexec(execfile) - properties = {} - check = [:group,:mode] - file[:check] = check - file[:group] = @groups[0] - - config = mk_catalog(file) - config.apply - - @@tmpfiles << execfile - - # 'subscribe' expects an array of arrays - exec[:subscribe] = Puppet::Resource.new(file.class.name,file.name) - exec[:refreshonly] = true - - assert_nothing_raised() { - file.retrieve - exec.retrieve - } - - check.each { |property| - properties[property] = file.value(property) - } - assert_nothing_raised() { - file[:mode] = "755" - } - - # Make a new catalog so the resource relationships get - # set up. - config = mk_catalog(file, exec) - - trans = assert_events([:mode_changed, :restarted], config) - - assert(FileTest.exists?(execfile), "Execfile does not exist") - File.unlink(execfile) - assert_nothing_raised() { - file[:group] = @groups[1] - } - - trans = assert_events([:group_changed, :restarted], config) - assert(FileTest.exists?(execfile), "Execfile does not exist") - end - - # Verify that one component requiring another causes the contained - # resources in the requiring component to get refreshed. - def test_refresh_across_two_components - transaction = nil - file = newfile() - execfile = File.join(tmpdir(), "exectestingness2") - @@tmpfiles << execfile - exec = newexec(execfile) - properties = {} - check = [:group,:mode] - file[:check] = check - file[:group] = @groups[0] - assert_apply(file) - - config = Puppet::Resource::Catalog.new - fcomp = Puppet::Type.type(:component).new(:name => "file") - config.add_resource fcomp - config.add_resource file - config.add_edge(fcomp, file) - - ecomp = Puppet::Type.type(:component).new(:name => "exec") - config.add_resource ecomp - config.add_resource exec - config.add_edge(ecomp, exec) - - # 'subscribe' expects an array of arrays - #component[:require] = [[file.class.name,file.name]] - ecomp[:subscribe] = fcomp.ref - exec[:refreshonly] = true - - trans = assert_events([], config) - - assert_nothing_raised() { - file[:group] = @groups[1] - file[:mode] = "755" - } - - trans = assert_events([:group_changed, :mode_changed, :restarted], config) - end - - # Make sure that multiple subscriptions get triggered. - def test_multisubs - path = tempfile() - file1 = tempfile() - file2 = tempfile() - file = Puppet::Type.type(:file).new( - :path => path, - :ensure => "file" - ) - exec1 = Puppet::Type.type(:exec).new( - :path => ENV["PATH"], - :command => "touch %s" % file1, - :refreshonly => true, - :subscribe => Puppet::Resource.new(:file, path) - ) - exec2 = Puppet::Type.type(:exec).new( - :path => ENV["PATH"], - :command => "touch %s" % file2, - :refreshonly => true, - :subscribe => Puppet::Resource.new(:file, path) - ) - - assert_apply(file, exec1, exec2) - assert(FileTest.exists?(file1), "File 1 did not get created") - assert(FileTest.exists?(file2), "File 2 did not get created") - end - - # Make sure that a failed trigger doesn't result in other events not - # getting triggered. - def test_failedrefreshes - path = tempfile() - newfile = tempfile() - file = Puppet::Type.type(:file).new( - :path => path, - :ensure => "file" - ) - exec1 = Puppet::Type.type(:exec).new( - :path => ENV["PATH"], - :command => "touch /this/cannot/possibly/exist", - :logoutput => true, - :refreshonly => true, - :subscribe => file, - :title => "one" - ) - exec2 = Puppet::Type.type(:exec).new( - :path => ENV["PATH"], - :command => "touch %s" % newfile, - :logoutput => true, - :refreshonly => true, - :subscribe => [file, exec1], - :title => "two" - ) - - assert_apply(file, exec1, exec2) - assert(FileTest.exists?(newfile), "Refresh file did not get created") - end - - # Make sure that unscheduled and untagged objects still respond to events - def test_unscheduled_and_untagged_response - Puppet::Type.type(:schedule).mkdefaultschedules - Puppet[:ignoreschedules] = false - file = Puppet::Type.type(:file).new( - :name => tempfile(), - :ensure => "file", - :backup => false - ) - - fname = tempfile() - exec = Puppet::Type.type(:exec).new( - :name => "touch %s" % fname, - :path => "/usr/bin:/bin", - :schedule => "monthly", - :subscribe => Puppet::Resource.new("file", file.name) - ) - - config = mk_catalog(file, exec) - - # Run it once - assert_apply(config) - assert(FileTest.exists?(fname), "File did not get created") - - assert(!exec.scheduled?, "Exec is somehow scheduled") - - # Now remove it, so it can get created again - File.unlink(fname) - - file[:content] = "some content" - - assert_events([:content_changed, :restarted], config) - - assert(FileTest.exists?(fname), "File did not get recreated") - - # Now remove it, so it can get created again - File.unlink(fname) - - # And tag our exec - exec.tag("testrun") - - # And our file, so it runs - file.tag("norun") - - Puppet[:tags] = "norun" - - file[:content] = "totally different content" - - assert(! file.insync?(file.retrieve), "Uh, file is in sync?") - - assert_events([:content_changed, :restarted], config) - assert(FileTest.exists?(fname), "File did not get recreated") - end - - def test_failed_reqs_mean_no_run - exec = Puppet::Type.type(:exec).new( - :command => "/bin/mkdir /this/path/cannot/possibly/exit", - :title => "mkdir" - ) - - file1 = Puppet::Type.type(:file).new( - :title => "file1", - :path => tempfile(), - :require => exec, - :ensure => :file - ) - - file2 = Puppet::Type.type(:file).new( - :title => "file2", - :path => tempfile(), - :require => file1, - :ensure => :file - ) - - config = mk_catalog(exec, file1, file2) - - assert_apply(config) - - assert(! FileTest.exists?(file1[:path]), - "File got created even tho its dependency failed") - assert(! FileTest.exists?(file2[:path]), - "File got created even tho its deep dependency failed") - end - end - # We need to generate resources before we prefetch them, else generated # resources that require prefetching don't work. def test_generate_before_prefetch @@ -612,13 +299,7 @@ class TestTransactions < Test::Unit::TestCase def test_explicit_dependencies_beat_automatic # Create a couple of different resource sets that have automatic relationships and make sure the manual relationships win rels = {} - # First users and groups - group = Puppet::Type.type(:group).new(:name => nonrootgroup.name, :ensure => :present) - user = Puppet::Type.type(:user).new(:name => nonrootuser.name, :ensure => :present, :gid => group.title) - # Now add the explicit relationship - group[:require] = user - rels[group] = user # Now files d = tempfile() f = File.join(d, "file") diff --git a/test/ral/type/host.rb b/test/ral/type/host.rb index c99beb9a3..308e84bc0 100755 --- a/test/ral/type/host.rb +++ b/test/ral/type/host.rb @@ -108,17 +108,6 @@ class TestHost < Test::Unit::TestCase # This was a hard bug to track down. assert_instance_of(String, current_values[host.property(:ip)]) - host[:host_aliases] = %w{madstop kirby yayness} - - assert_events([:host_aliases_changed], host) - - assert_nothing_raised { - current_values = host.retrieve - } - - assert_equal(%w{madstop kirby yayness}, - current_values[host.property(:host_aliases)]) - host[:ensure] = :absent assert_events([:host_removed], host) end @@ -182,28 +171,4 @@ class TestHost < Test::Unit::TestCase host[:name] = "y" } end - - def test_aliasisproperty - assert_equal(:property, @hosttype.attrtype(:host_aliases)) - end - - def test_multivalues - host = mkhost - assert_raise(Puppet::Error) { - host[:host_aliases] = "puppetmasterd yayness" - } - end - - def test_puppetalias - host = mkhost() - catalog = mk_catalog(host) - - assert_nothing_raised { - host[:alias] = "testing" - } - - same = catalog.resource(:host, "testing") - assert(same, "Could not retrieve by alias") - end end - diff --git a/test/ral/type/resources.rb b/test/ral/type/resources.rb index 1bfc9d358..adc75cb71 100755 --- a/test/ral/type/resources.rb +++ b/test/ral/type/resources.rb @@ -59,6 +59,71 @@ class TestResources < Test::Unit::TestCase @type = Puppet::Type.type(:resources) end + def test_purge + # Create a purgeable type + mkpurgertype + + purger = nil + assert_nothing_raised do + purger = @type.new :name => "purgetest", :noop => true, :loglevel => :warning + end + purger.catalog = Puppet::Resource::Catalog.new + assert(purger, "did not get purger manager") + add_purge_lister() + + assert_equal($purgemembers.values.sort, @purgetype.instances.sort) + + # and it should now succeed + assert_nothing_raised do + purger[:purge] = true + end + assert(purger.purge?, "purge boolean was not enabled") + + # Okay, now let's try doing some purging, yo + managed = [] + unmanned = [] + 3.times { managed << mk_purger(true) } # 3 managed + 3.times { unmanned << mk_purger(false) } # 3 unmanaged + + managed.each do |m| + assert(m.managed?, "managed resource was not considered managed") + end + unmanned.each do |u| + assert(! u.managed?, "unmanaged resource was considered managed") + end + + # First make sure we get nothing back when purge is false + genned = nil + purger[:purge] = false + assert_nothing_raised do + genned = purger.generate + end + assert_equal([], genned, "Purged even when purge is false") + + # Now make sure we can purge + purger[:purge] = true + assert_nothing_raised do + genned = purger.generate + end + assert(genned, "Did not get any generated resources") + + genned.each do |res| + assert(res.purging, "did not mark resource for purging") + end + assert(! genned.empty?, "generated resource list was empty") + + # Now make sure the generate method only finds the unmanaged resources + assert_equal(unmanned.collect { |r| r.title }.sort, genned.collect { |r| r.title }, + "Did not return correct purge list") + + # Now make sure our metaparams carried over + genned.each do |res| + [:noop, :loglevel].each do |param| + assert_equal(purger[param], res[param], "metaparam %s did not carry over" % param) + end + end + end + # Part of #408. def test_check # First check a non-user @@ -108,6 +173,5 @@ class TestResources < Test::Unit::TestCase assert(res.check(@user.create(:name => high)), "high user %s failed check" % high) end end - end diff --git a/test/ral/type/sshkey.rb b/test/ral/type/sshkey.rb index b528317a3..b68c14b34 100755 --- a/test/ral/type/sshkey.rb +++ b/test/ral/type/sshkey.rb @@ -98,47 +98,6 @@ class TestSSHKey < Test::Unit::TestCase end - def test_moddingkey - key = mkkey() - - @catalog.apply - - key.retrieve - - aliases = %w{madstop kirby yayness} - key[:alias] = aliases - - @catalog.apply - - aliases.each do |name| - assert_equal(key.object_id, @catalog.resource(:sshkey, name).object_id, "alias %s was not set" % name) - end - end - - def test_aliasisproperty - assert_equal(:property, @sshkeytype.attrtype(:host_aliases)) - end - - def test_multivalues - key = mkkey - assert_raise(Puppet::Error) { - key[:host_aliases] = "puppetmasterd yayness" - } - end - - def test_puppetalias - key = mkkey() - - assert_nothing_raised { - key[:alias] = "testing" - } - - key.finish - - same = @catalog.resource(:sshkey, "testing") - assert(same, "Could not retrieve by alias") - end - def test_removal sshkey = mkkey() assert_nothing_raised { diff --git a/test/util/settings.rb b/test/util/settings.rb index 1e8eb4864..a080ca03b 100755 --- a/test/util/settings.rb +++ b/test/util/settings.rb @@ -78,10 +78,8 @@ class TestSettings < Test::Unit::TestCase end def mkconfig - c = nil - assert_nothing_raised { - c = Puppet::Util::Settings.new - } + c = Puppet::Util::Settings.new + c.setdefaults :main, :noop => [false, "foo"] return c end @@ -303,6 +301,8 @@ yay = /a/path end def test_addargs_functional + @config = Puppet::Util::Settings.new + @config.setdefaults("testing", :onboolean => [true, "An on bool"], :string => ["a string", "A string arg"] @@ -666,15 +666,15 @@ yay = /a/path end # Test to make sure that we can set and get a short name - def test_celement_short_name - element = nil - assert_nothing_raised("Could not create celement") do - element = Setting.new :short => "n", :desc => "anything", :settings => Puppet::Util::Settings.new + def test_setting_short_name + setting= nil + assert_nothing_raised("Could not create setting") do + setting= Setting.new :short => "n", :desc => "anything", :settings => Puppet::Util::Settings.new end - assert_equal("n", element.short, "Short value is not retained") + assert_equal("n", setting.short, "Short value is not retained") assert_raise(ArgumentError,"Allowed multicharactered short names.") do - element = Setting.new :short => "no", :desc => "anything", :settings => Puppet::Util::Settings.new + setting= Setting.new :short => "no", :desc => "anything", :settings => Puppet::Util::Settings.new end end