diff --git a/lib/puppet/indirector/catalog/store_configs.rb b/lib/puppet/indirector/catalog/store_configs.rb new file mode 100644 index 000000000..2a6bdb5a9 --- /dev/null +++ b/lib/puppet/indirector/catalog/store_configs.rb @@ -0,0 +1,5 @@ +require 'puppet/indirector/store_configs' +require 'puppet/resource/catalog' + +class Puppet::Resource::Catalog::StoreConfigs < Puppet::Indirector::StoreConfigs +end diff --git a/lib/puppet/indirector/facts/store_configs.rb b/lib/puppet/indirector/facts/store_configs.rb new file mode 100644 index 000000000..5a6804c35 --- /dev/null +++ b/lib/puppet/indirector/facts/store_configs.rb @@ -0,0 +1,5 @@ +require 'puppet/node/facts' +require 'puppet/indirector/store_configs' + +class Puppet::Node::Facts::StoreConfigs < Puppet::Indirector::StoreConfigs +end diff --git a/lib/puppet/indirector/node/store_configs.rb b/lib/puppet/indirector/node/store_configs.rb new file mode 100644 index 000000000..192254e41 --- /dev/null +++ b/lib/puppet/indirector/node/store_configs.rb @@ -0,0 +1,5 @@ +require 'puppet/indirector/store_configs' +require 'puppet/node' + +class Puppet::Node::StoreConfigs < Puppet::Indirector::StoreConfigs +end diff --git a/lib/puppet/indirector/store_configs.rb b/lib/puppet/indirector/store_configs.rb new file mode 100644 index 000000000..3c7447437 --- /dev/null +++ b/lib/puppet/indirector/store_configs.rb @@ -0,0 +1,30 @@ +class Puppet::Indirector::StoreConfigs < Puppet::Indirector::Terminus + def initialize + super + # This will raise if the indirection can't be found, so we can assume it + # is always set to a valid instance from here on in. + @target = indirection.terminus Puppet[:storeconfigs_backend] + end + + attr_reader :target + + def head(request) + target.head request + end + + def find(request) + target.find request + end + + def search(request) + target.search request + end + + def save(request) + target.save request + end + + def destroy(request) + target.save request + end +end diff --git a/spec/shared_behaviours/store_configs_terminus.rb b/spec/shared_behaviours/store_configs_terminus.rb new file mode 100644 index 000000000..1ee241666 --- /dev/null +++ b/spec/shared_behaviours/store_configs_terminus.rb @@ -0,0 +1,21 @@ +shared_examples_for "a StoreConfigs terminus" do + before :each do + Puppet[:storeconfigs] = true + Puppet[:storeconfigs_backend] = "store_configs_testing" + end + + api = [:find, :search, :save, :destroy, :head] + + api.each do |name| + it { should respond_to name } + end + + it "should fail if an invalid backend is configured" do + Puppet[:storeconfigs_backend] = "synergy" + expect { subject }.to raise_error ArgumentError, /could not find terminus synergy/i + end + + it "should wrap the declared backend" do + subject.target.class.name.should == :store_configs_testing + end +end diff --git a/spec/unit/application/queue_spec.rb b/spec/unit/application/queue_spec.rb index d861383a6..28378d804 100755 --- a/spec/unit/application/queue_spec.rb +++ b/spec/unit/application/queue_spec.rb @@ -1,173 +1,172 @@ #!/usr/bin/env rspec require 'spec_helper' require 'puppet/application/queue' require 'puppet/indirector/catalog/queue' describe Puppet::Application::Queue, :unless => Puppet.features.microsoft_windows? do before :each do @queue = Puppet::Application[:queue] @queue.stubs(:puts) @daemon = stub_everything 'daemon', :daemonize => nil Puppet::Util::Log.stubs(:newdestination) Puppet::Resource::Catalog.indirection.stubs(:terminus_class=) end it "should ask Puppet::Application to parse Puppet configuration file" do @queue.should_parse_config?.should be_true end it "should declare a main command" do @queue.should respond_to(:main) end it "should declare a preinit block" do @queue.should respond_to(:preinit) end describe "in preinit" do it "should catch INT" do Signal.expects(:trap).with { |arg,block| arg == :INT } @queue.preinit end it "should init :verbose to false" do @queue.preinit @queue.options[:verbose].should be_false end it "should init :debug to false" do @queue.preinit @queue.options[:debug].should be_false end it "should create a Daemon instance and copy ARGV to it" do ARGV.expects(:dup).returns "eh" daemon = mock("daemon") daemon.expects(:argv=).with("eh") Puppet::Daemon.expects(:new).returns daemon @queue.preinit end end describe "when handling options" do [:debug, :verbose].each do |option| it "should declare handle_#{option} method" do @queue.should respond_to("handle_#{option}".to_sym) end it "should store argument value when calling handle_#{option}" do @queue.options.expects(:[]=).with(option, 'arg') @queue.send("handle_#{option}".to_sym, 'arg') end end end describe "during setup" do before :each do @queue.options.stubs(:[]) @queue.daemon.stubs(:daemonize) Puppet.stubs(:info) Puppet.features.stubs(:stomp?).returns true Puppet::Resource::Catalog.indirection.stubs(:terminus_class=) Puppet.stubs(:settraps) Puppet.settings.stubs(:print_config?) Puppet.settings.stubs(:print_config) end it "should fail if the stomp feature is missing" do Puppet.features.expects(:stomp?).returns false lambda { @queue.setup }.should raise_error(ArgumentError) end it "should print puppet config if asked to in Puppet config" do Puppet.settings.stubs(:print_configs?).returns(true) Puppet.settings.expects(:print_configs).returns(true) expect { @queue.setup }.to exit_with 0 end it "should exit after printing puppet config if asked to in Puppet config" do Puppet.settings.stubs(:print_configs?).returns(true) expect { @queue.setup }.to exit_with 1 end it "should call setup_logs" do @queue.expects(:setup_logs) @queue.setup end describe "when setting up logs" do before :each do Puppet::Util::Log.stubs(:newdestination) end it "should set log level to debug if --debug was passed" do @queue.options.stubs(:[]).with(:debug).returns(true) @queue.setup_logs Puppet::Util::Log.level.should == :debug end it "should set log level to info if --verbose was passed" do @queue.options.stubs(:[]).with(:verbose).returns(true) @queue.setup_logs Puppet::Util::Log.level.should == :info end [:verbose, :debug].each do |level| it "should set console as the log destination with level #{level}" do @queue.options.stubs(:[]).with(level).returns(true) Puppet::Util::Log.expects(:newdestination).with(:console) @queue.setup_logs end end end - it "should configure the Catalog class to use ActiveRecord" do - Puppet::Resource::Catalog.indirection.expects(:terminus_class=).with(:active_record) - + it "should configure the Catalog class to use StoreConfigs" do + Puppet::Resource::Catalog.indirection.expects(:terminus_class=).with(:store_configs) @queue.setup end it "should daemonize if needed" do Puppet.expects(:[]).with(:daemonize).returns(true) @queue.daemon.expects(:daemonize) @queue.setup end end describe "when running" do before :each do @queue.stubs(:sleep_forever) Puppet::Resource::Catalog::Queue.stubs(:subscribe) Thread.list.each { |t| t.stubs(:join) } end it "should subscribe to the queue" do Puppet::Resource::Catalog::Queue.expects(:subscribe) @queue.main end it "should log and save each catalog passed by the queue" do catalog = Puppet::Resource::Catalog.new('eh') Puppet::Resource::Catalog.indirection.expects(:save).with(catalog) Puppet::Resource::Catalog::Queue.expects(:subscribe).yields(catalog) Puppet.expects(:notice).times(2) @queue.main end it "should join all of the running threads" do Thread.list.each { |t| t.expects(:join) } @queue.main end end end diff --git a/spec/unit/indirector/catalog/store_configs_spec.rb b/spec/unit/indirector/catalog/store_configs_spec.rb new file mode 100755 index 000000000..623ae2410 --- /dev/null +++ b/spec/unit/indirector/catalog/store_configs_spec.rb @@ -0,0 +1,17 @@ +#!/usr/bin/env rspec +require 'spec_helper' +require 'puppet/node' +require 'puppet/indirector/memory' +require 'puppet/indirector/catalog/store_configs' + +class Puppet::Resource::Catalog::StoreConfigsTesting < Puppet::Indirector::Memory +end + +describe Puppet::Resource::Catalog::StoreConfigs do + after :each do + Puppet::Resource::Catalog.indirection.reset_terminus_class + Puppet::Resource::Catalog.indirection.cache_class = nil + end + + it_should_behave_like "a StoreConfigs terminus" +end diff --git a/spec/unit/indirector/facts/inventory_active_record_spec.rb b/spec/unit/indirector/facts/inventory_active_record_spec.rb index edd03d8e4..88e5e5359 100755 --- a/spec/unit/indirector/facts/inventory_active_record_spec.rb +++ b/spec/unit/indirector/facts/inventory_active_record_spec.rb @@ -1,167 +1,170 @@ #!/usr/bin/env rspec require 'spec_helper' begin require 'sqlite3' rescue LoadError end require 'tempfile' require 'puppet/rails' describe "Puppet::Node::Facts::InventoryActiveRecord", :if => (Puppet.features.rails? and defined? SQLite3) do let(:terminus) { Puppet::Node::Facts::InventoryActiveRecord.new } before :all do require 'puppet/indirector/facts/inventory_active_record' @dbfile = Tempfile.new("testdb") @dbfile.close end after :all do Puppet::Node::Facts.indirection.reset_terminus_class @dbfile.unlink end before :each do + Puppet::Node.indirection.reset_terminus_class + Puppet::Node.indirection.cache_class = nil + Puppet::Node::Facts.indirection.terminus_class = :inventory_active_record Puppet[:dbadapter] = 'sqlite3' Puppet[:dblocation] = @dbfile.path Puppet[:railslog] = "/dev/null" Puppet::Rails.init end after :each do Puppet::Rails.teardown ActiveRecord::Base.remove_connection end describe "#save" do it "should use an existing node if possible" do node = Puppet::Rails::InventoryNode.new(:name => "foo", :timestamp => Time.now) node.save facts = Puppet::Node::Facts.new("foo", "uptime_days" => "60", "kernel" => "Darwin") Puppet::Node::Facts.indirection.save(facts) Puppet::Rails::InventoryNode.count.should == 1 Puppet::Rails::InventoryNode.first.should == node end it "should create a new node if one can't be found" do # This test isn't valid if there are nodes to begin with Puppet::Rails::InventoryNode.count.should == 0 facts = Puppet::Node::Facts.new("foo", "uptime_days" => "60", "kernel" => "Darwin") Puppet::Node::Facts.indirection.save(facts) Puppet::Rails::InventoryNode.count.should == 1 Puppet::Rails::InventoryNode.first.name.should == "foo" end it "should save the facts" do facts = Puppet::Node::Facts.new("foo", "uptime_days" => "60", "kernel" => "Darwin") Puppet::Node::Facts.indirection.save(facts) Puppet::Rails::InventoryFact.all.map{|f| [f.name,f.value]}.should =~ [["uptime_days","60"],["kernel","Darwin"]] end it "should remove the previous facts for an existing node" do facts = Puppet::Node::Facts.new("foo", "uptime_days" => "30", "kernel" => "Darwin") Puppet::Node::Facts.indirection.save(facts) bar_facts = Puppet::Node::Facts.new("bar", "uptime_days" => "35", "kernel" => "Linux") foo_facts = Puppet::Node::Facts.new("foo", "uptime_days" => "60", "is_virtual" => "false") Puppet::Node::Facts.indirection.save(bar_facts) Puppet::Node::Facts.indirection.save(foo_facts) Puppet::Node::Facts.indirection.find("bar").should == bar_facts Puppet::Node::Facts.indirection.find("foo").should == foo_facts Puppet::Rails::InventoryFact.all.map{|f| [f.name,f.value]}.should_not include(["uptime_days", "30"], ["kernel", "Darwin"]) end end describe "#find" do before do @foo_facts = Puppet::Node::Facts.new("foo", "uptime_days" => "60", "kernel" => "Darwin") @bar_facts = Puppet::Node::Facts.new("bar", "uptime_days" => "30", "kernel" => "Linux") Puppet::Node::Facts.indirection.save(@foo_facts) Puppet::Node::Facts.indirection.save(@bar_facts) end it "should identify facts by node name" do Puppet::Node::Facts.indirection.find("foo").should == @foo_facts end it "should return nil if no node instance can be found" do Puppet::Node::Facts.indirection.find("non-existent node").should == nil end end describe "#search" do def search_request(conditions) Puppet::Indirector::Request.new(:facts, :search, nil, conditions) end before :each do @now = Time.now @foo = Puppet::Node::Facts.new("foo", "fact1" => "value1", "fact2" => "value2", "uptime_days" => "30") @bar = Puppet::Node::Facts.new("bar", "fact1" => "value1", "uptime_days" => "60") @baz = Puppet::Node::Facts.new("baz", "fact1" => "value2", "fact2" => "value1", "uptime_days" => "90") @bat = Puppet::Node::Facts.new("bat") @foo.timestamp = @now - 3600*1 @bar.timestamp = @now - 3600*3 @baz.timestamp = @now - 3600*5 @bat.timestamp = @now - 3600*7 [@foo, @bar, @baz, @bat].each {|facts| Puppet::Node::Facts.indirection.save(facts)} end it "should return node names that match 'equal' constraints" do request = search_request('facts.fact1.eq' => 'value1', 'facts.fact2.eq' => 'value2') terminus.search(request).should == ["foo"] end it "should return node names that match 'not equal' constraints" do request = search_request('facts.fact1.ne' => 'value2') terminus.search(request).should == ["bar","foo"] end it "should return node names that match strict inequality constraints" do request = search_request('facts.uptime_days.gt' => '20', 'facts.uptime_days.lt' => '70') terminus.search(request).should == ["bar","foo"] end it "should return node names that match non-strict inequality constraints" do request = search_request('facts.uptime_days.ge' => '30', 'facts.uptime_days.le' => '60') terminus.search(request).should == ["bar","foo"] end it "should return node names whose facts are within a given timeframe" do request = search_request('meta.timestamp.ge' => @now - 3600*5, 'meta.timestamp.le' => @now - 3600*1) terminus.search(request).should == ["bar","baz","foo"] end it "should return node names whose facts are from a specific time" do request = search_request('meta.timestamp.eq' => @now - 3600*3) terminus.search(request).should == ["bar"] end it "should return node names whose facts are not from a specific time" do request = search_request('meta.timestamp.ne' => @now - 3600*1) terminus.search(request).should == ["bar","bat","baz"] end it "should perform strict searches on nodes by timestamp" do request = search_request('meta.timestamp.gt' => @now - 3600*5, 'meta.timestamp.lt' => @now - 3600*1) terminus.search(request).should == ["bar"] end it "should search nodes based on both facts and timestamp values" do request = search_request('facts.uptime_days.gt' => '45', 'meta.timestamp.lt' => @now - 3600*4) terminus.search(request).should == ["baz"] end end end diff --git a/spec/unit/indirector/facts/store_configs_spec.rb b/spec/unit/indirector/facts/store_configs_spec.rb new file mode 100755 index 000000000..d302d17f8 --- /dev/null +++ b/spec/unit/indirector/facts/store_configs_spec.rb @@ -0,0 +1,17 @@ +#!/usr/bin/env rspec +require 'spec_helper' +require 'puppet/node' +require 'puppet/indirector/memory' +require 'puppet/indirector/facts/store_configs' + +class Puppet::Node::Facts::StoreConfigsTesting < Puppet::Indirector::Memory +end + +describe Puppet::Node::Facts::StoreConfigs do + after :all do + Puppet::Node::Facts.indirection.reset_terminus_class + Puppet::Node::Facts.indirection.cache_class = nil + end + + it_should_behave_like "a StoreConfigs terminus" +end diff --git a/spec/unit/indirector/node/store_configs_spec.rb b/spec/unit/indirector/node/store_configs_spec.rb new file mode 100755 index 000000000..004ea4ed1 --- /dev/null +++ b/spec/unit/indirector/node/store_configs_spec.rb @@ -0,0 +1,16 @@ +#!/usr/bin/env rspec +require 'spec_helper' +require 'puppet/node' +require 'puppet/indirector/node/store_configs' + +class Puppet::Node::StoreConfigsTesting < Puppet::Indirector::Memory +end + +describe Puppet::Node::StoreConfigs do + after :each do + Puppet::Node.indirection.reset_terminus_class + Puppet::Node.indirection.cache_class = nil + end + + it_should_behave_like "a StoreConfigs terminus" +end diff --git a/spec/unit/indirector/store_configs_spec.rb b/spec/unit/indirector/store_configs_spec.rb new file mode 100755 index 000000000..4ff22a292 --- /dev/null +++ b/spec/unit/indirector/store_configs_spec.rb @@ -0,0 +1,8 @@ +#!/usr/bin/env rspec +require 'spec_helper' + +require 'puppet/indirector/store_configs' + +describe Puppet::Indirector::StoreConfigs do + pending "REVISIT: creating an instance requires ludicrous amounts of stubbing, and there is relatively little to actually test here. What to do? Shared behaviours allow us to push down a lot of the testing into the implementation class tests anyhow..." +end