diff options
Diffstat (limited to 'spec')
43 files changed, 1409 insertions, 981 deletions
diff --git a/spec/integration/checksum.rb b/spec/integration/checksum.rb index cb187c656..c94f3e47e 100755 --- a/spec/integration/checksum.rb +++ b/spec/integration/checksum.rb @@ -38,7 +38,7 @@ describe Puppet::Checksum, " when using the file terminus" do File.stubs(:exist?).returns(true) File.expects(:unlink).with(@file) - Puppet::Checksum.destroy(@sum) + Puppet::Checksum.destroy(@sum.name) end after do diff --git a/spec/integration/indirector/direct_file_server.rb b/spec/integration/indirector/direct_file_server.rb index 383486986..40b753a6c 100755 --- a/spec/integration/indirector/direct_file_server.rb +++ b/spec/integration/indirector/direct_file_server.rb @@ -19,7 +19,7 @@ describe Puppet::Indirector::DirectFileServer, " when interacting with the files it "should return an instance of the model" do FileTest.expects(:exists?).with(@filepath).returns(true) - @terminus.find("file://host#{@filepath}").should be_instance_of(Puppet::FileServing::Content) + @terminus.find(@terminus.indirection.request(:find, "file://host#{@filepath}")).should be_instance_of(Puppet::FileServing::Content) end it "should return an instance capable of returning its content" do @@ -27,7 +27,7 @@ describe Puppet::Indirector::DirectFileServer, " when interacting with the files File.stubs(:lstat).with(@filepath).returns(stub("stat", :ftype => "file")) File.expects(:read).with(@filepath).returns("my content") - instance = @terminus.find("file://host#{@filepath}") + instance = @terminus.find(@terminus.indirection.request(:find, "file://host#{@filepath}")) instance.content.should == "my content" end @@ -50,10 +50,12 @@ describe Puppet::Indirector::DirectFileServer, " when interacting with FileServi end Dir.expects(:entries).with(@filepath).returns @subfiles + + @request = @terminus.indirection.request(:search, "file:///my/file", :recurse => true) end it "should return an instance for every file in the fileset" do - result = @terminus.search("file:///my/file", :recurse => true) + result = @terminus.search(@request) result.should be_instance_of(Array) result.length.should == 3 result.each { |r| r.should be_instance_of(Puppet::FileServing::Content) } @@ -65,7 +67,7 @@ describe Puppet::Indirector::DirectFileServer, " when interacting with FileServi File.expects(:read).with(File.join(@filepath, name)).returns("#{name} content") end - @terminus.search("file:///my/file", :recurse => true).each do |instance| + @terminus.search(@request).each do |instance| case instance.key when /one/: instance.content.should == "one content" when /two/: instance.content.should == "two content" diff --git a/spec/integration/node.rb b/spec/integration/node.rb index 631d4403e..b0375e743 100755 --- a/spec/integration/node.rb +++ b/spec/integration/node.rb @@ -7,38 +7,86 @@ require File.dirname(__FILE__) + '/../spec_helper' require 'puppet/node' -describe Puppet::Node, " when using the memory terminus" do - before do - @name = "me" - @old_terminus = Puppet::Node.indirection.terminus_class - @terminus = Puppet::Node.indirection.terminus(:memory) - Puppet::Node.indirection.stubs(:terminus).returns @terminus - @node = Puppet::Node.new(@name) - end +describe Puppet::Node do + describe "when delegating indirection calls" do + before do + @name = "me" + @node = Puppet::Node.new(@name) + end - it "should find no nodes by default" do - Puppet::Node.find(@name).should be_nil - end + it "should be able to use the exec terminus" do + Puppet::Node.indirection.stubs(:terminus_class).returns :exec - it "should be able to find nodes that were previously saved" do - @node.save - Puppet::Node.find(@name).should equal(@node) - end + # Load now so we can stub + terminus = Puppet::Node.indirection.terminus(:exec) - it "should replace existing saved nodes when a new node with the same name is saved" do - @node.save - two = Puppet::Node.new(@name) - two.save - Puppet::Node.find(@name).should equal(two) - end + terminus.expects(:query).with(@name).returns "myresults" + terminus.expects(:translate).with(@name, "myresults").returns "translated_results" + terminus.expects(:create_node).with(@name, "translated_results").returns @node - it "should be able to remove previously saved nodes" do - @node.save - Puppet::Node.destroy(@node) - Puppet::Node.find(@name).should be_nil - end + Puppet::Node.find(@name).should equal(@node) + end + + it "should be able to use the yaml terminus" do + Puppet::Node.indirection.stubs(:terminus_class).returns :yaml + + # Load now, before we stub the exists? method. + Puppet::Node.indirection.terminus(:yaml) + + file = File.join(Puppet[:yamldir], "node", "me.yaml") + FileTest.expects(:exist?).with(file).returns false + Puppet::Node.find(@name).should be_nil + end + + it "should have an ldap terminus" do + Puppet::Node.indirection.terminus(:ldap).should_not be_nil + end + + it "should be able to use the plain terminus" do + Puppet::Node.indirection.stubs(:terminus_class).returns :plain + + # Load now, before we stub the exists? method. + Puppet::Node.indirection.terminus(:plain) + + Puppet::Node.expects(:new).with(@name).returns @node + + Puppet::Node.find(@name).should equal(@node) + end + + describe "and using the memory terminus" do + before do + @name = "me" + @old_terminus = Puppet::Node.indirection.terminus_class + @terminus = Puppet::Node.indirection.terminus(:memory) + Puppet::Node.indirection.stubs(:terminus).returns @terminus + @node = Puppet::Node.new(@name) + end + + it "should find no nodes by default" do + Puppet::Node.find(@name).should be_nil + end + + it "should be able to find nodes that were previously saved" do + @node.save + Puppet::Node.find(@name).should equal(@node) + end + + it "should replace existing saved nodes when a new node with the same name is saved" do + @node.save + two = Puppet::Node.new(@name) + two.save + Puppet::Node.find(@name).should equal(two) + end + + it "should be able to remove previously saved nodes" do + @node.save + Puppet::Node.destroy(@node.name) + Puppet::Node.find(@name).should be_nil + end - it "should fail when asked to destroy a node that does not exist" do - proc { Puppet::Node.destroy(@node) }.should raise_error(ArgumentError) + it "should fail when asked to destroy a node that does not exist" do + proc { Puppet::Node.destroy(@node) }.should raise_error(ArgumentError) + end + end end end diff --git a/spec/integration/node/catalog.rb b/spec/integration/node/catalog.rb new file mode 100755 index 000000000..ca14c2ea8 --- /dev/null +++ b/spec/integration/node/catalog.rb @@ -0,0 +1,38 @@ +#!/usr/bin/env ruby +# +# Created by Luke Kanies on 2007-4-8. +# Copyright (c) 2008. All rights reserved. + +require File.dirname(__FILE__) + '/../../spec_helper' + +describe Puppet::Node::Catalog do + describe "when using the indirector" do + after { Puppet::Node::Catalog.indirection.clear_cache } + + it "should be able to delegate to the :yaml terminus" do + Puppet::Node::Catalog.indirection.stubs(:terminus_class).returns :yaml + + # Load now, before we stub the exists? method. + Puppet::Node::Catalog.indirection.terminus(:yaml) + + file = File.join(Puppet[:yamldir], "catalog", "me.yaml") + FileTest.expects(:exist?).with(file).returns false + Puppet::Node::Catalog.find("me").should be_nil + end + + it "should be able to delegate to the :compiler terminus" do + Puppet::Node::Catalog.indirection.stubs(:terminus_class).returns :compiler + + # Load now, before we stub the exists? method. + compiler = Puppet::Node::Catalog.indirection.terminus(:compiler) + + node = mock 'node' + node.stub_everything + + Puppet::Node.expects(:find).returns(node) + compiler.expects(:compile).with(node).returns nil + + Puppet::Node::Catalog.find("me").should be_nil + end + end +end diff --git a/spec/integration/node/facts.rb b/spec/integration/node/facts.rb new file mode 100755 index 000000000..c2f876578 --- /dev/null +++ b/spec/integration/node/facts.rb @@ -0,0 +1,45 @@ +#!/usr/bin/env ruby +# +# Created by Luke Kanies on 2008-4-8. +# Copyright (c) 2008. All rights reserved. + +require File.dirname(__FILE__) + '/../../spec_helper' + +describe Puppet::Node::Facts do + describe "when using the indirector" do + after { Puppet::Node::Facts.indirection.clear_cache } + + it "should expire any cached node instances when it is saved" do + Puppet::Node::Facts.indirection.stubs(:terminus_class).returns :yaml + terminus = Puppet::Node::Facts.indirection.terminus(:yaml) + + terminus.expects(:save) + Puppet::Node.expects(:expire).with("me") + + facts = Puppet::Node::Facts.new("me") + facts.save + end + + it "should be able to delegate to the :yaml terminus" do + Puppet::Node::Facts.indirection.stubs(:terminus_class).returns :yaml + + # Load now, before we stub the exists? method. + Puppet::Node::Facts.indirection.terminus(:yaml) + + file = File.join(Puppet[:yamldir], "facts", "me.yaml") + FileTest.expects(:exist?).with(file).returns false + + Puppet::Node::Facts.find("me").should be_nil + end + + it "should be able to delegate to the :facter terminus" do + Puppet::Node::Facts.indirection.stubs(:terminus_class).returns :facter + + Facter.expects(:to_hash).returns "facter_hash" + facts = Puppet::Node::Facts.new("me") + Puppet::Node::Facts.expects(:new).with("me", "facter_hash").returns facts + + Puppet::Node::Facts.find("me").should equal(facts) + end + end +end diff --git a/spec/integration/transaction/report.rb b/spec/integration/transaction/report.rb new file mode 100755 index 000000000..48e59f203 --- /dev/null +++ b/spec/integration/transaction/report.rb @@ -0,0 +1,26 @@ +#!/usr/bin/env ruby +# +# Created by Luke Kanies on 2008-4-8. +# Copyright (c) 2008. All rights reserved. + +require File.dirname(__FILE__) + '/../../spec_helper' + +describe Puppet::Transaction::Report do + describe "when using the indirector" do + after { Puppet::Transaction::Report.indirection.clear_cache } + + it "should be able to delegate to the :processor terminus" do + Puppet::Transaction::Report.indirection.stubs(:terminus_class).returns :processor + + terminus = Puppet::Transaction::Report.indirection.terminus(:processor) + + Facter.stubs(:value).returns "host.domain.com" + + report = Puppet::Transaction::Report.new + + terminus.expects(:process).with(report) + + report.save + end + end +end diff --git a/spec/shared_behaviours/file_serving.rb b/spec/shared_behaviours/file_serving.rb index b5ab6b0fd..82f207243 100644 --- a/spec/shared_behaviours/file_serving.rb +++ b/spec/shared_behaviours/file_serving.rb @@ -6,7 +6,7 @@ describe "Puppet::FileServing::Files", :shared => true do it "should use the rest terminus when the 'puppet' URI scheme is used and a host name is present" do uri = "puppet://myhost/mymod/my/file" - @indirection.terminus(:rest).expects(:find).with(uri) + @indirection.terminus(:rest).expects(:find) @test_class.find(uri) end @@ -14,7 +14,7 @@ describe "Puppet::FileServing::Files", :shared => true do uri = "puppet:///mymod/my/file" Puppet.settings.stubs(:value).with(:name).returns("puppetd") Puppet.settings.stubs(:value).with(:modulepath).returns("") - @indirection.terminus(:rest).expects(:find).with(uri) + @indirection.terminus(:rest).expects(:find) @test_class.find(uri) end @@ -27,27 +27,27 @@ describe "Puppet::FileServing::Files", :shared => true do Puppet.settings.stubs(:value).with(:libdir).returns("") Puppet.settings.stubs(:value).with(:fileserverconfig).returns("/whatever") Puppet.settings.stubs(:value).with(:environment).returns("") - @indirection.terminus(:file_server).expects(:find).with(uri) + @indirection.terminus(:file_server).expects(:find) @indirection.terminus(:file_server).stubs(:authorized?).returns(true) @test_class.find(uri) end it "should use the file_server terminus when the 'puppetmounts' URI scheme is used" do uri = "puppetmounts:///mymod/my/file" - @indirection.terminus(:file_server).expects(:find).with(uri) + @indirection.terminus(:file_server).expects(:find) @indirection.terminus(:file_server).stubs(:authorized?).returns(true) @test_class.find(uri) end it "should use the file terminus when the 'file' URI scheme is used" do uri = "file:///mymod/my/file" - @indirection.terminus(:file).expects(:find).with(uri) + @indirection.terminus(:file).expects(:find) @test_class.find(uri) end it "should use the file terminus when a fully qualified path is provided" do uri = "/mymod/my/file" - @indirection.terminus(:file).expects(:find).with(uri) + @indirection.terminus(:file).expects(:find) @test_class.find(uri) end end diff --git a/spec/shared_behaviours/memory_terminus.rb b/spec/shared_behaviours/memory_terminus.rb new file mode 100644 index 000000000..a00dc9f74 --- /dev/null +++ b/spec/shared_behaviours/memory_terminus.rb @@ -0,0 +1,32 @@ +# +# Created by Luke Kanies on 2008-4-8. +# Copyright (c) 2008. All rights reserved. + +describe "A Memory Terminus", :shared => true do + it "should find no instances by default" do + @searcher.find(@request).should be_nil + end + + it "should be able to find instances that were previously saved" do + @searcher.save(@request) + @searcher.find(@request).should equal(@instance) + end + + it "should replace existing saved instances when a new instance with the same name is saved" do + @searcher.save(@request) + two = stub 'second', :name => @name + trequest = stub 'request', :key => @name, :instance => two + @searcher.save(trequest) + @searcher.find(@request).should equal(two) + end + + it "should be able to remove previously saved instances" do + @searcher.save(@request) + @searcher.destroy(@request) + @searcher.find(@request).should be_nil + end + + it "should fail when asked to destroy an instance that does not exist" do + proc { @searcher.destroy(@request) }.should raise_error(ArgumentError) + end +end diff --git a/spec/unit/file_serving/configuration.rb b/spec/unit/file_serving/configuration.rb index eecaefe5f..a0710e20d 100755 --- a/spec/unit/file_serving/configuration.rb +++ b/spec/unit/file_serving/configuration.rb @@ -221,4 +221,4 @@ describe Puppet::FileServing::Configuration do @config.authorized?("/one/my/file").should be_false end end -end
\ No newline at end of file +end diff --git a/spec/unit/file_serving/configuration/parser.rb b/spec/unit/file_serving/configuration/parser.rb index df2f629d5..93d30ca1c 100755 --- a/spec/unit/file_serving/configuration/parser.rb +++ b/spec/unit/file_serving/configuration/parser.rb @@ -132,4 +132,4 @@ describe Puppet::FileServing::Configuration::Parser do @parser.parse end end -end
\ No newline at end of file +end diff --git a/spec/unit/file_serving/indirection_hooks.rb b/spec/unit/file_serving/indirection_hooks.rb index 34614b7b8..160e3ff0a 100755 --- a/spec/unit/file_serving/indirection_hooks.rb +++ b/spec/unit/file_serving/indirection_hooks.rb @@ -7,104 +7,118 @@ require File.dirname(__FILE__) + '/../../spec_helper' require 'puppet/file_serving/indirection_hooks' -describe Puppet::FileServing::IndirectionHooks, " when being used to select termini" do +describe Puppet::FileServing::IndirectionHooks do before do @object = Object.new @object.extend(Puppet::FileServing::IndirectionHooks) - end - - it "should escape the key before parsing" do - uri = stub 'uri', :scheme => "puppet", :host => "blah", :path => "/something" - URI.expects(:escape).with("mykey").returns("http://myhost/blah") - URI.expects(:parse).with("http://myhost/blah").returns(uri) - @object.select_terminus("mykey") - end - - it "should use the URI class to parse the key" do - uri = stub 'uri', :scheme => "puppet", :host => "blah", :path => "/something" - URI.expects(:parse).with("http://myhost/blah").returns(uri) - @object.select_terminus("http://myhost/blah") - end - - it "should choose :rest when the protocol is 'puppet'" do - @object.select_terminus("puppet://host/module/file").should == :rest - end - - it "should choose :file_server when the protocol is 'puppetmounts' and the mount name is not 'modules'" do - modules = mock 'modules' - @object.stubs(:terminus).with(:modules).returns(modules) - modules.stubs(:find_module).returns(nil) - - @object.select_terminus("puppetmounts://host/notmodules/file").should == :file_server - end - - it "should choose :file_server when no server name is provided, the process name is 'puppet', and the mount name is not 'modules'" do - modules = mock 'modules' - @object.stubs(:terminus).with(:modules).returns(modules) - modules.stubs(:find_module).returns(nil) - - Puppet.settings.expects(:value).with(:name).returns("puppet") - @object.select_terminus("puppet:///notmodules/file").should == :file_server - end - - it "should choose :modules if it would normally choose :file_server but the mount name is 'modules'" do - @object.select_terminus("puppetmounts://host/modules/mymod/file").should == :modules - end - - it "should choose :modules it would normally choose :file_server but a module exists with the mount name" do - modules = mock 'modules' - - @object.expects(:terminus).with(:modules).returns(modules) - modules.expects(:find_module).with("mymod", nil).returns(:thing) - - @object.select_terminus("puppetmounts://host/mymod/file").should == :modules - end - - it "should choose :rest when no server name is provided and the process name is not 'puppet'" do - Puppet.settings.expects(:value).with(:name).returns("puppetd") - @object.select_terminus("puppet:///module/file").should == :rest - end - - it "should choose :file when the protocol is 'file'" do - @object.select_terminus("file://host/module/file").should == :file - end - - it "should choose :file when the URI is a normal path name" do - @object.select_terminus("/module/file").should == :file - end - - # This is so that we only choose modules over mounts, not file - it "should choose :file when the protocol is 'file' and the fully qualified path starts with '/modules'" do - @object.select_terminus("file://host/modules/file").should == :file - end - - it "should fail when a protocol other than :puppet, :file, or :puppetmounts is used" do - proc { @object.select_terminus("http:///module/file") }.should raise_error(ArgumentError) - end -end - -describe Puppet::FileServing::IndirectionHooks, " when looking for a module whose name matches the mount name" do - before do - @object = Object.new - @object.extend(Puppet::FileServing::IndirectionHooks) - - @modules = mock 'modules' - @object.stubs(:terminus).with(:modules).returns(@modules) - end - - it "should use the modules terminus to look up the module" do - @modules.expects(:find_module).with("mymod", nil) - @object.select_terminus("puppetmounts://host/mymod/my/file") - end - - it "should pass the node name to the modules terminus" do - @modules.expects(:find_module).with("mymod", nil) - @object.select_terminus("puppetmounts://host/mymod/my/file") - end - it "should log a deprecation warning if a module is found" do - @modules.expects(:find_module).with("mymod", nil).returns(:something) - Puppet.expects(:warning) - @object.select_terminus("puppetmounts://host/mymod/my/file") + @request = stub 'request', :key => "http://myhost/blah", :options => {:node => "whatever"} + end + + describe "when being used to select termini" do + it "should escape the key before parsing" do + uri = stub 'uri', :scheme => "puppet", :host => "blah", :path => "/something" + URI.expects(:escape).with("http://myhost/blah").returns("escaped_blah") + URI.expects(:parse).with("escaped_blah").returns(uri) + @object.select_terminus(@request) + end + + it "should use the URI class to parse the key" do + uri = stub 'uri', :scheme => "puppet", :host => "blah", :path => "/something" + URI.expects(:parse).with("http://myhost/blah").returns(uri) + @object.select_terminus @request + end + + it "should choose :rest when the protocol is 'puppet'" do + @request.stubs(:key).returns "puppet://host/module/file" + @object.select_terminus(@request).should == :rest + end + + it "should choose :file_server when the protocol is 'puppetmounts' and the mount name is not 'modules'" do + modules = mock 'modules' + @object.stubs(:terminus).with(:modules).returns(modules) + modules.stubs(:find_module).returns(nil) + + @request.stubs(:key).returns "puppetmounts://host/notmodules/file" + + @object.select_terminus(@request).should == :file_server + end + + it "should choose :file_server when no server name is provided, the process name is 'puppet', and the mount name is not 'modules'" do + modules = mock 'modules' + @object.stubs(:terminus).with(:modules).returns(modules) + modules.stubs(:find_module).returns(nil) + + Puppet.settings.expects(:value).with(:name).returns("puppet") + @request.stubs(:key).returns "puppet:///notmodules/file" + @object.select_terminus(@request).should == :file_server + end + + it "should choose :modules if it would normally choose :file_server but the mount name is 'modules'" do + @request.stubs(:key).returns "puppetmounts://host/modules/mymod/file" + @object.select_terminus(@request).should == :modules + end + + it "should choose :modules if it would normally choose :file_server but a module exists with the mount name" do + modules = mock 'modules' + + @object.expects(:terminus).with(:modules).returns(modules) + modules.expects(:find_module).with("mymod", @request.options[:node]).returns(:thing) + + @request.stubs(:key).returns "puppetmounts://host/mymod/file" + @object.select_terminus(@request).should == :modules + end + + it "should choose :rest when no server name is provided and the process name is not 'puppet'" do + Puppet.settings.expects(:value).with(:name).returns("puppetd") + @request.stubs(:key).returns "puppet:///module/file" + @object.select_terminus(@request).should == :rest + end + + it "should choose :file when the protocol is 'file'" do + @request.stubs(:key).returns "file://host/module/file" + @object.select_terminus(@request).should == :file + end + + it "should choose :file when the URI is a normal path name" do + @request.stubs(:key).returns "/module/file" + @object.select_terminus(@request).should == :file + end + + # This is so that we only choose modules over mounts, not file + it "should choose :file when the protocol is 'file' and the fully qualified path starts with '/modules'" do + @request.stubs(:key).returns "/module/file" + @object.select_terminus(@request).should == :file + end + + it "should fail when a protocol other than :puppet, :file, or :puppetmounts is used" do + @request.stubs(:key).returns "http:///module/file" + proc { @object.select_terminus(@request) }.should raise_error(ArgumentError) + end + end + + describe "when looking for a module whose name matches the mount name" do + before do + @modules = mock 'modules' + @object.stubs(:terminus).with(:modules).returns(@modules) + + @request.stubs(:key).returns "puppetmounts://host/mymod/file" + end + + it "should use the modules terminus to look up the module" do + @modules.expects(:find_module).with("mymod", @request.options[:node]) + @object.select_terminus @request + end + + it "should pass the node name to the modules terminus" do + @modules.expects(:find_module).with("mymod", @request.options[:node]) + @object.select_terminus @request + end + + it "should log a deprecation warning if a module is found" do + @modules.expects(:find_module).with("mymod", @request.options[:node]).returns(:something) + Puppet.expects(:warning) + @object.select_terminus @request + end end end diff --git a/spec/unit/indirector.rb b/spec/unit/indirector.rb index 1a5867c51..1efa7b2e5 100755 --- a/spec/unit/indirector.rb +++ b/spec/unit/indirector.rb @@ -21,6 +21,10 @@ describe Puppet::Indirector, "when registering an indirection" do before do @thingie = Class.new do extend Puppet::Indirector + attr_reader :name + def initialize(name) + @name = name + end end end @@ -55,48 +59,81 @@ describe Puppet::Indirector, "when registering an indirection" do end end -describe Puppet::Indirector, " when redirecting a model" do +describe "Delegated Indirection Method", :shared => true do + it "should delegate to the indirection" do + @indirection.expects(@method) + @thingie.send(@method, "me") + end + + it "should pass all of the passed arguments directly to the indirection instance" do + @indirection.expects(@method).with("me", :one => :two) + @thingie.send(@method, "me", :one => :two) + end + + it "should return the results of the delegation as its result" do + request = mock 'request' + @indirection.expects(@method).returns "yay" + @thingie.send(@method, "me").should == "yay" + end +end + +describe Puppet::Indirector, "when redirecting a model" do before do @thingie = Class.new do extend Puppet::Indirector + attr_reader :name + def initialize(name) + @name = name + end end @indirection = @thingie.send(:indirects, :test) end - it "should give the model the ability set a version" do - thing = @thingie.new - thing.should respond_to(:version=) + it "should include the Envelope module in the model" do + @thingie.ancestors.should be_include(Puppet::Indirector::Envelope) end - it "should give the model the ability retrieve a version" do - thing = @thingie.new - thing.should respond_to(:version) + describe "when finding instances via the model" do + before { @method = :find } + it_should_behave_like "Delegated Indirection Method" end - it "should give the model the ability to lookup a model instance by letting the indirection perform the lookup" do - @indirection.expects(:find) - @thingie.find + describe "when destroying instances via the model" do + before { @method = :destroy } + it_should_behave_like "Delegated Indirection Method" end - it "should give the model the ability to remove model instances from a terminus by letting the indirection remove the instance" do - @indirection.expects(:destroy) - @thingie.destroy + describe "when searching for instances via the model" do + before { @method = :search } + it_should_behave_like "Delegated Indirection Method" end - it "should give the model the ability to search for model instances by letting the indirection find the matching instances" do - @indirection.expects(:search) - @thingie.search + describe "when expiring instances via the model" do + before { @method = :expire } + it_should_behave_like "Delegated Indirection Method" end - it "should give the model the ability to store a model instance by letting the indirection store the instance" do - thing = @thingie.new - @indirection.expects(:save).with(thing) - thing.save - end + # This is an instance method, so it behaves a bit differently. + describe "when saving instances via the model" do + before do + @instance = @thingie.new("me") + end + + it "should delegate to the indirection" do + @indirection.expects(:save) + @instance.save + end - it "should give the model the ability to look up an instance's version by letting the indirection perform the lookup" do - @indirection.expects(:version).with(:thing) - @thingie.version(:thing) + it "should pass the instance and all arguments to the indirection's :save method" do + @indirection.expects(:save).with(@instance, :one => :two) + @instance.save :one => :two + end + + it "should return the results of the delegation as its result" do + request = mock 'request' + @indirection.expects(:save).returns "yay" + @instance.save.should == "yay" + end end it "should give the model the ability to set the indirection terminus class" do diff --git a/spec/unit/indirector/catalog/compiler.rb b/spec/unit/indirector/catalog/compiler.rb index a4a0acd58..083a9ced5 100755 --- a/spec/unit/indirector/catalog/compiler.rb +++ b/spec/unit/indirector/catalog/compiler.rb @@ -26,8 +26,8 @@ describe Puppet::Node::Catalog::Compiler do Puppet::Node.stubs(:find_by_any_name).with('node1').returns(node1) Puppet::Node.stubs(:find_by_any_name).with('node2').returns(node2) - compiler.find('node1') - compiler.find('node2') + compiler.find(stub('request', :key => 'node1', :options => {})) + compiler.find(stub('node2request', :key => 'node2', :options => {})) end it "should provide a method for determining if the catalog is networked" do @@ -63,19 +63,14 @@ describe Puppet::Node::Catalog::Compiler, " when finding nodes" do @compiler = Puppet::Node::Catalog::Compiler.new @name = "me" @node = mock 'node' + @request = stub 'request', :key => @name, :options => {} @compiler.stubs(:compile) end it "should look node information up via the Node class with the provided key" do @node.stubs :merge Puppet::Node.expects(:find_by_any_name).with(@name).returns(@node) - @compiler.find(@name) - end - - it "should fail if it cannot find the node" do - @node.stubs :merge - Puppet::Node.expects(:find_by_any_name).with(@name).returns(nil) - proc { @compiler.find(@name) }.should raise_error(Puppet::Error) + @compiler.find(@request) end end @@ -88,23 +83,24 @@ describe Puppet::Node::Catalog::Compiler, " after finding nodes" do @compiler = Puppet::Node::Catalog::Compiler.new @name = "me" @node = mock 'node' + @request = stub 'request', :key => @name, :options => {} @compiler.stubs(:compile) Puppet::Node.stubs(:find_by_any_name).with(@name).returns(@node) end it "should add the server's Puppet version to the node's parameters as 'serverversion'" do @node.expects(:merge).with { |args| args["serverversion"] == "1" } - @compiler.find(@name) + @compiler.find(@request) end it "should add the server's fqdn to the node's parameters as 'servername'" do @node.expects(:merge).with { |args| args["servername"] == "my.server.com" } - @compiler.find(@name) + @compiler.find(@request) end it "should add the server's IP address to the node's parameters as 'serverip'" do @node.expects(:merge).with { |args| args["serverip"] == "my.ip.address" } - @compiler.find(@name) + @compiler.find(@request) end # LAK:TODO This is going to be difficult, because this whole process is so @@ -125,27 +121,34 @@ describe Puppet::Node::Catalog::Compiler, " when creating catalogs" do @name = "me" @node = Puppet::Node.new @name @node.stubs(:merge) + @request = stub 'request', :key => @name, :options => {} Puppet::Node.stubs(:find_by_any_name).with(@name).returns(@node) end it "should directly use provided nodes" do Puppet::Node.expects(:find_by_any_name).never @compiler.interpreter.expects(:compile).with(@node) - @compiler.find(@node) + @request.stubs(:options).returns(:node => @node) + @compiler.find(@request) + end + + it "should fail if no node is passed and none can be found" do + Puppet::Node.stubs(:find_by_any_name).with(@name).returns(nil) + proc { @compiler.find(@request) }.should raise_error(ArgumentError) end it "should pass the found node to the interpreter for compiling" do config = mock 'config' @compiler.interpreter.expects(:compile).with(@node) - @compiler.find(@name) + @compiler.find(@request) end it "should return the results of compiling as the catalog" do config = mock 'config' - result = mock 'result', :to_transportable => :catalog + result = mock 'result' @compiler.interpreter.expects(:compile).with(@node).returns(result) - @compiler.find(@name).should == :catalog + @compiler.find(@request).should equal(result) end it "should benchmark the compile process" do @@ -154,56 +157,6 @@ describe Puppet::Node::Catalog::Compiler, " when creating catalogs" do level == :notice and message =~ /^Compiled catalog/ end @compiler.interpreter.stubs(:compile).with(@node) - @compiler.find(@name) - end -end - -describe Puppet::Node::Catalog::Compiler, " when determining a client's available catalog version" do - before do - Puppet::Node::Facts.stubs(:find).returns(nil) - Facter.stubs(:value).returns("whatever") - @catalog = Puppet::Node::Catalog::Compiler.new - @name = "johnny" - end - - it "should provide a mechanism for providing the version of a given client's catalog" do - @catalog.should respond_to(:version) - end - - it "should use the client's Facts version as the available catalog version if it is the most recent" do - Puppet::Node::Facts.stubs(:version).with(@name).returns(5) - Puppet::Node.expects(:version).with(@name).returns(3) - @catalog.interpreter.stubs(:catalog_version).returns(4) - - @catalog.version(@name).should == 5 - end - - it "should use the client's Node version as the available catalog version if it is the most recent" do - Puppet::Node::Facts.stubs(:version).with(@name).returns(3) - Puppet::Node.expects(:version).with(@name).returns(5) - @catalog.interpreter.stubs(:catalog_version).returns(4) - - @catalog.version(@name).should == 5 - end - - it "should use the last parse date as the available catalog version if it is the most recent" do - Puppet::Node::Facts.stubs(:version).with(@name).returns(3) - Puppet::Node.expects(:version).with(@name).returns(4) - @catalog.interpreter.stubs(:catalog_version).returns(5) - - @catalog.version(@name).should == 5 - end - - it "should return a version of 0 if no information on the node can be found" do - Puppet::Node.stubs(:find_by_any_name).returns(nil) - @catalog.version(@name).should == 0 - end - - it "should indicate when an update is available even if an input has clock skew" do - pending "Unclear how to implement this" - end - - it "should not indicate an available update when apparent updates are a result of clock skew" do - pending "Unclear how to implement this" + @compiler.find(@request) end end diff --git a/spec/unit/indirector/checksum/file.rb b/spec/unit/indirector/checksum/file.rb index 4f8ee98b2..857d7b050 100755 --- a/spec/unit/indirector/checksum/file.rb +++ b/spec/unit/indirector/checksum/file.rb @@ -38,6 +38,8 @@ describe Puppet::Checksum::File do Puppet.stubs(:[]).with(:bucketdir).returns(@dir) @path = @store.path(@value) + + @request = stub 'request', :key => @value end @@ -76,7 +78,7 @@ describe Puppet::Checksum::File do # The smallest test that will use the calculated path it "should look for the calculated path" do File.expects(:exist?).with(@path).returns(false) - @store.find(@value) + @store.find(@request) end it "should return an instance of Puppet::Checksum created with the content if the file exists" do @@ -87,18 +89,18 @@ describe Puppet::Checksum::File do File.expects(:exist?).with(@path).returns(true) File.expects(:read).with(@path).returns(content) - @store.find(@value).should equal(sum) + @store.find(@request).should equal(sum) end it "should return nil if no file is found" do File.expects(:exist?).with(@path).returns(false) - @store.find(@value).should be_nil + @store.find(@request).should be_nil end it "should fail intelligently if a found file cannot be read" do File.expects(:exist?).with(@path).returns(true) File.expects(:read).with(@path).raises(RuntimeError) - proc { @store.find(@value) }.should raise_error(Puppet::Error) + proc { @store.find(@request) }.should raise_error(Puppet::Error) end end @@ -112,7 +114,7 @@ describe Puppet::Checksum::File do File.expects(:open).with(@path, "w") file = stub 'file', :name => @value - @store.save(file) + @store.save(@request) end it "should make any directories necessary for storage" do @@ -122,19 +124,16 @@ describe Puppet::Checksum::File do File.expects(:directory?).with(File.dirname(@path)).returns(true) File.expects(:open).with(@path, "w") - file = stub 'file', :name => @value - @store.save(file) + @store.save(@request) end end describe Puppet::Checksum::File, " when deleting files" do - it "should remove the file at the calculated path" do File.expects(:exist?).with(@path).returns(true) File.expects(:unlink).with(@path) - file = stub 'file', :name => @value - @store.destroy(file) + @store.destroy(@request) end end -end
\ No newline at end of file +end diff --git a/spec/unit/indirector/direct_file_server.rb b/spec/unit/indirector/direct_file_server.rb index 9f3652536..a8583716a 100755 --- a/spec/unit/indirector/direct_file_server.rb +++ b/spec/unit/indirector/direct_file_server.rb @@ -23,19 +23,21 @@ describe Puppet::Indirector::DirectFileServer do @server = @direct_file_class.new @uri = "file:///my/local" + + @request = stub 'request', :key => @uri, :options => {} end describe Puppet::Indirector::DirectFileServer, "when finding a single file" do it "should return nil if the file does not exist" do FileTest.expects(:exists?).with("/my/local").returns false - @server.find(@uri).should be_nil + @server.find(@request).should be_nil end it "should return a Content instance created with the full path to the file if the file exists" do FileTest.expects(:exists?).with("/my/local").returns true @model.expects(:new).returns(:mycontent) - @server.find(@uri).should == :mycontent + @server.find(@request).should == :mycontent end end @@ -49,18 +51,20 @@ describe Puppet::Indirector::DirectFileServer do it "should create the Content instance with the original key as the key" do @model.expects(:new).with { |key, options| key == @uri }.returns(@data) - @server.find(@uri) + @server.find(@request) end it "should pass the full path to the instance" do @model.expects(:new).with { |key, options| options[:path] == "/my/local" }.returns(@data) - @server.find(@uri) + @server.find(@request) end it "should pass the :links setting on to the created Content instance if the file exists and there is a value for :links" do @model.expects(:new).returns(@data) @data.expects(:links=).with(:manage) - @server.find(@uri, :links => :manage) + + @request.stubs(:options).returns(:links => :manage) + @server.find(@request) end end @@ -68,25 +72,27 @@ describe Puppet::Indirector::DirectFileServer do it "should return nil if the file does not exist" do FileTest.expects(:exists?).with("/my/local").returns false - @server.find(@uri).should be_nil + @server.find(@request).should be_nil end it "should pass the original key to :path2instances" do FileTest.expects(:exists?).with("/my/local").returns true @server.expects(:path2instances).with { |uri, path, options| uri == @uri } - @server.search(@uri) + @server.search(@request) end it "should use :path2instances from the terminus_helper to return instances if the file exists" do FileTest.expects(:exists?).with("/my/local").returns true @server.expects(:path2instances) - @server.search(@uri) + @server.search(@request) end it "should pass any options on to :path2instances" do FileTest.expects(:exists?).with("/my/local").returns true @server.expects(:path2instances).with { |uri, path, options| options == {:testing => :one, :other => :two}} - @server.search(@uri, :testing => :one, :other => :two) + + @request.stubs(:options).returns(:testing => :one, :other => :two) + @server.search(@request) end end -end
\ No newline at end of file +end diff --git a/spec/unit/indirector/envelope.rb b/spec/unit/indirector/envelope.rb new file mode 100755 index 000000000..17c62023a --- /dev/null +++ b/spec/unit/indirector/envelope.rb @@ -0,0 +1,47 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../spec_helper' +require 'puppet/indirector/envelope' + +describe Puppet::Indirector::Envelope do + before do + @instance = Object.new + @instance.extend(Puppet::Indirector::Envelope) + end + + it "should have an expiration accessor" do + @instance.expiration = "testing" + @instance.expiration.should == "testing" + end + + it "should have an expiration setter" do + @instance.should respond_to(:expiration=) + end + + it "should have a means of testing whether it is expired" do + @instance.should respond_to(:expired?) + end + + describe "when testing if it is expired" do + it "should return false if there is no expiration set" do + @instance.should_not be_expired + end + + it "should return true if the current date is after the expiration date" do + @instance.expiration = Time.now - 10 + @instance.should be_expired + end + + it "should return false if the current date is prior to the expiration date" do + @instance.expiration = Time.now + 10 + @instance.should_not be_expired + end + + it "should return false if the current date is equal to the expiration date" do + now = Time.now + Time.stubs(:now).returns(now) + @instance.expiration = now + @instance.should_not be_expired + end + end +end diff --git a/spec/unit/indirector/exec.rb b/spec/unit/indirector/exec.rb index 3baf06629..e474de8b9 100755 --- a/spec/unit/indirector/exec.rb +++ b/spec/unit/indirector/exec.rb @@ -18,31 +18,33 @@ describe Puppet::Indirector::Exec do @searcher = @exec_class.new @searcher.command = ["/echo"] + + @request = stub 'request', :key => "foo" end it "should throw an exception if the command is not an array" do @searcher.command = "/usr/bin/echo" - proc { @searcher.find("foo") }.should raise_error(Puppet::DevError) + proc { @searcher.find(@request) }.should raise_error(Puppet::DevError) end it "should throw an exception if the command is not fully qualified" do @searcher.command = ["mycommand"] - proc { @searcher.find("foo") }.should raise_error(ArgumentError) + proc { @searcher.find(@request) }.should raise_error(ArgumentError) end it "should execute the command with the object name as the only argument" do - @searcher.expects(:execute).with(%w{/echo yay}) - @searcher.find("yay") + @searcher.expects(:execute).with(%w{/echo foo}) + @searcher.find(@request) end it "should return the output of the script" do - @searcher.expects(:execute).with(%w{/echo yay}).returns("whatever") - @searcher.find("yay").should == "whatever" + @searcher.expects(:execute).with(%w{/echo foo}).returns("whatever") + @searcher.find(@request).should == "whatever" end it "should return nil when the command produces no output" do - @searcher.expects(:execute).with(%w{/echo yay}).returns(nil) - @searcher.find("yay").should be_nil + @searcher.expects(:execute).with(%w{/echo foo}).returns(nil) + @searcher.find(@request).should be_nil end it "should be able to execute commands with multiple arguments" diff --git a/spec/unit/indirector/facts/facter.rb b/spec/unit/indirector/facts/facter.rb index 0974a60ec..225eb153b 100755 --- a/spec/unit/indirector/facts/facter.rb +++ b/spec/unit/indirector/facts/facter.rb @@ -36,22 +36,22 @@ describe Puppet::Node::Facts::Facter do @facter = Puppet::Node::Facts::Facter.new Facter.stubs(:to_hash).returns({}) @name = "me" - @facts = @facter.find(@name) + @request = stub 'request', :key => @name end describe Puppet::Node::Facts::Facter, " when finding facts" do it "should return a Facts instance" do - @facts.should be_instance_of(Puppet::Node::Facts) + @facter.find(@request).should be_instance_of(Puppet::Node::Facts) end it "should return a Facts instance with the provided key as the name" do - @facts.name.should == @name + @facter.find(@request).name.should == @name end it "should return the Facter facts as the values in the Facts instance" do Facter.expects(:to_hash).returns("one" => "two") - facts = @facter.find(@name) + facts = @facter.find(@request) facts.values["one"].should == "two" end end @@ -73,4 +73,4 @@ describe Puppet::Node::Facts::Facter do describe Puppet::Node::Facts::Facter, " when loading facts from the factpath" do it "should load every fact in each factpath directory" end -end
\ No newline at end of file +end diff --git a/spec/unit/indirector/file.rb b/spec/unit/indirector/file.rb index 37740f0d0..67ead4cdb 100755 --- a/spec/unit/indirector/file.rb +++ b/spec/unit/indirector/file.rb @@ -21,6 +21,8 @@ describe Puppet::Indirector::File do @path = "/my/file" @dir = "/my" + + @request = stub 'request', :key => @path end describe Puppet::Indirector::File, " when finding files" do @@ -37,7 +39,7 @@ describe Puppet::Indirector::File do File.expects(:exist?).with(@path).returns(true) File.expects(:read).with(@path).returns(content) - @searcher.find(@path) + @searcher.find(@request) end it "should create the model instance with the content as the only argument to initialization" do @@ -48,18 +50,18 @@ describe Puppet::Indirector::File do File.expects(:exist?).with(@path).returns(true) File.expects(:read).with(@path).returns(content) - @searcher.find(@path).should equal(file) + @searcher.find(@request).should equal(file) end it "should return nil if no file is found" do File.expects(:exist?).with(@path).returns(false) - @searcher.find(@path).should be_nil + @searcher.find(@request).should be_nil end it "should fail intelligently if a found file cannot be read" do File.expects(:exist?).with(@path).returns(true) File.expects(:read).with(@path).raises(RuntimeError) - proc { @searcher.find(@path) }.should raise_error(Puppet::Error) + proc { @searcher.find(@request) }.should raise_error(Puppet::Error) end it "should use the path() method to calculate the path if it exists" do @@ -68,42 +70,39 @@ describe Puppet::Indirector::File do end File.expects(:exist?).with(@path.upcase).returns(false) - @searcher.find(@path) + @searcher.find(@request) end end describe Puppet::Indirector::File, " when saving files" do + before do + @content = "my content" + @file = stub 'file', :content => @content, :path => @path, :name => @path + @request.stubs(:instance).returns @file + end it "should provide a method to save file contents at a specified path" do filehandle = mock 'file' - content = "my content" File.expects(:directory?).with(@dir).returns(true) File.expects(:open).with(@path, "w").yields(filehandle) - filehandle.expects(:print).with(content) + filehandle.expects(:print).with(@content) - file = stub 'file', :content => content, :path => @path, :name => @path - - @searcher.save(file) + @searcher.save(@request) end it "should fail intelligently if the file's parent directory does not exist" do File.expects(:directory?).with(@dir).returns(false) - file = stub 'file', :path => @path, :name => @path - - proc { @searcher.save(file) }.should raise_error(Puppet::Error) + proc { @searcher.save(@request) }.should raise_error(Puppet::Error) end it "should fail intelligently if a file cannot be written" do filehandle = mock 'file' - content = "my content" File.expects(:directory?).with(@dir).returns(true) File.expects(:open).with(@path, "w").yields(filehandle) - filehandle.expects(:print).with(content).raises(ArgumentError) - - file = stub 'file', :content => content, :path => @path, :name => @path + filehandle.expects(:print).with(@content).raises(ArgumentError) - proc { @searcher.save(file) }.should raise_error(Puppet::Error) + proc { @searcher.save(@request) }.should raise_error(Puppet::Error) end it "should use the path() method to calculate the path if it exists" do @@ -111,48 +110,45 @@ describe Puppet::Indirector::File do name.upcase end - file = stub 'file', :name => "/yay" + # Reset the key to something without a parent dir, so no checks are necessary + @request.stubs(:key).returns "/my" - File.expects(:open).with("/YAY", "w") - @searcher.save(file) + File.expects(:open).with("/MY", "w") + @searcher.save(@request) end end describe Puppet::Indirector::File, " when removing files" do it "should provide a method to remove files at a specified path" do - file = stub 'file', :path => @path, :name => @path File.expects(:exist?).with(@path).returns(true) File.expects(:unlink).with(@path) - @searcher.destroy(file) + @searcher.destroy(@request) end it "should throw an exception if the file is not found" do - file = stub 'file', :path => @path, :name => @path File.expects(:exist?).with(@path).returns(false) - proc { @searcher.destroy(file) }.should raise_error(Puppet::Error) + proc { @searcher.destroy(@request) }.should raise_error(Puppet::Error) end it "should fail intelligently if the file cannot be removed" do - file = stub 'file', :path => @path, :name => @path File.expects(:exist?).with(@path).returns(true) File.expects(:unlink).with(@path).raises(ArgumentError) - proc { @searcher.destroy(file) }.should raise_error(Puppet::Error) + proc { @searcher.destroy(@request) }.should raise_error(Puppet::Error) end it "should use the path() method to calculate the path if it exists" do - @searcher.meta_def(:path) do |name| - name.upcase + @searcher.meta_def(:path) do |thing| + thing.to_s.upcase end - file = stub 'file', :name => "/yay" - File.expects(:exist?).with("/YAY").returns(true) - File.expects(:unlink).with("/YAY") + File.expects(:exist?).with("/MY/FILE").returns(true) + File.expects(:unlink).with("/MY/FILE") - @searcher.destroy(file) + @searcher.destroy(@request) end end -end
\ No newline at end of file +end diff --git a/spec/unit/indirector/file_metadata/file.rb b/spec/unit/indirector/file_metadata/file.rb index 0a37a6895..9474620c7 100755 --- a/spec/unit/indirector/file_metadata/file.rb +++ b/spec/unit/indirector/file_metadata/file.rb @@ -15,34 +15,38 @@ describe Puppet::Indirector::FileMetadata::File do it "should be a subclass of the DirectFileServer terminus" do Puppet::Indirector::FileMetadata::File.superclass.should equal(Puppet::Indirector::DirectFileServer) end -end -describe Puppet::Indirector::FileMetadata::File, "when creating the instance for a single found file" do - before do - @metadata = Puppet::Indirector::FileMetadata::File.new - @uri = "file:///my/local" - @data = mock 'metadata' - @data.stubs(:collect_attributes) - FileTest.expects(:exists?).with("/my/local").returns true - end + describe "when creating the instance for a single found file" do + before do + @metadata = Puppet::Indirector::FileMetadata::File.new + @uri = "file:///my/local" + @data = mock 'metadata' + @data.stubs(:collect_attributes) + FileTest.expects(:exists?).with("/my/local").returns true - it "should collect its attributes when a file is found" do - @data.expects(:collect_attributes) + @request = stub 'request', :key => @uri, :options => {} + end - Puppet::FileServing::Metadata.expects(:new).returns(@data) - @metadata.find(@uri).should == @data - end -end + it "should collect its attributes when a file is found" do + @data.expects(:collect_attributes) -describe Puppet::Indirector::FileMetadata::File, "when searching for multiple files" do - before do - @metadata = Puppet::Indirector::FileMetadata::File.new - @uri = "file:///my/local" + Puppet::FileServing::Metadata.expects(:new).returns(@data) + @metadata.find(@request).should == @data + end end - it "should collect the attributes of the instances returned" do - FileTest.expects(:exists?).with("/my/local").returns true - @metadata.expects(:path2instances).returns( [mock("one", :collect_attributes => nil), mock("two", :collect_attributes => nil)] ) - @metadata.search(@uri) + describe "when searching for multiple files" do + before do + @metadata = Puppet::Indirector::FileMetadata::File.new + @uri = "file:///my/local" + + @request = stub 'request', :key => @uri, :options => {} + end + + it "should collect the attributes of the instances returned" do + FileTest.expects(:exists?).with("/my/local").returns true + @metadata.expects(:path2instances).returns( [mock("one", :collect_attributes => nil), mock("two", :collect_attributes => nil)] ) + @metadata.search(@request) + end end end diff --git a/spec/unit/indirector/file_server.rb b/spec/unit/indirector/file_server.rb index 974b95e0e..79be8cc29 100755 --- a/spec/unit/indirector/file_server.rb +++ b/spec/unit/indirector/file_server.rb @@ -165,4 +165,4 @@ describe Puppet::Indirector::FileServer do @file_server.search(@uri, :testing => :one, :other => :two) end end -end
\ No newline at end of file +end diff --git a/spec/unit/indirector/indirection.rb b/spec/unit/indirector/indirection.rb index fe456b61e..e8ab9633b 100755 --- a/spec/unit/indirector/indirection.rb +++ b/spec/unit/indirector/indirection.rb @@ -2,579 +2,730 @@ require File.dirname(__FILE__) + '/../../spec_helper' -require 'puppet/indirector' +require 'puppet/indirector/indirection' +describe "Indirection Delegator", :shared => true do + it "should create a request object with the appropriate method name and all of the passed arguments" do + request = stub 'request', :options => {} + @indirection.expects(:request).with(@method, "mystuff", :one => :two).returns request -describe Puppet::Indirector::Indirection, " when initializing" do - # (LAK) I've no idea how to test this, really. - it "should store a reference to itself before it consumes its options" do - proc { @indirection = Puppet::Indirector::Indirection.new(Object.new, :testingness, :not_valid_option) }.should raise_error - Puppet::Indirector::Indirection.instance(:testingness).should be_instance_of(Puppet::Indirector::Indirection) - Puppet::Indirector::Indirection.instance(:testingness).delete + @terminus.stubs(@method) + + @indirection.send(@method, "mystuff", :one => :two) end - it "should keep a reference to the indirecting model" do - model = mock 'model' - @indirection = Puppet::Indirector::Indirection.new(model, :myind) - @indirection.model.should equal(model) + it "should let the :select_terminus method choose the terminus using the created request if the :select_terminus method is available" do + # Define the method, so our respond_to? hook matches. + class << @indirection + def select_terminus(request) + end + end + + request = stub 'request', :key => "me", :options => {} + + @indirection.stubs(:request).returns request + + @indirection.expects(:select_terminus).with(request).returns :test_terminus + + @indirection.stubs(:check_authorization) + @terminus.expects(@method) + + @indirection.send(@method, "me") end - it "should set the name" do - @indirection = Puppet::Indirector::Indirection.new(mock('model'), :myind) - @indirection.name.should == :myind + it "should choose the terminus returned by the :terminus_class method if no :select_terminus method is available" do + @indirection.expects(:terminus_class).returns :test_terminus + + @terminus.expects(@method) + + @indirection.send(@method, "me") end - it "should require indirections to have unique names" do - @indirection = Puppet::Indirector::Indirection.new(mock('model'), :test) - proc { Puppet::Indirector::Indirection.new(:test) }.should raise_error(ArgumentError) + it "should let the appropriate terminus perform the lookup" do + @terminus.expects(@method).with { |r| r.is_a?(Puppet::Indirector::Request) } + @indirection.send(@method, "me") end +end - it "should extend itself with any specified module" do - mod = Module.new - @indirection = Puppet::Indirector::Indirection.new(mock('model'), :test, :extend => mod) - @indirection.metaclass.included_modules.should include(mod) +describe "Delegation Authorizer", :shared => true do + before do + # So the :respond_to? turns out correctly. + class << @terminus + def authorized? + end + end end - after do - @indirection.delete if defined? @indirection + it "should not check authorization if a node name is not provided" do + @terminus.expects(:authorized?).never + @terminus.stubs(@method) + + # The quotes are necessary here, else it looks like a block. + @request.stubs(:options).returns({}) + @indirection.send(@method, "/my/key") end -end -describe Puppet::Indirector::Indirection do - before :each do - @indirection = Puppet::Indirector::Indirection.new(mock('model'), :test) - @terminus = stub 'terminus', :has_most_recent? => false - @indirection.stubs(:terminus).returns(@terminus) - @indirection.stubs(:terminus_class).returns(:whatever) - @instance = stub 'instance', :version => nil, :version= => nil, :name => "whatever" - @name = :mything + it "should pass the request to the terminus's authorization method" do + @terminus.expects(:authorized?).with { |r| r.is_a?(Puppet::Indirector::Request) }.returns(true) + @terminus.stubs(@method) + + @indirection.send(@method, "/my/key", :node => "mynode") end - - describe Puppet::Indirector::Indirection, " when looking for a model instance" do - it "should let the appropriate terminus perform the lookup" do - @terminus.expects(:find).with(@name).returns(@instance) - @indirection.find(@name).should == @instance - end + it "should fail if authorization returns false" do + @terminus.expects(:authorized?).returns(false) + @terminus.stubs(@method) + proc { @indirection.send(@method, "/my/key", :node => "mynode") }.should raise_error(ArgumentError) + end + + it "should continue if authorization returns true" do + @terminus.expects(:authorized?).returns(true) + @terminus.stubs(@method) + @indirection.send(@method, "/my/key", :node => "mynode") + end +end - it "should not attempt to set a timestamp if the terminus cannot find the instance" do - @terminus.expects(:find).with(@name).returns(nil) - proc { @indirection.find(@name) }.should_not raise_error +describe Puppet::Indirector::Indirection do + describe "when initializing" do + # (LAK) I've no idea how to test this, really. + it "should store a reference to itself before it consumes its options" do + proc { @indirection = Puppet::Indirector::Indirection.new(Object.new, :testingness, :not_valid_option) }.should raise_error + Puppet::Indirector::Indirection.instance(:testingness).should be_instance_of(Puppet::Indirector::Indirection) + Puppet::Indirector::Indirection.instance(:testingness).delete end - it "should pass the instance to the :post_find hook if there is one" do - class << @terminus - def post_find - end - end - @terminus.expects(:post_find).with(@instance) - @terminus.expects(:find).with(@name).returns(@instance) - @indirection.find(@name) + it "should keep a reference to the indirecting model" do + model = mock 'model' + @indirection = Puppet::Indirector::Indirection.new(model, :myind) + @indirection.model.should equal(model) end - end - - describe Puppet::Indirector::Indirection, " when removing a model instance" do - it "should let the appropriate terminus remove the instance" do - @terminus.expects(:destroy).with(@name).returns(@instance) - @indirection.destroy(@name).should == @instance + it "should set the name" do + @indirection = Puppet::Indirector::Indirection.new(mock('model'), :myind) + @indirection.name.should == :myind end - end - describe Puppet::Indirector::Indirection, " when searching for multiple model instances" do + it "should require indirections to have unique names" do + @indirection = Puppet::Indirector::Indirection.new(mock('model'), :test) + proc { Puppet::Indirector::Indirection.new(:test) }.should raise_error(ArgumentError) + end - it "should let the appropriate terminus find the matching instances" do - @terminus.expects(:search).with(@name).returns(@instance) - @indirection.search(@name).should == @instance + it "should extend itself with any specified module" do + mod = Module.new + @indirection = Puppet::Indirector::Indirection.new(mock('model'), :test, :extend => mod) + @indirection.metaclass.included_modules.should include(mod) end - it "should pass the instances to the :post_search hook if there is one" do - class << @terminus - def post_search - end - end - @terminus.expects(:post_search).with(@instance) - @terminus.expects(:search).with(@name).returns(@instance) - @indirection.search(@name) + after do + @indirection.delete if defined? @indirection end end - describe Puppet::Indirector::Indirection, " when storing a model instance" do + describe "when an instance" do + before :each do + @terminus_class = mock 'terminus_class' + @terminus = mock 'terminus' + @terminus_class.stubs(:new).returns(@terminus) + @cache = mock 'cache' + @cache_class = mock 'cache_class' + Puppet::Indirector::Terminus.stubs(:terminus_class).with(:test, :cache_terminus).returns(@cache_class) + Puppet::Indirector::Terminus.stubs(:terminus_class).with(:test, :test_terminus).returns(@terminus_class) + + @indirection = Puppet::Indirector::Indirection.new(mock('model'), :test) + @indirection.terminus_class = :test_terminus + + @instance = stub 'instance', :expiration => nil, :expiration= => nil, :name => "whatever" + @name = :mything - it "should let the appropriate terminus store the instance" do - @terminus.expects(:save).with(@instance).returns(@instance) - @indirection.save(@instance).should == @instance + #@request = stub 'instance', :key => "/my/key", :instance => @instance, :options => {} + @request = mock 'instance' + end + + it "should allow setting the ttl" do + @indirection.ttl = 300 + @indirection.ttl.should == 300 end - end - - describe Puppet::Indirector::Indirection, " when handling instance versions" do - it "should let the appropriate terminus perform the lookup" do - @terminus.expects(:version).with(@name).returns(5) - @indirection.version(@name).should == 5 + it "should default to the :runinterval setting, converted to an integer, for its ttl" do + Puppet.settings.expects(:value).returns "1800" + @indirection.ttl.should == 1800 end - it "should add versions to found instances that do not already have them" do - @terminus.expects(:find).with(@name).returns(@instance) - time = mock 'time' - time.expects(:utc).returns(:mystamp) - Time.expects(:now).returns(time) - @instance.expects(:version=).with(:mystamp) - @indirection.find(@name) + it "should calculate the current expiration by adding the TTL to the current time" do + @indirection.stubs(:ttl).returns(100) + now = Time.now + Time.stubs(:now).returns now + @indirection.expiration.should == (Time.now + 100) end - it "should add versions to saved instances that do not already have them" do - time = mock 'time' - time.expects(:utc).returns(:mystamp) - Time.expects(:now).returns(time) - @instance.expects(:version=).with(:mystamp) - @terminus.stubs(:save) - @indirection.save(@instance) + it "should have a method for creating an indirection request instance" do + @indirection.should respond_to(:request) end - # We've already tested this, basically, but... - it "should use the current time in UTC for versions" do - @instance.expects(:version=).with do |time| - time.utc? + describe "creates a request" do + it "should create it with its name as the request's indirection name" do + Puppet::Indirector::Request.expects(:new).with { |name, *other| @indirection.name == name } + @indirection.request(:funtest, "yayness") + end + + it "should require a method and key" do + Puppet::Indirector::Request.expects(:new).with { |name, method, key, *other| method == :funtest and key == "yayness" } + @indirection.request(:funtest, "yayness") + end + + it "should support optional arguments" do + Puppet::Indirector::Request.expects(:new).with { |name, method, key, other| other == {:one => :two} } + @indirection.request(:funtest, "yayness", :one => :two) + end + + it "should default to the arguments being nil" do + Puppet::Indirector::Request.expects(:new).with { |name, method, key, args| args.nil? } + @indirection.request(:funtest, "yayness") + end + + it "should return the request" do + request = mock 'request' + Puppet::Indirector::Request.expects(:new).returns request + @indirection.request(:funtest, "yayness").should equal(request) end - @terminus.stubs(:save) - @indirection.save(@instance) end - end + + describe "and looking for a model instance" do + before { @method = :find } + it_should_behave_like "Indirection Delegator" + it_should_behave_like "Delegation Authorizer" - describe Puppet::Indirector::Indirection, " when an authorization hook is present" do + it "should return the results of the delegation" do + @terminus.expects(:find).returns(@instance) + @indirection.find("me").should equal(@instance) + end - before do - # So the :respond_to? turns out right. - class << @terminus - def authorized? + it "should set the expiration date on any instances without one set" do + @terminus.stubs(:find).returns(@instance) + + @indirection.expects(:expiration).returns :yay + + @instance.expects(:expiration).returns(nil) + @instance.expects(:expiration=).with(:yay) + + @indirection.find("/my/key") + end + + it "should not override an already-set expiration date on returned instances" do + @terminus.stubs(:find).returns(@instance) + + @indirection.expects(:expiration).never + + @instance.expects(:expiration).returns(:yay) + @instance.expects(:expiration=).never + + @indirection.find("/my/key") + end + + describe "when caching is enabled" do + before do + @indirection.cache_class = :cache_terminus + @cache_class.expects(:new).returns(@cache) + + @instance.stubs(:expired?).returns false + end + + it "should first look in the cache for an instance" do + @terminus.stubs(:find).never + @cache.expects(:find).returns @instance + + @indirection.find("/my/key") + end + + it "should use a request to look in the cache for cached objects" do + @cache.expects(:find).with { |r| r.method == :find and r.key == "/my/key" }.returns @instance + + @cache.stubs(:save) + + @indirection.find("/my/key") + end + + it "should return the cached object if it is not expired" do + @instance.stubs(:expired?).returns false + + @cache.stubs(:find).returns @instance + @indirection.find("/my/key").should equal(@instance) + end + + it "should send a debug log if it is using the cached object" do + Puppet.expects(:debug) + @cache.stubs(:find).returns @instance + + @indirection.find("/my/key") + end + + it "should not return the cached object if it is expired" do + @instance.stubs(:expired?).returns true + + @cache.stubs(:find).returns @instance + @terminus.stubs(:find).returns nil + @indirection.find("/my/key").should be_nil + end + + it "should send an info log if it is using the cached object" do + Puppet.expects(:info) + @instance.stubs(:expired?).returns true + + @cache.stubs(:find).returns @instance + @terminus.stubs(:find).returns nil + @indirection.find("/my/key") + end + + it "should cache any objects not retrieved from the cache" do + @cache.expects(:find).returns nil + + @terminus.expects(:find).returns(@instance) + @cache.expects(:save) + + @indirection.find("/my/key") + end + + it "should use a request to look in the cache for cached objects" do + @cache.expects(:find).with { |r| r.method == :find and r.key == "/my/key" }.returns nil + + @terminus.stubs(:find).returns(@instance) + @cache.stubs(:save) + + @indirection.find("/my/key") + end + + it "should cache the instance using a request with the instance set to the cached object" do + @cache.stubs(:find).returns nil + + @terminus.stubs(:find).returns(@instance) + + @cache.expects(:save).with { |r| r.method == :save and r.instance == @instance } + + @indirection.find("/my/key") + end + + it "should send an info log that the object is being cached" do + @cache.stubs(:find).returns nil + + @terminus.stubs(:find).returns(@instance) + @cache.stubs(:save) + + Puppet.expects(:info) + + @indirection.find("/my/key") end end end - it "should not check authorization if a node name is not provided" do - @terminus.expects(:authorized?).never - @terminus.stubs(:find) - @indirection.find("/my/key") - end + describe "and storing a model instance" do + before { @method = :save } - it "should fail while finding instances if authorization returns false" do - @terminus.expects(:authorized?).with(:find, "/my/key", :node => "mynode").returns(false) - @terminus.stubs(:find) - proc { @indirection.find("/my/key", :node => "mynode") }.should raise_error(ArgumentError) - end + it_should_behave_like "Indirection Delegator" + it_should_behave_like "Delegation Authorizer" - it "should continue finding instances if authorization returns true" do - @terminus.expects(:authorized?).with(:find, "/my/key", :node => "mynode").returns(true) - @terminus.stubs(:find) - @indirection.find("/my/key", :node => "mynode") - end + it "should return nil" do + @terminus.stubs(:save) + @indirection.save(@instance).should be_nil + end - it "should fail while saving instances if authorization returns false" do - @terminus.expects(:authorized?).with(:save, :myinstance, :node => "mynode").returns(false) - @terminus.stubs(:save) - proc { @indirection.save(:myinstance, :node => "mynode") }.should raise_error(ArgumentError) - end + describe "when caching is enabled" do + before do + @indirection.cache_class = :cache_terminus + @cache_class.expects(:new).returns(@cache) - it "should continue saving instances if authorization returns true" do - instance = stub 'instance', :version => 1.0, :name => "eh" - @terminus.expects(:authorized?).with(:save, instance, :node => "mynode").returns(true) - @terminus.stubs(:save) - @indirection.save(instance, :node => "mynode") - end + @instance.stubs(:expired?).returns false + end - it "should fail while destroying instances if authorization returns false" do - @terminus.expects(:authorized?).with(:destroy, "/my/key", :node => "mynode").returns(false) - @terminus.stubs(:destroy) - proc { @indirection.destroy("/my/key", :node => "mynode") }.should raise_error(ArgumentError) - end + it "should use a request to save the object to the cache" do + request = stub 'request', :instance => @instance, :options => {} - it "should continue destroying instances if authorization returns true" do - instance = stub 'instance', :version => 1.0, :name => "eh" - @terminus.expects(:authorized?).with(:destroy, instance, :node => "mynode").returns(true) - @terminus.stubs(:destroy) - @indirection.destroy(instance, :node => "mynode") - end + @indirection.expects(:request).returns request - it "should fail while searching for instances if authorization returns false" do - @terminus.expects(:authorized?).with(:search, "/my/key", :node => "mynode").returns(false) - @terminus.stubs(:search) - proc { @indirection.search("/my/key", :node => "mynode") }.should raise_error(ArgumentError) + @cache.expects(:save).with(request) + @terminus.stubs(:save) + @indirection.save(@instance) + end + end end + + describe "and removing a model instance" do + before { @method = :destroy } - it "should continue searching for instances if authorization returns true" do - @terminus.expects(:authorized?).with(:search, "/my/key", :node => "mynode").returns(true) - @terminus.stubs(:search) - @indirection.search("/my/key", :node => "mynode") - end - end + it_should_behave_like "Indirection Delegator" + it_should_behave_like "Delegation Authorizer" - after :each do - @indirection.delete - Puppet::Indirector::Indirection.clear_cache - end -end + it "should return nil" do + @terminus.stubs(:destroy) + @indirection.destroy("/my/key").should be_nil + end + describe "when caching is enabled" do + before do + @indirection.cache_class = :cache_terminus + @cache_class.expects(:new).returns(@cache) -describe Puppet::Indirector::Indirection, " when managing indirection instances" do - it "should allow an indirection to be retrieved by name" do - @indirection = Puppet::Indirector::Indirection.new(mock('model'), :test) - Puppet::Indirector::Indirection.instance(:test).should equal(@indirection) - end - - it "should return nil when the named indirection has not been created" do - Puppet::Indirector::Indirection.instance(:test).should be_nil - end + @instance.stubs(:expired?).returns false + end - it "should allow an indirection's model to be retrieved by name" do - mock_model = mock('model') - @indirection = Puppet::Indirector::Indirection.new(mock_model, :test) - Puppet::Indirector::Indirection.model(:test).should equal(mock_model) - end - - it "should return nil when no model matches the requested name" do - Puppet::Indirector::Indirection.model(:test).should be_nil - end + it "should use a request instance to search in and remove objects from the cache" do + destroy = stub 'destroy_request', :key => "/my/key", :options => {} + find = stub 'destroy_request', :key => "/my/key", :options => {} - after do - @indirection.delete if defined? @indirection - end -end - -describe Puppet::Indirector::Indirection, " when choosing the terminus class" do - before do - @indirection = Puppet::Indirector::Indirection.new(mock('model'), :test) - @terminus = mock 'terminus' - @terminus_class = stub 'terminus class', :new => @terminus - Puppet::Indirector::Terminus.stubs(:terminus_class).with(:test, :default).returns(@terminus_class) - end + @indirection.expects(:request).with(:destroy, "/my/key").returns destroy + @indirection.expects(:request).with(:find, "/my/key").returns find - it "should choose the default terminus class if one is specified and no specific terminus class is provided" do - @indirection.terminus_class = :default - @indirection.terminus_class.should equal(:default) - end + cached = mock 'cache' - it "should use the provided Puppet setting if told to do so" do - Puppet::Indirector::Terminus.stubs(:terminus_class).with(:test, :my_terminus).returns(mock("terminus_class2")) - Puppet.settings.expects(:value).with(:my_setting).returns("my_terminus") - @indirection.terminus_setting = :my_setting - @indirection.terminus_class.should equal(:my_terminus) - end + @cache.expects(:find).with(find).returns cached + @cache.expects(:destroy).with(destroy) - it "should fail if the provided terminus class is not valid" do - Puppet::Indirector::Terminus.stubs(:terminus_class).with(:test, :nosuchclass).returns(nil) - proc { @indirection.terminus_class = :nosuchclass }.should raise_error(ArgumentError) - end - - it "should fail if no terminus class is picked" do - proc { @indirection.terminus_class }.should raise_error(Puppet::DevError) - end + @terminus.stubs(:destroy) - after do - @indirection.delete if defined? @indirection - end -end + @indirection.destroy("/my/key") + end + end + end -describe Puppet::Indirector::Indirection, " when specifying the terminus class to use" do - before do - @indirection = Puppet::Indirector::Indirection.new(mock('model'), :test) - @terminus = mock 'terminus' - @terminus_class = stub 'terminus class', :new => @terminus - end + describe "and searching for multiple model instances" do + before { @method = :search } - it "should allow specification of a terminus type" do - @indirection.should respond_to(:terminus_class=) - end + it_should_behave_like "Indirection Delegator" + it_should_behave_like "Delegation Authorizer" - it "should fail to redirect if no terminus type has been specified" do - proc { @indirection.find("blah") }.should raise_error(Puppet::DevError) - end + it "should set the expiration date on any instances without one set" do + @terminus.stubs(:search).returns([@instance]) - it "should fail when the terminus class name is an empty string" do - proc { @indirection.terminus_class = "" }.should raise_error(ArgumentError) - end + @indirection.expects(:expiration).returns :yay - it "should fail when the terminus class name is nil" do - proc { @indirection.terminus_class = nil }.should raise_error(ArgumentError) - end + @instance.expects(:expiration).returns(nil) + @instance.expects(:expiration=).with(:yay) - it "should fail when the specified terminus class cannot be found" do - Puppet::Indirector::Terminus.expects(:terminus_class).with(:test, :foo).returns(nil) - proc { @indirection.terminus_class = :foo }.should raise_error(ArgumentError) - end + @indirection.search("/my/key") + end - it "should select the specified terminus class if a terminus class name is provided" do - Puppet::Indirector::Terminus.expects(:terminus_class).with(:test, :foo).returns(@terminus_class) - @indirection.terminus(:foo).should equal(@terminus) - end + it "should not override an already-set expiration date on returned instances" do + @terminus.stubs(:search).returns([@instance]) - it "should use the configured terminus class if no terminus name is specified" do - Puppet::Indirector::Terminus.stubs(:terminus_class).with(:test, :foo).returns(@terminus_class) - @indirection.terminus_class = :foo - @indirection.terminus().should equal(@terminus) - end + @indirection.expects(:expiration).never - after do - @indirection.delete if defined? @indirection - end -end + @instance.expects(:expiration).returns(:yay) + @instance.expects(:expiration=).never -describe Puppet::Indirector::Indirection, " when a select_terminus hook is available" do - before do - @indirection = Puppet::Indirector::Indirection.new(mock('model'), :test) + @indirection.search("/my/key") + end - # And provide a select_terminus hook - @indirection.meta_def(:select_terminus) do |uri| - :other + it "should return the results of searching in the terminus" do + @terminus.expects(:search).returns([@instance]) + @indirection.search("/my/key").should == [@instance] + end end - @terminus = mock 'terminus' - @terminus_class = stub 'terminus class', :new => @terminus + describe "and expiring a model instance" do + describe "when caching is not enabled" do + it "should do nothing" do + @cache_class.expects(:new).never - @other_terminus = mock 'other_terminus' - @other_terminus_class = stub 'other_terminus_class', :new => @other_terminus + @indirection.expire("/my/key") + end + end - @cache_terminus = mock 'cache_terminus' - @cache_terminus_class = stub 'cache_terminus_class', :new => @cache_terminus + describe "when caching is enabled" do + before do + @indirection.cache_class = :cache_terminus + @cache_class.expects(:new).returns(@cache) - Puppet::Indirector::Terminus.stubs(:terminus_class).with(:test, :foo).returns(@terminus_class) - Puppet::Indirector::Terminus.stubs(:terminus_class).with(:test, :other).returns(@other_terminus_class) - Puppet::Indirector::Terminus.stubs(:terminus_class).with(:test, :cache).returns(@cache_terminus_class) + @instance.stubs(:expired?).returns false - # Set it to a default type. - @indirection.terminus_class = :foo + @cached = stub 'cached', :expiration= => nil, :name => "/my/key" + end - @uri = "full://url/path" - @result = stub 'result', :version => 1.0 - end + it "should use a request to find within the cache" do + @cache.expects(:find).with { |r| r.is_a?(Puppet::Indirector::Request) and r.method == :find } + @indirection.expire("/my/key") + end - it "should use the terminus name provided by passing the key to the :select_terminus hook when finding instances" do - # Set up the expectation - @other_terminus.expects(:find).with(@uri).returns(@result) + it "should do nothing if no such instance is cached" do + @cache.expects(:find).returns nil - @indirection.find(@uri) - end + @indirection.expire("/my/key") + end - it "should use the terminus name provided by passing the key to the :select_terminus hook when testing if a cached instance is up to date" do - @indirection.cache_class = :cache + it "should log that it is expiring any found instance" do + @cache.expects(:find).returns @cached + @cache.stubs(:save) - @other_terminus.expects(:version).with(@uri).returns(2.0) + Puppet.expects(:info) - @cache_terminus.expects(:has_most_recent?).with(@uri, 2.0).returns(true) - @cache_terminus.expects(:find).returns(:whatever) + @indirection.expire("/my/key") + end - @indirection.find(@uri).should == :whatever - end + it "should set the cached instance's expiration to a time in the past" do + @cache.expects(:find).returns @cached + @cache.stubs(:save) - it "should pass all arguments to the :select_terminus hook" do - @indirection.expects(:select_terminus).with(@uri, :node => "johnny").returns(:other) - @other_terminus.stubs(:find) + @cached.expects(:expiration=).with { |t| t < Time.now } - @indirection.find(@uri, :node => "johnny") - end + @indirection.expire("/my/key") + end - it "should pass the original key to the terminus rather than a modified key" do - # This is the same test as before - @other_terminus.expects(:find).with(@uri).returns(@result) - @indirection.find(@uri) - end + it "should save the now expired instance back into the cache" do + @cache.expects(:find).returns @cached - after do - @indirection.delete if defined? @indirection - end -end + @cached.expects(:expiration=).with { |t| t < Time.now } -describe Puppet::Indirector::Indirection, " when managing terminus instances" do - before do - @indirection = Puppet::Indirector::Indirection.new(mock('model'), :test) - @terminus = mock 'terminus' - @terminus_class = mock 'terminus class' - Puppet::Indirector::Terminus.stubs(:terminus_class).with(:test, :foo).returns(@terminus_class) - end + @cache.expects(:save) - it "should create an instance of the chosen terminus class" do - @terminus_class.stubs(:new).returns(@terminus) - @indirection.terminus(:foo).should equal(@terminus) - end + @indirection.expire("/my/key") + end - it "should allow the clearance of cached terminus instances" do - terminus1 = mock 'terminus1' - terminus2 = mock 'terminus2' - @terminus_class.stubs(:new).returns(terminus1, terminus2, ArgumentError) - @indirection.terminus(:foo).should equal(terminus1) - @indirection.class.clear_cache - @indirection.terminus(:foo).should equal(terminus2) - end + it "should use a request to save the expired resource to the cache" do + @cache.expects(:find).returns @cached - # Make sure it caches the terminus. - it "should return the same terminus instance each time for a given name" do - @terminus_class.stubs(:new).returns(@terminus) - @indirection.terminus(:foo).should equal(@terminus) - @indirection.terminus(:foo).should equal(@terminus) - end + @cached.expects(:expiration=).with { |t| t < Time.now } - it "should not create a terminus instance until one is actually needed" do - Puppet::Indirector.expects(:terminus).never - indirection = Puppet::Indirector::Indirection.new(mock('model'), :lazytest) - end + @cache.expects(:save).with { |r| r.is_a?(Puppet::Indirector::Request) and r.instance == @cached and r.method == :save }.returns(@cached) - after do - @indirection.delete - Puppet::Indirector::Indirection.clear_cache - end -end + @indirection.expire("/my/key") + end + end + end -describe Puppet::Indirector::Indirection, " when deciding whether to cache" do - before do - @indirection = Puppet::Indirector::Indirection.new(mock('model'), :test) - @terminus = mock 'terminus' - @terminus_class = mock 'terminus class' - @terminus_class.stubs(:new).returns(@terminus) - Puppet::Indirector::Terminus.stubs(:terminus_class).with(:test, :foo).returns(@terminus_class) - @indirection.terminus_class = :foo + after :each do + @indirection.delete + Puppet::Indirector::Indirection.clear_cache + end end - it "should provide a method for setting the cache terminus class" do - @indirection.should respond_to(:cache_class=) - end - it "should fail to cache if no cache type has been specified" do - proc { @indirection.cache }.should raise_error(Puppet::DevError) - end + describe "when managing indirection instances" do + it "should allow an indirection to be retrieved by name" do + @indirection = Puppet::Indirector::Indirection.new(mock('model'), :test) + Puppet::Indirector::Indirection.instance(:test).should equal(@indirection) + end + + it "should return nil when the named indirection has not been created" do + Puppet::Indirector::Indirection.instance(:test).should be_nil + end - it "should fail to set the cache class when the cache class name is an empty string" do - proc { @indirection.cache_class = "" }.should raise_error(ArgumentError) - end + it "should allow an indirection's model to be retrieved by name" do + mock_model = mock('model') + @indirection = Puppet::Indirector::Indirection.new(mock_model, :test) + Puppet::Indirector::Indirection.model(:test).should equal(mock_model) + end + + it "should return nil when no model matches the requested name" do + Puppet::Indirector::Indirection.model(:test).should be_nil + end - it "should fail to set the cache class when the cache class name is nil" do - proc { @indirection.cache_class = nil }.should raise_error(ArgumentError) + after do + @indirection.delete if defined? @indirection + end end - it "should fail to set the cache class when the specified cache class cannot be found" do - Puppet::Indirector::Terminus.expects(:terminus_class).with(:test, :foo).returns(nil) - proc { @indirection.cache_class = :foo }.should raise_error(ArgumentError) - end + describe "when routing to the correct the terminus class" do + before do + @indirection = Puppet::Indirector::Indirection.new(mock('model'), :test) + @terminus = mock 'terminus' + @terminus_class = stub 'terminus class', :new => @terminus + Puppet::Indirector::Terminus.stubs(:terminus_class).with(:test, :default).returns(@terminus_class) + end - after do - @indirection.delete - Puppet::Indirector::Indirection.clear_cache - end -end + it "should fail if no terminus class can be picked" do + proc { @indirection.terminus_class }.should raise_error(Puppet::DevError) + end -describe Puppet::Indirector::Indirection do - before :each do - Puppet.settings.stubs(:value).with("test_terminus").returns("test_terminus") - @terminus_class = mock 'terminus_class' - @terminus = mock 'terminus' - @terminus_class.stubs(:new).returns(@terminus) - @cache = mock 'cache' - @cache_class = mock 'cache_class' - Puppet::Indirector::Terminus.stubs(:terminus_class).with(:test, :cache_terminus).returns(@cache_class) - Puppet::Indirector::Terminus.stubs(:terminus_class).with(:test, :test_terminus).returns(@terminus_class) - @indirection = Puppet::Indirector::Indirection.new(mock('model'), :test) - @indirection.terminus_class = :test_terminus + it "should choose the default terminus class if one is specified" do + @indirection.terminus_class = :default + @indirection.terminus_class.should equal(:default) + end + + it "should use the provided Puppet setting if told to do so" do + Puppet::Indirector::Terminus.stubs(:terminus_class).with(:test, :my_terminus).returns(mock("terminus_class2")) + Puppet.settings.expects(:value).with(:my_setting).returns("my_terminus") + @indirection.terminus_setting = :my_setting + @indirection.terminus_class.should equal(:my_terminus) + end + + it "should fail if the provided terminus class is not valid" do + Puppet::Indirector::Terminus.stubs(:terminus_class).with(:test, :nosuchclass).returns(nil) + proc { @indirection.terminus_class = :nosuchclass }.should raise_error(ArgumentError) + end + + after do + @indirection.delete if defined? @indirection + end end - describe Puppet::Indirector::Indirection, " when managing the cache terminus" do + describe "when specifying the terminus class to use" do + before do + @indirection = Puppet::Indirector::Indirection.new(mock('model'), :test) + @terminus = mock 'terminus' + @terminus_class = stub 'terminus class', :new => @terminus + end + + it "should allow specification of a terminus type" do + @indirection.should respond_to(:terminus_class=) + end - it "should not create a cache terminus at initialization" do - # This is weird, because all of the code is in the setup. If we got - # new() called on the cache class, we'd get an exception here. + it "should fail to redirect if no terminus type has been specified" do + proc { @indirection.find("blah") }.should raise_error(Puppet::DevError) end - it "should reuse the cache terminus" do - @cache_class.expects(:new).returns(@cache) - Puppet.settings.stubs(:value).with("test_cache").returns("cache_terminus") - @indirection.cache_class = :cache_terminus - @indirection.cache.should equal(@cache) - @indirection.cache.should equal(@cache) + it "should fail when the terminus class name is an empty string" do + proc { @indirection.terminus_class = "" }.should raise_error(ArgumentError) end - it "should remove the cache terminus when all other terminus instances are cleared" do - cache2 = mock 'cache2' - @cache_class.stubs(:new).returns(@cache, cache2) - @indirection.cache_class = :cache_terminus - @indirection.cache.should equal(@cache) - @indirection.clear_cache - @indirection.cache.should equal(cache2) + it "should fail when the terminus class name is nil" do + proc { @indirection.terminus_class = nil }.should raise_error(ArgumentError) end - end - describe Puppet::Indirector::Indirection, " when saving and using a cache" do + it "should fail when the specified terminus class cannot be found" do + Puppet::Indirector::Terminus.expects(:terminus_class).with(:test, :foo).returns(nil) + proc { @indirection.terminus_class = :foo }.should raise_error(ArgumentError) + end - before do - @indirection.cache_class = :cache_terminus - @cache_class.expects(:new).returns(@cache) - @name = "testing" - @instance = stub 'instance', :version => 5, :name => @name + it "should select the specified terminus class if a terminus class name is provided" do + Puppet::Indirector::Terminus.expects(:terminus_class).with(:test, :foo).returns(@terminus_class) + @indirection.terminus(:foo).should equal(@terminus) end - it "should not update the cache or terminus if the new object is not different" do - @cache.expects(:has_most_recent?).with(@name, 5).returns(true) - @indirection.save(@instance) + it "should use the configured terminus class if no terminus name is specified" do + Puppet::Indirector::Terminus.stubs(:terminus_class).with(:test, :foo).returns(@terminus_class) + @indirection.terminus_class = :foo + @indirection.terminus().should equal(@terminus) end - it "should update the original and the cache if the cached object is different" do - @cache.expects(:has_most_recent?).with(@name, 5).returns(false) - @terminus.expects(:save).with(@instance) - @cache.expects(:save).with(@instance) - @indirection.save(@instance) + after do + @indirection.delete if defined? @indirection end end - - describe Puppet::Indirector::Indirection, " when finding and using a cache" do + describe "when managing terminus instances" do before do - @indirection.cache_class = :cache_terminus - @cache_class.expects(:new).returns(@cache) + @indirection = Puppet::Indirector::Indirection.new(mock('model'), :test) + @terminus = mock 'terminus' + @terminus_class = mock 'terminus class' + Puppet::Indirector::Terminus.stubs(:terminus_class).with(:test, :foo).returns(@terminus_class) + end + + it "should create an instance of the chosen terminus class" do + @terminus_class.stubs(:new).returns(@terminus) + @indirection.terminus(:foo).should equal(@terminus) end - it "should return the cached object if the cache is up to date" do - cached = mock 'cached object' + it "should allow the clearance of cached terminus instances" do + terminus1 = mock 'terminus1' + terminus2 = mock 'terminus2' + @terminus_class.stubs(:new).returns(terminus1, terminus2, ArgumentError) + @indirection.terminus(:foo).should equal(terminus1) + @indirection.class.clear_cache + @indirection.terminus(:foo).should equal(terminus2) + end - name = "myobject" + # Make sure it caches the terminus. + it "should return the same terminus instance each time for a given name" do + @terminus_class.stubs(:new).returns(@terminus) + @indirection.terminus(:foo).should equal(@terminus) + @indirection.terminus(:foo).should equal(@terminus) + end - @terminus.expects(:version).with(name).returns(1) - @cache.expects(:has_most_recent?).with(name, 1).returns(true) + it "should not create a terminus instance until one is actually needed" do + Puppet::Indirector.expects(:terminus).never + indirection = Puppet::Indirector::Indirection.new(mock('model'), :lazytest) + end - @cache.expects(:find).with(name).returns(cached) + after do + @indirection.delete + Puppet::Indirector::Indirection.clear_cache + end + end + + describe "when deciding whether to cache" do + before do + @indirection = Puppet::Indirector::Indirection.new(mock('model'), :test) + @terminus = mock 'terminus' + @terminus_class = mock 'terminus class' + @terminus_class.stubs(:new).returns(@terminus) + Puppet::Indirector::Terminus.stubs(:terminus_class).with(:test, :foo).returns(@terminus_class) + @indirection.terminus_class = :foo + end - @indirection.find(name).should equal(cached) + it "should provide a method for setting the cache terminus class" do + @indirection.should respond_to(:cache_class=) end - it "should return the original object if the cache is not up to date" do - real = stub 'real object', :version => 1 + it "should fail to cache if no cache type has been specified" do + proc { @indirection.cache }.should raise_error(Puppet::DevError) + end - name = "myobject" + it "should fail to set the cache class when the cache class name is an empty string" do + proc { @indirection.cache_class = "" }.should raise_error(ArgumentError) + end - @cache.stubs(:save) - @cache.expects(:has_most_recent?).with(name, 1).returns(false) - @terminus.expects(:version).with(name).returns(1) + it "should fail to set the cache class when the cache class name is nil" do + proc { @indirection.cache_class = nil }.should raise_error(ArgumentError) + end - @terminus.expects(:find).with(name).returns(real) + it "should fail to set the cache class when the specified cache class cannot be found" do + Puppet::Indirector::Terminus.expects(:terminus_class).with(:test, :foo).returns(nil) + proc { @indirection.cache_class = :foo }.should raise_error(ArgumentError) + end - @indirection.find(name).should equal(real) + after do + @indirection.delete + Puppet::Indirector::Indirection.clear_cache end + end - it "should cache any newly returned objects" do - real = stub 'real object', :version => 1 + describe "when using a cache" do + before :each do + Puppet.settings.stubs(:value).with("test_terminus").returns("test_terminus") + @terminus_class = mock 'terminus_class' + @terminus = mock 'terminus' + @terminus_class.stubs(:new).returns(@terminus) + @cache = mock 'cache' + @cache_class = mock 'cache_class' + Puppet::Indirector::Terminus.stubs(:terminus_class).with(:test, :cache_terminus).returns(@cache_class) + Puppet::Indirector::Terminus.stubs(:terminus_class).with(:test, :test_terminus).returns(@terminus_class) + @indirection = Puppet::Indirector::Indirection.new(mock('model'), :test) + @indirection.terminus_class = :test_terminus + end - name = "myobject" + describe "and managing the cache terminus" do + it "should not create a cache terminus at initialization" do + # This is weird, because all of the code is in the setup. If we got + # new() called on the cache class, we'd get an exception here. + end - @terminus.expects(:version).with(name).returns(1) - @cache.expects(:has_most_recent?).with(name, 1).returns(false) + it "should reuse the cache terminus" do + @cache_class.expects(:new).returns(@cache) + Puppet.settings.stubs(:value).with("test_cache").returns("cache_terminus") + @indirection.cache_class = :cache_terminus + @indirection.cache.should equal(@cache) + @indirection.cache.should equal(@cache) + end - @terminus.expects(:find).with(name).returns(real) - @cache.expects(:save).with(real) + it "should remove the cache terminus when all other terminus instances are cleared" do + cache2 = mock 'cache2' + @cache_class.stubs(:new).returns(@cache, cache2) + @indirection.cache_class = :cache_terminus + @indirection.cache.should equal(@cache) + @indirection.clear_cache + @indirection.cache.should equal(cache2) + end + end - @indirection.find(name).should equal(real) + describe "and saving" do + end + + describe "and finding" do + end + + after :each do + @indirection.delete + Puppet::Indirector::Indirection.clear_cache end - end - - after :each do - @indirection.delete - Puppet::Indirector::Indirection.clear_cache end end diff --git a/spec/unit/indirector/ldap.rb b/spec/unit/indirector/ldap.rb index 6712ccb4f..2599bcecf 100755 --- a/spec/unit/indirector/ldap.rb +++ b/spec/unit/indirector/ldap.rb @@ -24,11 +24,13 @@ describe Puppet::Indirector::Ldap, " when searching ldap" do @searcher.stubs(:search_filter).returns(:filter) @searcher.stubs(:search_base).returns(:base) @searcher.stubs(:process) + + @request = stub 'request', :key => "yay" end it "should call the ldapsearch method with the name being searched for" do @searcher.expects(:ldapsearch).with("yay") - @searcher.find "yay" + @searcher.find @request end it "should fail if no block is passed to the ldapsearch method" do @@ -41,7 +43,7 @@ describe Puppet::Indirector::Ldap, " when searching ldap" do args[0].should == "mybase" true end - @searcher.find "yay" + @searcher.find @request end it "should default to the value of the :search_base setting as the result of the ldapbase method" do @@ -56,7 +58,7 @@ describe Puppet::Indirector::Ldap, " when searching ldap" do args[3].should == :myattrs true end - @searcher.find "yay" + @searcher.find @request end it "should use the results of the :search_filter method as the search filter" do @@ -65,7 +67,7 @@ describe Puppet::Indirector::Ldap, " when searching ldap" do args[2].should == "yay's filter" true end - @searcher.find "yay" + @searcher.find @request end it "should use depth 2 when searching" do @@ -73,13 +75,13 @@ describe Puppet::Indirector::Ldap, " when searching ldap" do args[1].should == 2 true end - @searcher.find "yay" + @searcher.find @request end it "should call process() on the first found entry" do @connection.expects(:search).yields("myresult") @searcher.expects(:process).with("yay", "myresult") - @searcher.find "yay" + @searcher.find @request end it "should reconnect and retry the search if there is a failure" do @@ -94,7 +96,7 @@ describe Puppet::Indirector::Ldap, " when searching ldap" do end.yields("myresult") @searcher.expects(:process).with("yay", "myresult") - @searcher.find "yay" + @searcher.find @request end it "should not reconnect on failure more than once" do @@ -103,7 +105,7 @@ describe Puppet::Indirector::Ldap, " when searching ldap" do count += 1 raise ArgumentError, "yay" end - proc { @searcher.find("whatever") }.should raise_error(Puppet::Error) + proc { @searcher.find(@request) }.should raise_error(Puppet::Error) count.should == 2 end diff --git a/spec/unit/indirector/memory.rb b/spec/unit/indirector/memory.rb index c0fca6bd9..3b754a1eb 100755 --- a/spec/unit/indirector/memory.rb +++ b/spec/unit/indirector/memory.rb @@ -3,33 +3,7 @@ require File.dirname(__FILE__) + '/../../spec_helper' require 'puppet/indirector/memory' -describe "A Memory Terminus", :shared => true do - it "should find no instances by default" do - @searcher.find(@name).should be_nil - end - - it "should be able to find instances that were previously saved" do - @searcher.save(@instance) - @searcher.find(@name).should equal(@instance) - end - - it "should replace existing saved instances when a new instance with the same name is saved" do - @searcher.save(@instance) - two = stub 'second', :name => @name - @searcher.save(two) - @searcher.find(@name).should equal(two) - end - - it "should be able to remove previously saved instances" do - @searcher.save(@instance) - @searcher.destroy(@instance) - @searcher.find(@name).should be_nil - end - - it "should fail when asked to destroy an instance that does not exist" do - proc { @searcher.destroy(@instance) }.should raise_error(ArgumentError) - end -end +require 'shared_behaviours/memory_terminus' describe Puppet::Indirector::Memory do it_should_behave_like "A Memory Terminus" @@ -49,5 +23,7 @@ describe Puppet::Indirector::Memory do @searcher = @memory_class.new @name = "me" @instance = stub 'instance', :name => @name + + @request = stub 'request', :key => @name, :instance => @instance end end diff --git a/spec/unit/indirector/node/exec.rb b/spec/unit/indirector/node/exec.rb index b67e0fe97..09f13ab90 100755 --- a/spec/unit/indirector/node/exec.rb +++ b/spec/unit/indirector/node/exec.rb @@ -11,12 +11,6 @@ describe Puppet::Node::Exec do @searcher = Puppet::Node::Exec.new end - it "should use the version of the facts as its version" do - version = mock 'version' - Puppet::Node::Facts.expects(:version).with("me").returns version - @searcher.version("me").should equal(version) - end - describe "when constructing the command to run" do it "should use the external_node script as the command" do Puppet.expects(:[]).with(:external_nodes).returns("/bin/echo") @@ -25,7 +19,7 @@ describe Puppet::Node::Exec do it "should throw an exception if no external node command is set" do Puppet.expects(:[]).with(:external_nodes).returns("none") - proc { @searcher.find("foo") }.should raise_error(ArgumentError) + proc { @searcher.find(stub('request', :key => "foo")) }.should raise_error(ArgumentError) end end @@ -40,34 +34,36 @@ describe Puppet::Node::Exec do @searcher.meta_def(:execute) do |command| return YAML.dump(result) end + + @request = stub 'request', :key => @name end it "should translate the YAML into a Node instance" do # Use an empty hash - @searcher.find(@name).should equal(@node) + @searcher.find(@request).should equal(@node) end it "should set the resulting parameters as the node parameters" do @result[:parameters] = {"a" => "b", "c" => "d"} @node.expects(:parameters=).with "a" => "b", "c" => "d" - @searcher.find(@name) + @searcher.find(@request) end it "should set the resulting classes as the node classes" do @result[:classes] = %w{one two} @node.expects(:classes=).with %w{one two} - @searcher.find(@name) + @searcher.find(@request) end it "should merge the node's facts with its parameters" do @node.expects(:fact_merge) - @searcher.find(@name) + @searcher.find(@request) end it "should set the node's environment if one is provided" do @result[:environment] = "yay" @node.expects(:environment=).with "yay" - @searcher.find(@name) + @searcher.find(@request) end end end diff --git a/spec/unit/indirector/node/ldap.rb b/spec/unit/indirector/node/ldap.rb index 34456703d..a40698662 100755 --- a/spec/unit/indirector/node/ldap.rb +++ b/spec/unit/indirector/node/ldap.rb @@ -5,13 +5,6 @@ require File.dirname(__FILE__) + '/../../../spec_helper' require 'puppet/indirector/node/ldap' describe Puppet::Node::Ldap do - it "should use the version of the facts as its version" do - @searcher = Puppet::Node::Ldap.new - version = mock 'version' - Puppet::Node::Facts.expects(:version).with("me").returns version - @searcher.version("me").should equal(version) - end - describe "when searching for nodes" do before :each do @searcher = Puppet::Node::Ldap.new @@ -31,16 +24,18 @@ describe Puppet::Node::Ldap do @node.stubs(:fact_merge) @name = "mynode" Puppet::Node.stubs(:new).with(@name).returns(@node) + + @request = stub 'request', :key => @name end it "should return nil if no results are found in ldap" do @connection.stubs(:search) - @searcher.find("mynode").should be_nil + @searcher.find(@request).should be_nil end it "should return a node object if results are found in ldap" do @entry.stubs(:to_hash).returns({}) - @searcher.find("mynode").should equal(@node) + @searcher.find(@request).should equal(@node) end it "should deduplicate class values" do @@ -49,7 +44,7 @@ describe Puppet::Node::Ldap do @entry.stubs(:vals).with("one").returns(%w{a b}) @entry.stubs(:vals).with("two").returns(%w{b c}) @node.expects(:classes=).with(%w{a b c}) - @searcher.find("mynode") + @searcher.find(@request) end it "should add any values stored in the class_attributes attributes to the node classes" do @@ -58,38 +53,38 @@ describe Puppet::Node::Ldap do @entry.stubs(:vals).with("one").returns(%w{a b}) @entry.stubs(:vals).with("two").returns(%w{c d}) @node.expects(:classes=).with(%w{a b c d}) - @searcher.find("mynode") + @searcher.find(@request) end it "should add all entry attributes as node parameters" do @entry.stubs(:to_hash).returns("one" => ["two"], "three" => ["four"]) @node.expects(:parameters=).with("one" => "two", "three" => "four") - @searcher.find("mynode") + @searcher.find(@request) end it "should set the node's environment to the environment of the results" do @entry.stubs(:to_hash).returns("environment" => ["test"]) @node.stubs(:parameters=) @node.expects(:environment=).with("test") - @searcher.find("mynode") + @searcher.find(@request) end it "should retain false parameter values" do @entry.stubs(:to_hash).returns("one" => [false]) @node.expects(:parameters=).with("one" => false) - @searcher.find("mynode") + @searcher.find(@request) end it "should turn single-value parameter value arrays into single non-arrays" do @entry.stubs(:to_hash).returns("one" => ["a"]) @node.expects(:parameters=).with("one" => "a") - @searcher.find("mynode") + @searcher.find(@request) end it "should keep multi-valued parametes as arrays" do @entry.stubs(:to_hash).returns("one" => ["a", "b"]) @node.expects(:parameters=).with("one" => ["a", "b"]) - @searcher.find("mynode") + @searcher.find(@request) end describe "and a parent node is specified" do @@ -113,7 +108,7 @@ describe Puppet::Node::Ldap do @entry.stubs(:to_hash).returns({}) @entry.stubs(:vals).with(:parent).returns(%w{parent}) - proc { @searcher.find("mynode") }.should raise_error(Puppet::Error) + proc { @searcher.find(@request) }.should raise_error(Puppet::Error) end it "should add any parent classes to the node's classes" do @@ -127,7 +122,7 @@ describe Puppet::Node::Ldap do @searcher.stubs(:class_attributes).returns(%w{classes}) @node.expects(:classes=).with(%w{a b c d}) - @searcher.find("mynode") + @searcher.find(@request) end it "should add any parent parameters to the node's parameters" do @@ -138,7 +133,7 @@ describe Puppet::Node::Ldap do @parent.stubs(:vals).with(:parent).returns(nil) @node.expects(:parameters=).with("one" => "two", "three" => "four") - @searcher.find("mynode") + @searcher.find(@request) end it "should prefer node parameters over parent parameters" do @@ -149,7 +144,7 @@ describe Puppet::Node::Ldap do @parent.stubs(:vals).with(:parent).returns(nil) @node.expects(:parameters=).with("one" => "two") - @searcher.find("mynode") + @searcher.find(@request) end it "should use the parent's environment if the node has none" do @@ -161,7 +156,7 @@ describe Puppet::Node::Ldap do @node.stubs(:parameters=) @node.expects(:environment=).with("parent") - @searcher.find("mynode") + @searcher.find(@request) end it "should prefer the node's environment to the parent's" do @@ -173,7 +168,7 @@ describe Puppet::Node::Ldap do @node.stubs(:parameters=) @node.expects(:environment=).with("child") - @searcher.find("mynode") + @searcher.find(@request) end it "should recursively look up parent information" do @@ -188,7 +183,7 @@ describe Puppet::Node::Ldap do @parent_parent.stubs(:vals).with(:parent).returns(nil) @node.expects(:parameters=).with("one" => "two", "three" => "four", "five" => "six") - @searcher.find("mynode") + @searcher.find(@request) end it "should not allow loops in parent declarations" do @@ -197,7 +192,7 @@ describe Puppet::Node::Ldap do @parent.stubs(:to_hash).returns("three" => "four") @parent.stubs(:vals).with(:parent).returns([@name]) - proc { @searcher.find("mynode") }.should raise_error(ArgumentError) + proc { @searcher.find(@request) }.should raise_error(ArgumentError) end end end diff --git a/spec/unit/indirector/node/memory.rb b/spec/unit/indirector/node/memory.rb index a924c6209..71e01d4f3 100755 --- a/spec/unit/indirector/node/memory.rb +++ b/spec/unit/indirector/node/memory.rb @@ -4,14 +4,15 @@ require File.dirname(__FILE__) + '/../../../spec_helper' require 'puppet/indirector/node/memory' -# All of our behaviour is described here, so we always have to include it. -require File.dirname(__FILE__) + '/../memory' +require 'shared_behaviours/memory_terminus' describe Puppet::Node::Memory do before do @name = "me" @searcher = Puppet::Node::Memory.new @instance = stub 'instance', :name => @name + + @request = stub 'request', :key => @name, :instance => @instance end it_should_behave_like "A Memory Terminus" diff --git a/spec/unit/indirector/node/plain.rb b/spec/unit/indirector/node/plain.rb index 943af52b4..a595998a1 100755 --- a/spec/unit/indirector/node/plain.rb +++ b/spec/unit/indirector/node/plain.rb @@ -13,12 +13,7 @@ describe Puppet::Node::Plain do node = mock 'node' Puppet::Node.expects(:new).with("mynode").returns(node) node.expects(:fact_merge) - @searcher.find("mynode") - end - - it "should use the version of the facts as its version" do - version = mock 'version' - Puppet::Node::Facts.expects(:version).with("me").returns version - @searcher.version("me").should equal(version) + request = stub 'request', :key => "mynode" + @searcher.find(request) end end diff --git a/spec/unit/indirector/plain.rb b/spec/unit/indirector/plain.rb index 1277739af..aca2816f2 100755 --- a/spec/unit/indirector/plain.rb +++ b/spec/unit/indirector/plain.rb @@ -17,11 +17,13 @@ describe Puppet::Indirector::Plain do end @searcher = @plain_class.new + + @request = stub 'request', :key => "yay" end it "should return return an instance of the indirected model" do object = mock 'object' - @model.expects(:new).with("yay").returns object - @searcher.find("yay").should equal(object) + @model.expects(:new).with(@request.key).returns object + @searcher.find(@request).should equal(object) end end diff --git a/spec/unit/indirector/report/processor.rb b/spec/unit/indirector/report/processor.rb index 587f512ee..bcb400bda 100755 --- a/spec/unit/indirector/report/processor.rb +++ b/spec/unit/indirector/report/processor.rb @@ -13,7 +13,6 @@ describe Puppet::Transaction::Report::Processor do end end - describe Puppet::Transaction::Report::Processor, " when saving a report" do before do Puppet.settings.stubs(:use) @@ -24,7 +23,9 @@ describe Puppet::Transaction::Report::Processor, " when saving a report" do Puppet::Reports.expects(:report).never Puppet.settings.expects(:value).with(:reports).returns("none") - @reporter.save(:whatever) + request = stub 'request', :instance => mock("report") + + @reporter.save(request) end it "should process the report with each configured report type" do @@ -44,6 +45,9 @@ describe Puppet::Transaction::Report::Processor, " when processing a report" do @dup_report.stubs(:process) @report = mock 'report' @report.expects(:dup).returns(@dup_report) + + @request = stub 'request', :instance => @report + Puppet::Reports.expects(:report).with("one").returns(@report_type) @dup_report.expects(:extend).with(@report_type) @@ -53,21 +57,21 @@ describe Puppet::Transaction::Report::Processor, " when processing a report" do # make sense to split it out, which means I just do the same test # three times so the spec looks right. it "should process a duplicate of the report, not the original" do - @reporter.save(@report) + @reporter.save(@request) end it "should extend the report with the report type's module" do - @reporter.save(@report) + @reporter.save(@request) end it "should call the report type's :process method" do @dup_report.expects(:process) - @reporter.save(@report) + @reporter.save(@request) end it "should not raise exceptions" do Puppet.settings.stubs(:value).with(:trace).returns(false) @dup_report.expects(:process).raises(ArgumentError) - proc { @reporter.save(@report) }.should_not raise_error + proc { @reporter.save(@request) }.should_not raise_error end end diff --git a/spec/unit/indirector/request.rb b/spec/unit/indirector/request.rb new file mode 100755 index 000000000..cdb40b181 --- /dev/null +++ b/spec/unit/indirector/request.rb @@ -0,0 +1,55 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../spec_helper' +require 'puppet/indirector/request' + +describe Puppet::Indirector::Request do + describe "when initializing" do + it "should require an indirection name, a key, and a method" do + lambda { Puppet::Indirector::Request.new }.should raise_error(ArgumentError) + end + + it "should use provided value as the key if it is a string" do + Puppet::Indirector::Request.new(:ind, :method, "mykey").key.should == "mykey" + end + + it "should use provided value as the key if it is a symbol" do + Puppet::Indirector::Request.new(:ind, :method, :mykey).key.should == :mykey + end + + it "should use the name of the provided instance as its key if an instance is provided as the key instead of a string" do + instance = mock 'instance', :name => "mykey" + request = Puppet::Indirector::Request.new(:ind, :method, instance) + request.key.should == "mykey" + request.instance.should equal(instance) + end + + it "should support options specified as a hash" do + lambda { Puppet::Indirector::Request.new(:ind, :method, :key, :one => :two) }.should_not raise_error(ArgumentError) + end + + it "should support nil options" do + lambda { Puppet::Indirector::Request.new(:ind, :method, :key, nil) }.should_not raise_error(ArgumentError) + end + + it "should support unspecified options" do + lambda { Puppet::Indirector::Request.new(:ind, :method, :key) }.should_not raise_error(ArgumentError) + end + + it "should fail if options are specified as anything other than nil or a hash" do + lambda { Puppet::Indirector::Request.new(:ind, :method, :key, [:one, :two]) }.should raise_error(ArgumentError) + end + + it "should use an empty options hash if nil was provided" do + Puppet::Indirector::Request.new(:ind, :method, :key, nil).options.should == {} + end + end + + it "should look use the Indirection class to return the appropriate indirection" do + ind = mock 'indirection' + Puppet::Indirector::Indirection.expects(:instance).with(:myind).returns ind + request = Puppet::Indirector::Request.new(:myind, :method, :key) + + request.indirection.should equal(ind) + end +end diff --git a/spec/unit/indirector/terminus.rb b/spec/unit/indirector/terminus.rb index 86813e4e5..3fcbf9d0c 100755 --- a/spec/unit/indirector/terminus.rb +++ b/spec/unit/indirector/terminus.rb @@ -106,60 +106,6 @@ describe Puppet::Indirector::Terminus do @terminus.model.should == :yay end end - - describe Puppet::Indirector::Terminus, " when managing indirected instances" do - - it "should support comparing an instance's version with the terminus's version using just the instance's key" do - @terminus.should respond_to(:has_most_recent?) - end - - it "should fail if the :version method has not been overridden and no :find method is available" do - proc { @terminus.version('yay') }.should raise_error(Puppet::DevError) - end - - it "should use a found instance's version by default" do - name = 'instance' - instance = stub name, :version => 2 - @terminus.expects(:find).with(name).returns(instance) - @terminus.version(name).should == 2 - end - - it "should return nil as the version if no instance can be found" do - name = 'instance' - @terminus.expects(:find).with(name).returns(nil) - @terminus.version(name).should be_nil - end - - it "should consider an instance fresh if its version is more recent than the version provided" do - name = "yay" - @terminus.expects(:version).with(name).returns(5) - @terminus.has_most_recent?(name, 4).should be_true - end - - it "should consider an instance fresh if its version is equal to the version provided" do - name = "yay" - @terminus.expects(:version).with(name).returns(5) - @terminus.has_most_recent?(name, 5).should be_true - end - - it "should consider an instance not fresh if the provided version is more recent than its version" do - name = "yay" - @terminus.expects(:version).with(name).returns(4) - @terminus.has_most_recent?(name, 5).should be_false - end - - # Times annoyingly can't be compared directly to numbers, and our - # default version is 0. - it "should convert versions to floats when checking for freshness" do - existing = mock 'existing version' - new = mock 'new version' - existing.expects(:to_f).returns(1.0) - new.expects(:to_f).returns(1.0) - name = "yay" - @terminus.expects(:version).with(name).returns(existing) - @terminus.has_most_recent?(name, new) - end - end end # LAK: This could reasonably be in the Indirection instances, too. It doesn't make diff --git a/spec/unit/indirector/yaml.rb b/spec/unit/indirector/yaml.rb index 339529ab0..53d12f426 100755 --- a/spec/unit/indirector/yaml.rb +++ b/spec/unit/indirector/yaml.rb @@ -21,37 +21,28 @@ describe Puppet::Indirector::Yaml, " when choosing file location" do @dir = "/what/ever" Puppet.settings.stubs(:value).with(:yamldir).returns(@dir) - end - - it "should use the mtime of the written file as the version" do - stat = mock 'stat' - FileTest.stubs(:exist?).returns true - File.expects(:stat).returns stat - time = Time.now - stat.expects(:mtime).returns time - @store.version(:me).should equal(time) + @request = stub 'request', :key => :me, :instance => @subject end describe Puppet::Indirector::Yaml, " when choosing file location" do - it "should store all files in a single file root set in the Puppet defaults" do - @store.send(:path, :me).should =~ %r{^#{@dir}} + @store.path(:me).should =~ %r{^#{@dir}} end it "should use the terminus name for choosing the subdirectory" do - @store.send(:path, :me).should =~ %r{^#{@dir}/my_yaml} + @store.path(:me).should =~ %r{^#{@dir}/my_yaml} end it "should use the object's name to determine the file name" do - @store.send(:path, :me).should =~ %r{me.yaml$} + @store.path(:me).should =~ %r{me.yaml$} end end describe Puppet::Indirector::Yaml, " when storing objects as YAML" do - it "should only store objects that respond to :name" do - proc { @store.save(Object.new) }.should raise_error(ArgumentError) + @request.stubs(:instance).returns Object.new + proc { @store.save(@request) }.should raise_error(ArgumentError) end it "should convert Ruby objects to YAML and write them to disk" do @@ -62,7 +53,7 @@ describe Puppet::Indirector::Yaml, " when choosing file location" do File.expects(:open).with(path, "w", 0660).yields(file) file.expects(:print).with(yaml) - @store.save(@subject) + @store.save(@request) end it "should create the indirection subdirectory if it does not exist" do @@ -75,16 +66,11 @@ describe Puppet::Indirector::Yaml, " when choosing file location" do File.expects(:open).with(path, "w", 0660).yields(file) file.expects(:print).with(yaml) - @store.save(@subject) + @store.save(@request) end end describe Puppet::Indirector::Yaml, " when retrieving YAML" do - - it "should require the name of the object to retrieve" do - proc { @store.find(nil) }.should raise_error(ArgumentError) - end - it "should read YAML in from disk and convert it to Ruby objects" do path = @store.send(:path, @subject.name) @@ -92,7 +78,7 @@ describe Puppet::Indirector::Yaml, " when choosing file location" do FileTest.expects(:exist?).with(path).returns(true) File.expects(:read).with(path).returns(yaml) - @store.find(@subject.name).instance_variable_get("@name").should == :me + @store.find(@request).instance_variable_get("@name").should == :me end it "should fail coherently when the stored YAML is invalid" do @@ -104,7 +90,7 @@ describe Puppet::Indirector::Yaml, " when choosing file location" do FileTest.expects(:exist?).with(path).returns(true) File.expects(:read).with(path).returns(yaml) - proc { @store.find(@subject.name) }.should raise_error(Puppet::Error) + proc { @store.find(@request) }.should raise_error(Puppet::Error) end end end diff --git a/spec/unit/other/modules.rb b/spec/unit/module.rb index 26ca3907d..06b2d016d 100755 --- a/spec/unit/other/modules.rb +++ b/spec/unit/module.rb @@ -1,6 +1,6 @@ #!/usr/bin/env ruby -require File.dirname(__FILE__) + '/../../spec_helper' +require File.dirname(__FILE__) + '/../spec_helper' describe Puppet::Module, " when building its search path" do include PuppetTest @@ -171,6 +171,15 @@ describe Puppet::Module, " when searching for manifests in a found module" do Puppet::Module.find_manifests("mymod/yay/*.pp").should == %w{/one /two} end + it "should not return directories" do + Puppet.settings.expects(:value).with(:modulepath, nil).returns("/my/modules") + File.stubs(:directory?).returns(true) + Dir.expects(:glob).with("/my/modules/mymod/manifests/yay/*.pp").returns(%w{/one /two}) + FileTest.expects(:directory?).with("/one").returns false + FileTest.expects(:directory?).with("/two").returns true + Puppet::Module.find_manifests("mymod/yay/*.pp").should == %w{/one} + end + it "should default to the 'init.pp' file in the manifests directory" do Puppet.settings.expects(:value).with(:modulepath, nil).returns("/my/modules") File.stubs(:directory?).returns(true) diff --git a/spec/unit/network/client/master.rb b/spec/unit/network/client/master.rb index 7bf755d88..c0ad7562f 100755 --- a/spec/unit/network/client/master.rb +++ b/spec/unit/network/client/master.rb @@ -36,30 +36,6 @@ describe Puppet::Network::Client::Master, " when retrieving the catalog" do proc { @client.getconfig }.should raise_error(Puppet::Network::ClientError) end - it "should use the cached catalog if it is up to date" do - file = "/path/to/cachefile" - @client.stubs(:cachefile).returns(file) - FileTest.expects(:exist?).with(file).returns(true) - @client.expects(:fresh?).with(@facts).returns true - @client.class.stubs(:facts).returns(@facts) - @client.expects(:use_cached_config).returns(true) - Puppet.stubs(:info) - - @client.getconfig - end - - it "should log that the catalog does not need a recompile" do - file = "/path/to/cachefile" - @client.stubs(:cachefile).returns(file) - FileTest.stubs(:exist?).with(file).returns(true) - @client.stubs(:fresh?).with(@facts).returns true - @client.stubs(:use_cached_config).returns(true) - @client.class.stubs(:facts).returns(@facts) - Puppet.expects(:info).with { |m| m.include?("up to date") } - - @client.getconfig - end - it "should retrieve plugins if :pluginsync is enabled" do file = "/path/to/cachefile" @client.stubs(:cachefile).returns(file) @@ -69,7 +45,6 @@ describe Puppet::Network::Client::Master, " when retrieving the catalog" do @client.expects(:getplugins) @client.stubs(:get_actual_config).returns(nil) FileTest.stubs(:exist?).with(file).returns(true) - @client.stubs(:fresh?).with(@facts).returns true @client.stubs(:use_cached_config).returns(true) @client.class.stubs(:facts).returns(@facts) @client.getconfig diff --git a/spec/unit/node.rb b/spec/unit/node.rb index bb99378d9..348e160cf 100755 --- a/spec/unit/node.rb +++ b/spec/unit/node.rb @@ -133,9 +133,9 @@ end describe Puppet::Node, " when indirecting" do it "should redirect to the indirection" do - @indirection = mock 'indirection' + @indirection = stub 'indirection', :name => :node Puppet::Node.stubs(:indirection).returns(@indirection) - @indirection.expects(:find).with(:my_node.to_s) + @indirection.expects(:find) Puppet::Node.find(:my_node.to_s) end diff --git a/spec/unit/node/catalog.rb b/spec/unit/node/catalog.rb index d607b3540..8d7692442 100755 --- a/spec/unit/node/catalog.rb +++ b/spec/unit/node/catalog.rb @@ -794,14 +794,14 @@ end describe Puppet::Node::Catalog, " when indirecting" do before do - @indirection = mock 'indirection' + @indirection = stub 'indirection', :name => :catalog Puppet::Indirector::Indirection.clear_cache end it "should redirect to the indirection for retrieval" do Puppet::Node::Catalog.stubs(:indirection).returns(@indirection) - @indirection.expects(:find).with(:myconfig) + @indirection.expects(:find) Puppet::Node::Catalog.find(:myconfig) end diff --git a/spec/unit/node/facts.rb b/spec/unit/node/facts.rb index 743a7082e..1bfccd32e 100755 --- a/spec/unit/node/facts.rb +++ b/spec/unit/node/facts.rb @@ -6,7 +6,7 @@ require 'puppet/node/facts' describe Puppet::Node::Facts, " when indirecting" do before do - @indirection = mock 'indirection' + @indirection = stub 'indirection', :request => mock('request'), :name => :facts # We have to clear the cache so that the facts ask for our indirection stub, # instead of anything that might be cached. @@ -16,13 +16,13 @@ describe Puppet::Node::Facts, " when indirecting" do it "should redirect to the specified fact store for retrieval" do Puppet::Node::Facts.stubs(:indirection).returns(@indirection) - @indirection.expects(:find).with(:my_facts) + @indirection.expects(:find) Puppet::Node::Facts.find(:my_facts) end it "should redirect to the specified fact store for storage" do Puppet::Node::Facts.stubs(:indirection).returns(@indirection) - @indirection.expects(:save).with(@facts) + @indirection.expects(:save) @facts.save end diff --git a/spec/unit/parser/ast/node.rb b/spec/unit/parser/ast/node.rb index 757934415..aaba4c2e8 100755 --- a/spec/unit/parser/ast/node.rb +++ b/spec/unit/parser/ast/node.rb @@ -122,4 +122,4 @@ describe Puppet::Parser::AST::Node do @compiler.class_scope(@middle).namespaces.should be_include(@top.namespace) end end -end
\ No newline at end of file +end diff --git a/spec/unit/parser/resource.rb b/spec/unit/parser/resource.rb index 776e9c742..6b2021916 100755 --- a/spec/unit/parser/resource.rb +++ b/spec/unit/parser/resource.rb @@ -64,6 +64,13 @@ describe Puppet::Parser::Resource do @resource[:one].should == "yay" end + it "should have a method for converting to a ral resource" do + trans = mock 'trans', :to_type => "yay" + @resource = mkresource + @resource.expects(:to_trans).returns trans + @resource.to_type.should == "yay" + end + describe "when initializing" do before do @arguments = {:type => "resource", :title => "testing", :scope => stub('scope', :source => mock('source'))} diff --git a/spec/unit/ral/type/nagios.rb b/spec/unit/ral/type/nagios.rb index 8aca7d401..35f00b0e5 100755 --- a/spec/unit/ral/type/nagios.rb +++ b/spec/unit/ral/type/nagios.rb @@ -4,51 +4,59 @@ require File.dirname(__FILE__) + '/../../../spec_helper' require 'puppet/external/nagios' -Nagios::Base.eachtype do |name, nagios_type| - puppet_type = Puppet::Type.type("nagios_" + name.to_s) +describe "Nagios resource types" do + Nagios::Base.eachtype do |name, nagios_type| + puppet_type = Puppet::Type.type("nagios_" + name.to_s) - describe puppet_type do - it "should be defined as a Puppet resource type" do + it "should have a valid type for #{name}" do puppet_type.should_not be_nil end - it "should have documentation" do - puppet_type.instance_variable_get("@doc").should_not == "" - end + next unless puppet_type - it "should have %s as its namevar" % nagios_type.namevar do - puppet_type.namevar.should == nagios_type.namevar - end + describe puppet_type do + it "should be defined as a Puppet resource type" do + puppet_type.should_not be_nil + end - it "should have documentation for its %s parameter" % nagios_type.namevar do - puppet_type.attrclass(nagios_type.namevar).instance_variable_get("@doc").should_not be_nil - end + it "should have documentation" do + puppet_type.instance_variable_get("@doc").should_not == "" + end - it "should have an ensure property" do - puppet_type.should be_validproperty(:ensure) - end + it "should have %s as its namevar" % nagios_type.namevar do + puppet_type.namevar.should == nagios_type.namevar + end - it "should have a target property" do - puppet_type.should be_validproperty(:target) - end + it "should have documentation for its %s parameter" % nagios_type.namevar do + puppet_type.attrclass(nagios_type.namevar).instance_variable_get("@doc").should_not be_nil + end - it "should have documentation for its target property" do - puppet_type.attrclass(:target).instance_variable_get("@doc").should_not be_nil - end + it "should have an ensure property" do + puppet_type.should be_validproperty(:ensure) + end - nagios_type.parameters.reject { |param| param == nagios_type.namevar or param.to_s =~ /^[0-9]/ }.each do |param| - it "should have a %s property" % param do - puppet_type.should be_validproperty(param) + it "should have a target property" do + puppet_type.should be_validproperty(:target) end - it "should have documentation for its %s property" % param do - puppet_type.attrclass(param).instance_variable_get("@doc").should_not be_nil + it "should have documentation for its target property" do + puppet_type.attrclass(:target).instance_variable_get("@doc").should_not be_nil + end + + nagios_type.parameters.reject { |param| param == nagios_type.namevar or param.to_s =~ /^[0-9]/ }.each do |param| + it "should have a %s property" % param do + puppet_type.should be_validproperty(param) + end + + it "should have documentation for its %s property" % param do + puppet_type.attrclass(param).instance_variable_get("@doc").should_not be_nil + end end - end - nagios_type.parameters.find_all { |param| param.to_s =~ /^[0-9]/ }.each do |param| - it "should have not have a %s property" % param do - puppet_type.should_not be_validproperty(:param) + nagios_type.parameters.find_all { |param| param.to_s =~ /^[0-9]/ }.each do |param| + it "should have not have a %s property" % param do + puppet_type.should_not be_validproperty(:param) + end end end end diff --git a/spec/unit/transaction/report.rb b/spec/unit/transaction/report.rb index 8fc3f0794..644f8d709 100755 --- a/spec/unit/transaction/report.rb +++ b/spec/unit/transaction/report.rb @@ -9,18 +9,18 @@ require 'puppet/transaction/report' describe Puppet::Transaction::Report, " when being indirect" do it "should redirect :find to the indirection" do - @indirection = mock 'indirection' + @indirection = stub 'indirection', :name => :report Puppet::Transaction::Report.stubs(:indirection).returns(@indirection) - @indirection.expects(:find).with(:report) + @indirection.expects(:find) Puppet::Transaction::Report.find(:report) end it "should redirect :save to the indirection" do Facter.stubs(:value).returns("eh") - @indirection = mock 'indirection' + @indirection = stub 'indirection', :name => :report Puppet::Transaction::Report.stubs(:indirection).returns(@indirection) report = Puppet::Transaction::Report.new - @indirection.expects(:save).with(report) + @indirection.expects(:save) report.save end @@ -28,6 +28,12 @@ describe Puppet::Transaction::Report, " when being indirect" do Puppet::Transaction::Report.indirection.terminus_class.should == :processor end + it "should delegate its name attribute to its host method" do + report = Puppet::Transaction::Report.new + report.expects(:host).returns "me" + report.name.should == "me" + end + after do Puppet::Indirector::Indirection.clear_cache end diff --git a/spec/unit/util/loadedfile.rb b/spec/unit/util/loadedfile.rb new file mode 100755 index 000000000..083120e20 --- /dev/null +++ b/spec/unit/util/loadedfile.rb @@ -0,0 +1,65 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../spec_helper' + +require 'tempfile' +require 'puppet/util/loadedfile' + +describe Puppet::Util::LoadedFile do + before(:each) do + @f = Tempfile.new('loadedfile_test') + @f.puts "yayness" + @f.flush + + @loaded = Puppet::Util::LoadedFile.new(@f.path) + + fake_ctime = Time.now - (2 * Puppet[:filetimeout]) + @stat = stub('stat', :ctime => fake_ctime) + @fake_now = Time.now + (2 * Puppet[:filetimeout]) + end + + it "should recognize when the file has not changed" do + # Use fake "now" so that we can be sure changed? actually checks, without sleeping + # for Puppet[:filetimeout] seconds. + Time.stubs(:now).returns(@fake_now) + @loaded.changed?.should == false + end + + it "should recognize when the file has changed" do + # Fake File.stat so we don't have to depend on the filesystem granularity. Doing a flush() + # just didn't do the job. + File.stubs(:stat).returns(@stat) + # Use fake "now" so that we can be sure changed? actually checks, without sleeping + # for Puppet[:filetimeout] seconds. + Time.stubs(:now).returns(@fake_now) + @loaded.changed?.should be_an_instance_of(Time) + end + + it "should not catch a change until the timeout has elapsed" do + # Fake File.stat so we don't have to depend on the filesystem granularity. Doing a flush() + # just didn't do the job. + File.stubs(:stat).returns(@stat) + @loaded.changed?.should be(false) + # Use fake "now" so that we can be sure changed? actually checks, without sleeping + # for Puppet[:filetimeout] seconds. + Time.stubs(:now).returns(@fake_now) + @loaded.changed?.should_not be(false) + end + + it "should consider a file changed when that file is missing" do + @f.close! + # Use fake "now" so that we can be sure changed? actually checks, without sleeping + # for Puppet[:filetimeout] seconds. + Time.stubs(:now).returns(@fake_now) + @loaded.changed?.should_not be(false) + end + + it "should disable checking if Puppet[:filetimeout] is negative" do + Puppet[:filetimeout] = -1 + @loaded.changed?.should_not be(false) + end + + after(:each) do + @f.close + end +end |