summaryrefslogtreecommitdiffstats
path: root/spec
diff options
context:
space:
mode:
authorLuke Kanies <luke@madstop.com>2008-04-07 23:47:01 -0500
committerLuke Kanies <luke@madstop.com>2008-04-08 11:33:49 -0500
commitc6729d134b6b0479e091928ee68abb9008d0f71d (patch)
tree0fc97c75dbd946d18d8c72d3006b10bf38054ee8 /spec
parent8e1e06ff1c65bc5d8162fce41776e31b9f00d1bf (diff)
downloadpuppet-c6729d134b6b0479e091928ee68abb9008d0f71d.tar.gz
puppet-c6729d134b6b0479e091928ee68abb9008d0f71d.tar.xz
puppet-c6729d134b6b0479e091928ee68abb9008d0f71d.zip
Reworking the caching layer to use TTLs instead of versions
based on timestamps. This just modifies the indirection class itself, there is still some work to do to remove version code from other classes.
Diffstat (limited to 'spec')
-rwxr-xr-xspec/unit/indirector/indirection.rb927
1 files changed, 485 insertions, 442 deletions
diff --git a/spec/unit/indirector/indirection.rb b/spec/unit/indirector/indirection.rb
index fe456b61e..5338a4858 100755
--- a/spec/unit/indirector/indirection.rb
+++ b/spec/unit/indirector/indirection.rb
@@ -2,579 +2,622 @@
require File.dirname(__FILE__) + '/../../spec_helper'
-require 'puppet/indirector'
+require 'puppet/indirector/indirection'
+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 keep a reference to the indirecting model" do
+ model = mock 'model'
+ @indirection = Puppet::Indirector::Indirection.new(model, :myind)
+ @indirection.model.should equal(model)
+ end
-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
- end
+ it "should set the name" do
+ @indirection = Puppet::Indirector::Indirection.new(mock('model'), :myind)
+ @indirection.name.should == :myind
+ 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)
- 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)
+ end
- it "should set the name" do
- @indirection = Puppet::Indirector::Indirection.new(mock('model'), :myind)
- @indirection.name.should == :myind
- 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)
+ 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)
- end
+ it "should allow specification of supported options" do
+ lambda { @indirection = Puppet::Indirector::Indirection.new(mock('model'), :test, :options => [:one, :two]) }.should_not raise_error
+ 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)
- end
+ it "should define a new Struct class to support the specified options" do
+ struct = mock 'struct'
+ Struct.expects(:new).with(:one, :two)
+ @indirection = Puppet::Indirector::Indirection.new(mock('model'), :test, :options => [:one, :two])
+ end
- after do
- @indirection.delete if defined? @indirection
+ after do
+ @indirection.delete if defined? @indirection
+ end
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
- end
-
- describe Puppet::Indirector::Indirection, " when looking for 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)
- it "should let the appropriate terminus perform the lookup" do
- @terminus.expects(:find).with(@name).returns(@instance)
- @indirection.find(@name).should == @instance
- end
+ @indirection = Puppet::Indirector::Indirection.new(mock('model'), :test)
+ @indirection.terminus_class = :test_terminus
- 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
+ @instance = stub 'instance', :expiration => nil, :expiration= => nil, :name => "whatever"
+ @name = :mything
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 allow setting the ttl" do
+ @indirection.ttl = 300
+ @indirection.ttl.should == 300
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 default to the :runinterval setting, converted to an integer, for its ttl" do
+ Puppet.settings.expects(:value).returns "1800"
+ @indirection.ttl.should == 1800
end
- end
-
- describe Puppet::Indirector::Indirection, " when searching for multiple model instances" do
- 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 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
+
+ describe "and 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 pass the instances to the :post_search hook if there is one" do
- class << @terminus
- def post_search
- end
+ it "should return nil if nothing is returned by the terminus" do
+ @terminus.expects(:find).with(@name).returns(nil)
+ @indirection.find(@name).should be_nil
end
- @terminus.expects(:post_search).with(@instance)
- @terminus.expects(:search).with(@name).returns(@instance)
- @indirection.search(@name)
- end
- end
- describe Puppet::Indirector::Indirection, " when storing a model instance" do
+ it "should extend any found instance with the Envelope module" do
+ @terminus.stubs(:find).returns(@instance)
- it "should let the appropriate terminus store the instance" do
- @terminus.expects(:save).with(@instance).returns(@instance)
- @indirection.save(@instance).should == @instance
- end
- end
-
- describe Puppet::Indirector::Indirection, " when handling instance versions" do
+ @instance.expects(:extend).with(Puppet::Indirector::Envelope)
+ @indirection.find(@name)
+ end
- it "should let the appropriate terminus perform the lookup" do
- @terminus.expects(:version).with(@name).returns(5)
- @indirection.version(@name).should == 5
- end
+ it "should set the expiration date on any instances without one set" do
+ # Otherwise, our stub method doesn't get used, so the tests fail.
+ @instance.stubs(:extend)
+ @terminus.stubs(:find).returns(@instance)
- 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)
- end
+ @indirection.expects(:expiration).returns :yay
- 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)
- end
+ @instance.expects(:expiration).returns(nil)
+ @instance.expects(:expiration=).with(:yay)
- # 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?
+ @indirection.find(@name)
end
- @terminus.stubs(:save)
- @indirection.save(@instance)
- end
- end
+ it "should not override an already-set expiration date on returned instances" do
+ # Otherwise, our stub method doesn't get used, so the tests fail.
+ @instance.stubs(:extend)
+ @terminus.stubs(:find).returns(@instance)
- describe Puppet::Indirector::Indirection, " when an authorization hook is present" do
+ @indirection.expects(:expiration).never
- before do
- # So the :respond_to? turns out right.
- class << @terminus
- def authorized?
- end
+ @instance.expects(:expiration).returns(:yay)
+ @instance.expects(:expiration=).never
+
+ @indirection.find(@name)
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 "when caching is enabled" do
+ before do
+ @indirection.cache_class = :cache_terminus
+ @cache_class.expects(:new).returns(@cache)
- 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
+ @instance.stubs(:expired?).returns false
+ end
- 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 first look in the cache for an instance" do
+ @terminus.expects(:find).never
+ @cache.expects(:find).with(@name).returns @instance
- 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
+ @indirection.find(@name)
+ end
- 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
+ it "should return the cached object if it is not expired" do
+ @instance.stubs(:expired?).returns false
- 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
+ @cache.stubs(:find).returns @instance
+ @indirection.find(@name).should equal(@instance)
+ end
- 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
+ it "should send a debug log if it is using the cached object" do
+ Puppet.expects(:debug)
+ @cache.stubs(:find).returns @instance
- 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)
- end
+ @indirection.find(@name)
+ end
- 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 not return the cached object if it is expired" do
+ @instance.stubs(:expired?).returns true
- after :each do
- @indirection.delete
- Puppet::Indirector::Indirection.clear_cache
- end
-end
+ @cache.stubs(:find).returns @instance
+ @terminus.stubs(:find).returns nil
+ @indirection.find(@name).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
-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
+ @cache.stubs(:find).returns @instance
+ @terminus.stubs(:find).returns nil
+ @indirection.find(@name)
+ 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 cache any objects not retrieved from the cache" do
+ @cache.expects(:find).with(@name).returns nil
- after do
- @indirection.delete if defined? @indirection
- end
-end
+ @terminus.expects(:find).with(@name).returns(@instance)
+ @cache.expects(:save).with(@instance)
-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.find(@name)
+ end
- 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
+ it "should send an info log that the object is being cached" do
+ @cache.stubs(:find).returns nil
- 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
+ @terminus.stubs(:find).returns(@instance)
+ @cache.stubs(:save)
- 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
+ Puppet.expects(:info)
- after do
- @indirection.delete if defined? @indirection
- end
-end
+ @indirection.find(@name)
+ 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 storing a model instance" do
+ it "should let the appropriate terminus store the instance" do
+ @terminus.expects(:save).with(@instance).returns(@instance)
+ @indirection.save(@instance).should == @instance
+ end
- it "should allow specification of a terminus type" do
- @indirection.should respond_to(:terminus_class=)
- end
+ it "should check authorization" do
+ @indirection.expects(:check_authorization).with(:save, :test_terminus, [@instance])
+ @terminus.stubs(:save)
- it "should fail to redirect if no terminus type has been specified" do
- proc { @indirection.find("blah") }.should raise_error(Puppet::DevError)
- end
+ @indirection.save(@instance)
+ end
- it "should fail when the terminus class name is an empty string" do
- proc { @indirection.terminus_class = "" }.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 fail when the terminus class name is nil" do
- proc { @indirection.terminus_class = nil }.should raise_error(ArgumentError)
- end
+ @instance.stubs(:expired?).returns false
+ end
- 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
+ it "should save the object to the cache" do
+ @cache.expects(:save).with(@instance)
+ @terminus.stubs(:save)
+ @indirection.save(@instance)
+ end
+ end
+ end
+
+ describe "and removing a model instance" do
+ it "should delegate the instance removal to the appropriate terminus" do
+ @terminus.expects(:destroy).with(@name)
+ @indirection.destroy(@name)
+ 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 return nil" do
+ @terminus.stubs(:destroy)
+ @indirection.destroy(@name).should be_nil
+ end
- 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
+ describe "when caching is enabled" do
+ before do
+ @indirection.cache_class = :cache_terminus
+ @cache_class.expects(:new).returns(@cache)
- after do
- @indirection.delete if defined? @indirection
- end
-end
+ @instance.stubs(:expired?).returns false
+ end
+
+ it "should destroy any found object in the cache" do
+ cached = mock 'cache'
+ @cache.expects(:find).with(@name).returns cached
+ @cache.expects(:destroy).with(@name)
+ @terminus.stubs(:destroy)
-describe Puppet::Indirector::Indirection, " when a select_terminus hook is available" do
- before do
- @indirection = Puppet::Indirector::Indirection.new(mock('model'), :test)
+ @indirection.destroy(@name)
+ end
+ end
+ end
- # And provide a select_terminus hook
- @indirection.meta_def(:select_terminus) do |uri|
- :other
+ describe "and searching for multiple model instances" do
+ it "should let the appropriate terminus find the matching instances" do
+ @terminus.expects(:search).with(@name).returns(@instance)
+ @indirection.search(@name).should == @instance
+ end
end
- @terminus = mock 'terminus'
- @terminus_class = stub 'terminus class', :new => @terminus
+ describe "and an authorization hook is present" do
+ before do
+ # So the :respond_to? turns out correctly.
+ class << @terminus
+ def authorized?
+ end
+ end
+ end
- @other_terminus = mock 'other_terminus'
- @other_terminus_class = stub 'other_terminus_class', :new => @other_terminus
+ 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
- @cache_terminus = mock 'cache_terminus'
- @cache_terminus_class = stub 'cache_terminus_class', :new => @cache_terminus
+ 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
- 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)
+ 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
- # Set it to a default type.
- @indirection.terminus_class = :foo
+ it "should fail while saving instances if authorization returns false" do
+ @terminus.expects(:authorized?).with(:save, @instance, :node => "mynode").returns(false)
+ @terminus.stubs(:save)
+ proc { @indirection.save(@instance, :node => "mynode") }.should raise_error(ArgumentError)
+ end
- @uri = "full://url/path"
- @result = stub 'result', :version => 1.0
- end
+ it "should continue saving instances if authorization returns true" do
+ @terminus.expects(:authorized?).with(:save, @instance, :node => "mynode").returns(true)
+ @terminus.stubs(:save)
+ @indirection.save(@instance, :node => "mynode")
+ 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 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 continue destroying instances if authorization returns true" do
+ @terminus.expects(:authorized?).with(:destroy, @instance, :node => "mynode").returns(true)
+ @terminus.stubs(:destroy)
+ @indirection.destroy(@instance, :node => "mynode")
+ end
+
+ 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)
+ end
+
+ 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
- @indirection.find(@uri)
+ after :each do
+ @indirection.delete
+ Puppet::Indirector::Indirection.clear_cache
+ end
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
- @other_terminus.expects(:version).with(@uri).returns(2.0)
+ 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
- @cache_terminus.expects(:has_most_recent?).with(@uri, 2.0).returns(true)
- @cache_terminus.expects(:find).returns(:whatever)
+ 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
- @indirection.find(@uri).should == :whatever
+ after do
+ @indirection.delete if defined? @indirection
+ end
end
- 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)
+ 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
+
+ it "should have a method for choosing the appropriate terminus class"
- @indirection.find(@uri, :node => "johnny")
- end
+ it "should fail if no terminus class can be picked" do
+ proc { @indirection.terminus_class }.should raise_error(Puppet::DevError)
+ 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 use the select_terminus hook if one is available"
- after do
- @indirection.delete if defined? @indirection
- end
-end
+ it "should choose the default terminus class if one is specified" do
+ @indirection.terminus_class = :default
+ @indirection.terminus_class.should equal(:default)
+ end
-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
+ 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 create an instance of the chosen terminus class" do
- @terminus_class.stubs(:new).returns(@terminus)
- @indirection.terminus(:foo).should equal(@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
- 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)
+ after do
+ @indirection.delete if defined? @indirection
+ end
end
- # 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
+ 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 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
+ it "should allow specification of a terminus type" do
+ @indirection.should respond_to(:terminus_class=)
+ end
- after do
- @indirection.delete
- Puppet::Indirector::Indirection.clear_cache
- end
-end
+ it "should fail to redirect if no terminus type has been specified" do
+ proc { @indirection.find("blah") }.should raise_error(Puppet::DevError)
+ 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
- end
+ it "should fail when the terminus class name is an empty string" do
+ proc { @indirection.terminus_class = "" }.should raise_error(ArgumentError)
+ end
- it "should provide a method for setting the cache terminus class" do
- @indirection.should respond_to(:cache_class=)
- end
+ it "should fail when the terminus class name is nil" do
+ proc { @indirection.terminus_class = nil }.should raise_error(ArgumentError)
+ end
- it "should fail to cache if no cache type has been specified" do
- proc { @indirection.cache }.should raise_error(Puppet::DevError)
- end
+ 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
- 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 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 fail to set the cache class when the cache class name is nil" do
- proc { @indirection.cache_class = nil }.should raise_error(ArgumentError)
- end
+ 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 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)
+ after do
+ @indirection.delete if defined? @indirection
+ end
end
- after do
- @indirection.delete
- Puppet::Indirector::Indirection.clear_cache
- end
-end
+ describe "when a select_terminus hook is available" do
+ before do
+ @indirection = Puppet::Indirector::Indirection.new(mock('model'), :test)
-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
- end
+ # And provide a select_terminus hook
+ @indirection.meta_def(:select_terminus) do |uri|
+ :other
+ end
- describe Puppet::Indirector::Indirection, " when managing the cache terminus" do
+ @terminus = mock 'terminus'
+ @terminus_class = stub 'terminus class', :new => @terminus
- 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
+ @other_terminus = mock 'other_terminus'
+ @other_terminus_class = stub 'other_terminus_class', :new => @other_terminus
- 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)
+ @cache_terminus = mock 'cache_terminus'
+ @cache_terminus_class = stub 'cache_terminus_class', :new => @cache_terminus
+
+ 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)
+
+ # Set it to a default type.
+ @indirection.terminus_class = :foo
+
+ @uri = "full://url/path"
+ @result = stub 'result', :expiration => 1, :expired? => false
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 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)
+
+ @indirection.find(@uri)
end
- end
- describe Puppet::Indirector::Indirection, " when saving and using a cache" do
+ 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)
- before do
- @indirection.cache_class = :cache_terminus
- @cache_class.expects(:new).returns(@cache)
- @name = "testing"
- @instance = stub 'instance', :version => 5, :name => @name
+ @indirection.find(@uri, :node => "johnny")
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 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 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 return the cached object if the cache is up to date" do
- cached = mock 'cached object'
+ it "should create an instance of the chosen terminus class" do
+ @terminus_class.stubs(:new).returns(@terminus)
+ @indirection.terminus(:foo).should equal(@terminus)
+ end
- name = "myobject"
+ 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
- @terminus.expects(:version).with(name).returns(1)
- @cache.expects(:has_most_recent?).with(name, 1).returns(true)
+ # 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
- @cache.expects(:find).with(name).returns(cached)
+ 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
- @indirection.find(name).should equal(cached)
+ after do
+ @indirection.delete
+ Puppet::Indirector::Indirection.clear_cache
end
+ end
- it "should return the original object if the cache is not up to date" do
- real = stub 'real object', :version => 1
+ 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
- name = "myobject"
+ it "should provide a method for setting the cache terminus class" do
+ @indirection.should respond_to(:cache_class=)
+ 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 cache if no cache type has been specified" do
+ proc { @indirection.cache }.should raise_error(Puppet::DevError)
+ end
- @terminus.expects(:find).with(name).returns(real)
+ 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
- @indirection.find(name).should equal(real)
+ 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
- it "should cache any newly returned objects" do
- real = stub 'real object', :version => 1
+ 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
- name = "myobject"
+ after do
+ @indirection.delete
+ Puppet::Indirector::Indirection.clear_cache
+ end
+ end
+
+ 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
- @terminus.expects(:version).with(name).returns(1)
- @cache.expects(:has_most_recent?).with(name, 1).returns(false)
+ 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(:find).with(name).returns(real)
- @cache.expects(:save).with(real)
+ 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
- @indirection.find(name).should equal(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
+
+ 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