require 'spec_helper' require 'puppet/indirector/indirection' shared_examples_for "Indirection Delegator" do it "should create a request object with the appropriate method name and all of the passed arguments" do request = Puppet::Indirector::Request.new(:indirection, :find, "me", nil) expect(@indirection).to receive(:request).with(@method, "mystuff", nil, :one => :two).and_return(request) allow(@terminus).to receive(@method) @indirection.send(@method, "mystuff", :one => :two) end it "should choose the terminus returned by the :terminus_class" do expect(@indirection).to receive(:terminus_class).and_return(:test_terminus) expect(@terminus).to receive(@method) @indirection.send(@method, "me") end it "should let the appropriate terminus perform the lookup" do expect(@terminus).to receive(@method).with(be_a(Puppet::Indirector::Request)) @indirection.send(@method, "me") end end shared_examples_for "Delegation Authorizer" do before do # So the :respond_to? turns out correctly. class << @terminus def authorized? end end end it "should not check authorization if a node name is not provided" do expect(@terminus).not_to receive(:authorized?) allow(@terminus).to receive(@method) # The parenthesis are necessary here, else it looks like a block. allow(@request).to receive(:options).and_return({}) @indirection.send(@method, "/my/key") end it "should pass the request to the terminus's authorization method" do expect(@terminus).to receive(:authorized?).with(be_a(Puppet::Indirector::Request)).and_return(true) allow(@terminus).to receive(@method) @indirection.send(@method, "/my/key", :node => "mynode") end it "should fail if authorization returns false" do expect(@terminus).to receive(:authorized?).and_return(false) allow(@terminus).to receive(@method) expect { @indirection.send(@method, "/my/key", :node => "mynode") }.to raise_error(ArgumentError) end it "should continue if authorization returns true" do expect(@terminus).to receive(:authorized?).and_return(true) allow(@terminus).to receive(@method) @indirection.send(@method, "/my/key", :node => "mynode") end end shared_examples_for "Request validator" do it "asks the terminus to validate the request" do expect(@terminus).to receive(:validate).and_raise(Puppet::Indirector::ValidationError, "Invalid") expect(@terminus).not_to receive(@method) expect { @indirection.send(@method, "key") }.to raise_error Puppet::Indirector::ValidationError end end describe Puppet::Indirector::Indirection do describe "when initializing" do it "should keep a reference to the indirecting model" do model = double('model') @indirection = Puppet::Indirector::Indirection.new(model, :myind) expect(@indirection.model).to equal(model) end it "should set the name" do @indirection = Puppet::Indirector::Indirection.new(double('model'), :myind) expect(@indirection.name).to eq(:myind) end it "should require indirections to have unique names" do @indirection = Puppet::Indirector::Indirection.new(double('model'), :test) expect { Puppet::Indirector::Indirection.new(:test) }.to raise_error(ArgumentError) end it "should extend itself with any specified module" do mod = Module.new @indirection = Puppet::Indirector::Indirection.new(double('model'), :test, :extend => mod) expect(@indirection.singleton_class.included_modules).to include(mod) end after do @indirection.delete if defined?(@indirection) end end describe "when an instance" do before :each do @terminus_class = double('terminus_class') @terminus = double('terminus') allow(@terminus).to receive(:validate) allow(@terminus_class).to receive(:new).and_return(@terminus) @cache = double('cache', :name => "mycache") @cache_class = double('cache_class') allow(Puppet::Indirector::Terminus).to receive(:terminus_class).with(:test, :cache_terminus).and_return(@cache_class) allow(Puppet::Indirector::Terminus).to receive(:terminus_class).with(:test, :test_terminus).and_return(@terminus_class) @indirection = Puppet::Indirector::Indirection.new(double('model'), :test) @indirection.terminus_class = :test_terminus @instance = double('instance', :expiration => nil, :expiration= => nil, :name => "whatever") @name = :mything @request = double('instance') end describe 'ensure that indirection settings are threadsafe' do before :each do @alt_term = double('alternate_terminus') expect(Puppet::Indirector::Terminus).to receive(:terminus_class).with(:test, :alternate_terminus).and_return(@alt_term) @alt_cache= double('alternate_cache') expect(Puppet::Indirector::Terminus).to receive(:terminus_class).with(:test, :alternate_cache).and_return(@alt_cache) end it 'does not change the original value when modified in new thread' do Thread.new do @indirection.terminus_class = :alternate_terminus @indirection.terminus_setting = :alternate_terminus_setting @indirection.cache_class = :alternate_cache end.join expect(@indirection.terminus_class).to eq(:test_terminus) expect(@indirection.terminus_setting).to eq(nil) expect(@indirection.cache_class).to eq(nil) end it 'can modify indirection settings globally for all threads using the global setter' do Thread.new do @indirection.set_global_setting(:terminus_class, :alternate_terminus) @indirection.set_global_setting(:terminus_setting, :alternate_terminus_setting) @indirection.set_global_setting(:cache_class, :alternate_cache) end.join expect(@indirection.terminus_class).to eq(:alternate_terminus) expect(@indirection.terminus_setting).to eq(:alternate_terminus_setting) expect(@indirection.cache_class).to eq(:alternate_cache) end end it "should allow setting the ttl" do @indirection.ttl = 300 expect(@indirection.ttl).to eq(300) end it "should default to the :runinterval setting, converted to an integer, for its ttl" do Puppet[:runinterval] = 1800 expect(@indirection.ttl).to eq(1800) end it "should calculate the current expiration by adding the TTL to the current time" do allow(@indirection).to receive(:ttl).and_return(100) now = Time.now allow(Time).to receive(:now).and_return(now) expect(@indirection.expiration).to eq(Time.now + 100) end it "should have a method for creating an indirection request instance" do expect(@indirection).to respond_to(:request) end describe "creates a request" do it "should create it with its name as the request's indirection name" do expect(@indirection.request(:funtest, "yayness", nil).indirection_name).to eq(@indirection.name) end it "should require a method and key" do request = @indirection.request(:funtest, "yayness", nil) expect(request.method).to eq(:funtest) expect(request.key).to eq("yayness") end it "should support optional arguments" do expect(@indirection.request(:funtest, "yayness", nil, :one => :two).options).to eq(:one => :two) end it "should not pass options if none are supplied" do expect(@indirection.request(:funtest, "yayness", nil).options).to eq({}) end it "should return the request" do expect(@indirection.request(:funtest, "yayness", nil)).to be_a(Puppet::Indirector::Request) 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" it_should_behave_like "Request validator" it "should return the results of the delegation" do expect(@terminus).to receive(:find).and_return(@instance) expect(@indirection.find("me")).to equal(@instance) end it "should return false if the instance is false" do expect(@terminus).to receive(:find).and_return(false) expect(@indirection.find("me")).to equal(false) end it "should set the expiration date on any instances without one set" do allow(@terminus).to receive(:find).and_return(@instance) expect(@indirection).to receive(:expiration).and_return(:yay) expect(@instance).to receive(:expiration).and_return(nil) expect(@instance).to receive(:expiration=).with(:yay) @indirection.find("/my/key") end it "should not override an already-set expiration date on returned instances" do allow(@terminus).to receive(:find).and_return(@instance) expect(@indirection).not_to receive(:expiration) expect(@instance).to receive(:expiration).and_return(:yay) expect(@instance).not_to receive(:expiration=) @indirection.find("/my/key") end it "should filter the result instance if the terminus supports it" do allow(@terminus).to receive(:find).and_return(@instance) allow(@terminus).to receive(:respond_to?).with(:filter).and_return(true) expect(@terminus).to receive(:filter).with(@instance) @indirection.find("/my/key") end describe "when caching is enabled" do before do @indirection.cache_class = :cache_terminus allow(@cache_class).to receive(:new).and_return(@cache) allow(@instance).to receive(:expired?).and_return(false) end it "should first look in the cache for an instance" do expect(@terminus).not_to receive(:find) expect(@cache).to receive(:find).and_return(@instance) @indirection.find("/my/key") end it "should not look in the cache if the request specifies not to use the cache" do expect(@terminus).to receive(:find).and_return(@instance) expect(@cache).not_to receive(:find) allow(@cache).to receive(:save) @indirection.find("/my/key", :ignore_cache => true) end it "should still save to the cache even if the cache is being ignored during readin" do expect(@terminus).to receive(:find).and_return(@instance) expect(@cache).to receive(:save) @indirection.find("/my/key", :ignore_cache => true) end it "should not save to the cache if told to skip updating the cache" do expect(@terminus).to receive(:find).and_return(@instance) expect(@cache).to receive(:find).and_return(nil) expect(@cache).not_to receive(:save) @indirection.find("/my/key", :ignore_cache_save => true) end it "should only look in the cache if the request specifies not to use the terminus" do expect(@terminus).not_to receive(:find) expect(@cache).to receive(:find) @indirection.find("/my/key", :ignore_terminus => true) end it "should use a request to look in the cache for cached objects" do expect(@cache).to receive(:find) do |r| expect(r.method).to eq(:find) expect(r.key).to eq("/my/key") @instance end allow(@cache).to receive(:save) @indirection.find("/my/key") end it "should return the cached object if it is not expired" do allow(@instance).to receive(:expired?).and_return(false) allow(@cache).to receive(:find).and_return(@instance) expect(@indirection.find("/my/key")).to equal(@instance) end it "should not fail if the cache fails" do allow(@terminus).to receive(:find).and_return(@instance) expect(@cache).to receive(:find).and_raise(ArgumentError) allow(@cache).to receive(:save) expect { @indirection.find("/my/key") }.not_to raise_error end it "should look in the main terminus if the cache fails" do expect(@terminus).to receive(:find).and_return(@instance) expect(@cache).to receive(:find).and_raise(ArgumentError) allow(@cache).to receive(:save) expect(@indirection.find("/my/key")).to equal(@instance) end it "should send a debug log if it is using the cached object" do expect(Puppet).to receive(:debug) allow(@cache).to receive(:find).and_return(@instance) @indirection.find("/my/key") end it "should not return the cached object if it is expired" do allow(@instance).to receive(:expired?).and_return(true) allow(@cache).to receive(:find).and_return(@instance) allow(@terminus).to receive(:find).and_return(nil) expect(@indirection.find("/my/key")).to be_nil end it "should send an info log if it is using the cached object" do expect(Puppet).to receive(:info) allow(@instance).to receive(:expired?).and_return(true) allow(@cache).to receive(:find).and_return(@instance) allow(@terminus).to receive(:find).and_return(nil) @indirection.find("/my/key") end it "should cache any objects not retrieved from the cache" do expect(@cache).to receive(:find).and_return(nil) expect(@terminus).to receive(:find).and_return(@instance) expect(@cache).to receive(:save) @indirection.find("/my/key") end it "should use a request to look in the cache for cached objects" do expect(@cache).to receive(:find) do |r| expect(r.method).to eq(:find) expect(r.key).to eq("/my/key") nil end allow(@terminus).to receive(:find).and_return(@instance) allow(@cache).to receive(:save) @indirection.find("/my/key") end it "should cache the instance using a request with the instance set to the cached object" do allow(@cache).to receive(:find).and_return(nil) allow(@terminus).to receive(:find).and_return(@instance) expect(@cache).to receive(:save) do |r| expect(r.method).to eq(:save) expect(r.instance).to eq(@instance) end @indirection.find("/my/key") end it "should send an info log that the object is being cached" do allow(@cache).to receive(:find).and_return(nil) allow(@terminus).to receive(:find).and_return(@instance) allow(@cache).to receive(:save) expect(Puppet).to receive(:info) @indirection.find("/my/key") end it "should fail if saving to the cache fails but log the exception" do allow(@cache).to receive(:find).and_return(nil) allow(@terminus).to receive(:find).and_return(@instance) allow(@cache).to receive(:save).and_raise(RuntimeError) expect(Puppet).to receive(:log_exception) expect { @indirection.find("/my/key") }.to raise_error RuntimeError end end end describe "and doing a head operation" do before { @method = :head } it_should_behave_like "Indirection Delegator" it_should_behave_like "Delegation Authorizer" it_should_behave_like "Request validator" it "should return true if the head method returned true" do expect(@terminus).to receive(:head).and_return(true) expect(@indirection.head("me")).to eq(true) end it "should return false if the head method returned false" do expect(@terminus).to receive(:head).and_return(false) expect(@indirection.head("me")).to eq(false) end describe "when caching is enabled" do before do @indirection.cache_class = :cache_terminus allow(@cache_class).to receive(:new).and_return(@cache) allow(@instance).to receive(:expired?).and_return(false) end it "should first look in the cache for an instance" do expect(@terminus).not_to receive(:find) expect(@terminus).not_to receive(:head) expect(@cache).to receive(:find).and_return(@instance) expect(@indirection.head("/my/key")).to eq(true) end it "should not save to the cache" do expect(@cache).to receive(:find).and_return(nil) expect(@cache).not_to receive(:save) expect(@terminus).to receive(:head).and_return(true) expect(@indirection.head("/my/key")).to eq(true) end it "should not fail if the cache fails" do allow(@terminus).to receive(:head).and_return(true) expect(@cache).to receive(:find).and_raise(ArgumentError) expect { @indirection.head("/my/key") }.not_to raise_error end it "should look in the main terminus if the cache fails" do expect(@terminus).to receive(:head).and_return(true) expect(@cache).to receive(:find).and_raise(ArgumentError) expect(@indirection.head("/my/key")).to eq(true) end it "should send a debug log if it is using the cached object" do expect(Puppet).to receive(:debug) allow(@cache).to receive(:find).and_return(@instance) @indirection.head("/my/key") end it "should not accept the cached object if it is expired" do allow(@instance).to receive(:expired?).and_return(true) allow(@cache).to receive(:find).and_return(@instance) allow(@terminus).to receive(:head).and_return(false) expect(@indirection.head("/my/key")).to eq(false) end end end describe "and storing a model instance" do before { @method = :save } it "should return the result of the save" do allow(@terminus).to receive(:save).and_return("foo") expect(@indirection.save(@instance)).to eq("foo") end describe "when caching is enabled" do before do @indirection.cache_class = :cache_terminus allow(@cache_class).to receive(:new).and_return(@cache) allow(@instance).to receive(:expired?).and_return(false) end it "should return the result of saving to the terminus" do request = double('request', :instance => @instance, :node => nil, :ignore_cache_save? => false) expect(@indirection).to receive(:request).and_return(request) allow(@cache).to receive(:save) allow(@terminus).to receive(:save).and_return(@instance) expect(@indirection.save(@instance)).to equal(@instance) end it "should use a request to save the object to the cache" do request = double('request', :instance => @instance, :node => nil, :ignore_cache_save? => false) expect(@indirection).to receive(:request).and_return(request) expect(@cache).to receive(:save).with(request) allow(@terminus).to receive(:save) @indirection.save(@instance) end it "should not save to the cache if the normal save fails" do request = double('request', :instance => @instance, :node => nil) expect(@indirection).to receive(:request).and_return(request) expect(@cache).not_to receive(:save) expect(@terminus).to receive(:save).and_raise("eh") expect { @indirection.save(@instance) }.to raise_error(RuntimeError, /eh/) end it "should not save to the cache if told to ignore saving to the cache" do expect(@terminus).to receive(:save) expect(@cache).not_to receive(:save) @indirection.save(@instance, '/my/key', :ignore_cache_save => true) end end end describe "and removing a model instance" do before { @method = :destroy } it_should_behave_like "Indirection Delegator" it_should_behave_like "Delegation Authorizer" it_should_behave_like "Request validator" it "should return the result of removing the instance" do allow(@terminus).to receive(:destroy).and_return("yayness") expect(@indirection.destroy("/my/key")).to eq("yayness") end describe "when caching is enabled" do before do @indirection.cache_class = :cache_terminus expect(@cache_class).to receive(:new).and_return(@cache) allow(@instance).to receive(:expired?).and_return(false) end it "should use a request instance to search in and remove objects from the cache" do destroy = double('destroy_request', :key => "/my/key", :node => nil) find = double('destroy_request', :key => "/my/key", :node => nil) expect(@indirection).to receive(:request).with(:destroy, "/my/key", nil, be_a(Hash).or(be_nil)).and_return(destroy) expect(@indirection).to receive(:request).with(:find, "/my/key", nil, be_a(Hash).or(be_nil)).and_return(find) cached = double('cache') expect(@cache).to receive(:find).with(find).and_return(cached) expect(@cache).to receive(:destroy).with(destroy) allow(@terminus).to receive(:destroy) @indirection.destroy("/my/key") end end end describe "and searching for multiple model instances" do before { @method = :search } it_should_behave_like "Indirection Delegator" it_should_behave_like "Delegation Authorizer" it_should_behave_like "Request validator" it "should set the expiration date on any instances without one set" do allow(@terminus).to receive(:search).and_return([@instance]) expect(@indirection).to receive(:expiration).and_return(:yay) expect(@instance).to receive(:expiration).and_return(nil) expect(@instance).to receive(:expiration=).with(:yay) @indirection.search("/my/key") end it "should not override an already-set expiration date on returned instances" do allow(@terminus).to receive(:search).and_return([@instance]) expect(@indirection).not_to receive(:expiration) expect(@instance).to receive(:expiration).and_return(:yay) expect(@instance).not_to receive(:expiration=) @indirection.search("/my/key") end it "should return the results of searching in the terminus" do expect(@terminus).to receive(:search).and_return([@instance]) expect(@indirection.search("/my/key")).to eq([@instance]) end end describe "and expiring a model instance" do describe "when caching is not enabled" do it "should do nothing" do expect(@cache_class).not_to receive(:new) @indirection.expire("/my/key") end end describe "when caching is enabled" do before do @indirection.cache_class = :cache_terminus expect(@cache_class).to receive(:new).and_return(@cache) allow(@instance).to receive(:expired?).and_return(false) @cached = double('cached', :expiration= => nil, :name => "/my/key") end it "should use a request to find within the cache" do expect(@cache).to receive(:find) do |r| expect(r).to be_a(Puppet::Indirector::Request) expect(r.method).to eq(:find) nil end @indirection.expire("/my/key") end it "should do nothing if no such instance is cached" do expect(@cache).to receive(:find).and_return(nil) @indirection.expire("/my/key") end it "should log when expiring a found instance" do expect(@cache).to receive(:find).and_return(@cached) allow(@cache).to receive(:save) expect(Puppet).to receive(:info) @indirection.expire("/my/key") end it "should set the cached instance's expiration to a time in the past" do expect(@cache).to receive(:find).and_return(@cached) allow(@cache).to receive(:save) expect(@cached).to receive(:expiration=).with(be < Time.now) @indirection.expire("/my/key") end it "should save the now expired instance back into the cache" do expect(@cache).to receive(:find).and_return(@cached) expect(@cached).to receive(:expiration=).with(be < Time.now) expect(@cache).to receive(:save) @indirection.expire("/my/key") end it "does not expire an instance if told to skip cache saving" do expect(@indirection.cache).not_to receive(:find) expect(@indirection.cache).not_to receive(:save) @indirection.expire("/my/key", :ignore_cache_save => true) end it "should use a request to save the expired resource to the cache" do expect(@cache).to receive(:find).and_return(@cached) expect(@cached).to receive(:expiration=).with(be < Time.now) expect(@cache).to receive(:save) do |r| expect(r).to be_a(Puppet::Indirector::Request) expect(r.instance).to eq(@cached) expect(r.method).to eq(:save) @cached end @indirection.expire("/my/key") end end end after :each do @indirection.delete end end describe "when managing indirection instances" do it "should allow an indirection to be retrieved by name" do @indirection = Puppet::Indirector::Indirection.new(double('model'), :test) expect(Puppet::Indirector::Indirection.instance(:test)).to equal(@indirection) end it "should return nil when the named indirection has not been created" do expect(Puppet::Indirector::Indirection.instance(:test)).to be_nil end it "should allow an indirection's model to be retrieved by name" do mock_model = double('model') @indirection = Puppet::Indirector::Indirection.new(mock_model, :test) expect(Puppet::Indirector::Indirection.model(:test)).to equal(mock_model) end it "should return nil when no model matches the requested name" do expect(Puppet::Indirector::Indirection.model(:test)).to be_nil end after do @indirection.delete if defined?(@indirection) end end describe "when routing to the correct the terminus class" do before do @indirection = Puppet::Indirector::Indirection.new(double('model'), :test) @terminus = double('terminus') @terminus_class = double('terminus class', :new => @terminus) allow(Puppet::Indirector::Terminus).to receive(:terminus_class).with(:test, :default).and_return(@terminus_class) end it "should fail if no terminus class can be picked" do expect { @indirection.terminus_class }.to raise_error(Puppet::DevError) end it "should choose the default terminus class if one is specified" do @indirection.terminus_class = :default expect(@indirection.terminus_class).to equal(:default) end it "should use the provided Puppet setting if told to do so" do allow(Puppet::Indirector::Terminus).to receive(:terminus_class).with(:test, :my_terminus).and_return(double("terminus_class2")) Puppet[:node_terminus] = :my_terminus @indirection.terminus_setting = :node_terminus expect(@indirection.terminus_class).to equal(:my_terminus) end it "should fail if the provided terminus class is not valid" do allow(Puppet::Indirector::Terminus).to receive(:terminus_class).with(:test, :nosuchclass).and_return(nil) expect { @indirection.terminus_class = :nosuchclass }.to raise_error(ArgumentError) end after do @indirection.delete if defined?(@indirection) end end describe "when specifying the terminus class to use" do before do @indirection = Puppet::Indirector::Indirection.new(double('model'), :test) @terminus = double('terminus') allow(@terminus).to receive(:validate) @terminus_class = double('terminus class', :new => @terminus) end it "should allow specification of a terminus type" do expect(@indirection).to respond_to(:terminus_class=) end it "should fail to redirect if no terminus type has been specified" do expect { @indirection.find("blah") }.to raise_error(Puppet::DevError) end it "should fail when the terminus class name is an empty string" do expect { @indirection.terminus_class = "" }.to raise_error(ArgumentError) end it "should fail when the terminus class name is nil" do expect { @indirection.terminus_class = nil }.to raise_error(ArgumentError) end it "should fail when the specified terminus class cannot be found" do expect(Puppet::Indirector::Terminus).to receive(:terminus_class).with(:test, :foo).and_return(nil) expect { @indirection.terminus_class = :foo }.to raise_error(ArgumentError) end it "should select the specified terminus class if a terminus class name is provided" do expect(Puppet::Indirector::Terminus).to receive(:terminus_class).with(:test, :foo).and_return(@terminus_class) expect(@indirection.terminus(:foo)).to equal(@terminus) end it "should use the configured terminus class if no terminus name is specified" do allow(Puppet::Indirector::Terminus).to receive(:terminus_class).with(:test, :foo).and_return(@terminus_class) @indirection.terminus_class = :foo expect(@indirection.terminus).to equal(@terminus) end after do @indirection.delete if defined?(@indirection) end end describe "when managing terminus instances" do before do @indirection = Puppet::Indirector::Indirection.new(double('model'), :test) @terminus = double('terminus') @terminus_class = double('terminus class') allow(Puppet::Indirector::Terminus).to receive(:terminus_class).with(:test, :foo).and_return(@terminus_class) end it "should create an instance of the chosen terminus class" do allow(@terminus_class).to receive(:new).and_return(@terminus) expect(@indirection.terminus(:foo)).to equal(@terminus) end # Make sure it caches the terminus. it "should return the same terminus instance each time for a given name" do allow(@terminus_class).to receive(:new).and_return(@terminus) expect(@indirection.terminus(:foo)).to equal(@terminus) expect(@indirection.terminus(:foo)).to equal(@terminus) end it "should not create a terminus instance until one is actually needed" do expect(@indirection).not_to receive(:terminus) Puppet::Indirector::Indirection.new(double('model'), :lazytest) end after do @indirection.delete end end describe "when deciding whether to cache" do before do @indirection = Puppet::Indirector::Indirection.new(double('model'), :test) @terminus = double('terminus') @terminus_class = double('terminus class') allow(@terminus_class).to receive(:new).and_return(@terminus) allow(Puppet::Indirector::Terminus).to receive(:terminus_class).with(:test, :foo).and_return(@terminus_class) @indirection.terminus_class = :foo end it "should provide a method for setting the cache terminus class" do expect(@indirection).to respond_to(:cache_class=) end it "should fail to cache if no cache type has been specified" do expect { @indirection.cache }.to raise_error(Puppet::DevError) end it "should fail to set the cache class when the cache class name is an empty string" do expect { @indirection.cache_class = "" }.to raise_error(ArgumentError) end it "should allow resetting the cache_class to nil" do @indirection.cache_class = nil expect(@indirection.cache_class).to be_nil end it "should fail to set the cache class when the specified cache class cannot be found" do expect(Puppet::Indirector::Terminus).to receive(:terminus_class).with(:test, :foo).and_return(nil) expect { @indirection.cache_class = :foo }.to raise_error(ArgumentError) end after do @indirection.delete end end describe "when using a cache" do before :each do @terminus_class = double('terminus_class') @terminus = double('terminus') allow(@terminus_class).to receive(:new).and_return(@terminus) @cache = double('cache') @cache_class = double('cache_class') allow(Puppet::Indirector::Terminus).to receive(:terminus_class).with(:test, :cache_terminus).and_return(@cache_class) allow(Puppet::Indirector::Terminus).to receive(:terminus_class).with(:test, :test_terminus).and_return(@terminus_class) @indirection = Puppet::Indirector::Indirection.new(double('model'), :test) @indirection.terminus_class = :test_terminus end 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 it "should reuse the cache terminus" do expect(@cache_class).to receive(:new).and_return(@cache) @indirection.cache_class = :cache_terminus expect(@indirection.cache).to equal(@cache) expect(@indirection.cache).to equal(@cache) end end after :each do @indirection.delete end end end