diff --git a/spec/unit/application/indirection_base_spec.rb b/spec/unit/application/indirection_base_spec.rb index 1610f85ff..2742fc93c 100755 --- a/spec/unit/application/indirection_base_spec.rb +++ b/spec/unit/application/indirection_base_spec.rb @@ -1,44 +1,52 @@ #! /usr/bin/env ruby require 'spec_helper' require 'puppet/util/command_line' require 'puppet/application/indirection_base' require 'puppet/indirector/face' ######################################################################## # Stub for testing; the names are critical, sadly. --daniel 2011-03-30 class Puppet::Application::TestIndirection < Puppet::Application::IndirectionBase end - -face = Puppet::Indirector::Face.define(:test_indirection, '0.0.1') do - summary "fake summary" - copyright "Puppet Labs", 2011 - license "Apache 2 license; see COPYING" -end -# REVISIT: This horror is required because we don't allow anything to be -# :current except for if it lives on, and is loaded from, disk. --daniel 2011-03-29 -face.instance_variable_set('@version', :current) -Puppet::Face.register(face) ######################################################################## describe Puppet::Application::IndirectionBase do + before :all do + face = Puppet::Indirector::Face.define(:test_indirection, '0.0.1') do + summary "fake summary" + copyright "Puppet Labs", 2011 + license "Apache 2 license; see COPYING" + end + # REVISIT: This horror is required because we don't allow anything to be + # :current except for if it lives on, and is loaded from, disk. --daniel 2011-03-29 + face.instance_variable_set('@version', :current) + + Puppet::Face.register(face) + end + + after :all do + # Delete the face so that it doesn't interfere with other specs + Puppet::Interface::FaceCollection.instance_variable_get(:@faces).delete Puppet::Interface::FaceCollection.underscorize(face.name) + end + it "should accept a terminus command line option" do # It would be nice not to have to stub this, but whatever... writing an # entire indirection stack would cause us more grief. --daniel 2011-03-31 terminus = stub_everything("test indirection terminus") terminus.stubs(:name).returns(:test_indirection) # This is necessary because Instrumentation tickles indirection, which # messes up our expectations. Puppet::Util::Instrumentation.stubs(:init) Puppet::Indirector::Indirection.expects(:instance). with(:test_indirection).returns(terminus) command_line = Puppet::Util::CommandLine.new("puppet", %w{test_indirection --terminus foo save bar}) application = Puppet::Application::TestIndirection.new(command_line) expect { application.run }.to exit_with 0 end end diff --git a/spec/unit/interface/face_collection_spec.rb b/spec/unit/interface/face_collection_spec.rb index 3a2082e95..a364a0cde 100755 --- a/spec/unit/interface/face_collection_spec.rb +++ b/spec/unit/interface/face_collection_spec.rb @@ -1,200 +1,199 @@ #! /usr/bin/env ruby require 'spec_helper' require 'tmpdir' require 'puppet/interface' describe Puppet::Interface::FaceCollection do - # To avoid cross-pollution we have to save and restore both the hash - # containing all the interface data, and the array used by require. Restoring - # both means that we don't leak side-effects across the code. --daniel 2011-04-06 - # - # Worse luck, we *also* need to flush $" of anything defining a face, - # because otherwise we can cross-pollute from other test files and end up - # with no faces loaded, but the require value set true. --daniel 2011-04-10 - before :each do - @original_faces = subject.instance_variable_get("@faces").dup - @original_required = $".dup - $".delete_if do |path| path =~ %r{/face/.*\.rb$} end + + # Used to clear faces state before and after tests + # This is done to prevent this spec from interfering with other specs that use faces + def clear_faces + # Reset FaceCollection state subject.instance_variable_get(:@faces).clear - subject.instance_variable_set(:@loaded, false) - @autoload_loaded = {} - Puppet::Util::Autoload.stubs(:loaded).returns(@autoload_loaded) + subject.instance_variable_set :@loaded, false + + # Remove any face files from the list of required files + $".delete_if { |path| path =~ /face\/.*\.rb$/ } + + # Remove all faces from the autoloader + loaded = Puppet::Util::Autoload.instance_variable_get(:@loaded) + loaded.keys.dup.each do |k| + next unless k.start_with? 'puppet/face' + loaded.delete k + end + end + + before :each do + clear_faces end after :each do - # Just pushing the duplicate back into place doesn't work as reliably as - # this method to restore the state. Honestly, I need to make this horror - # go away entirely. --daniel 2012-04-28 - faces = subject.instance_variable_get("@faces") - faces.clear - @original_faces.each {|k,v| faces[k] = v } - - @original_required.each {|f| $".push f unless $".include? f } + clear_faces end describe "::[]" do before :each do subject.instance_variable_get("@faces")[:foo][SemVer.new('0.0.1')] = 10 end it "should return the face with the given name" do subject["foo", '0.0.1'].should == 10 end it "should attempt to load the face if it isn't found" do subject.expects(:require).once.with('puppet/face/bar') subject.expects(:require).once.with('puppet/face/0.0.1/bar') subject["bar", '0.0.1'] end it "should attempt to load the default face for the specified version :current" do subject.expects(:require).with('puppet/face/fozzie') subject['fozzie', :current] end it "should return true if the face specified is registered" do subject.instance_variable_get("@faces")[:foo][SemVer.new('0.0.1')] = 10 subject["foo", '0.0.1'].should == 10 end it "should attempt to require the face if it is not registered" do subject.expects(:require).with do |file| subject.instance_variable_get("@faces")[:bar][SemVer.new('0.0.1')] = true file == 'puppet/face/bar' end subject["bar", '0.0.1'].should be_true end it "should return false if the face is not registered" do subject.stubs(:require).returns(true) subject["bar", '0.0.1'].should be_false end it "should return false if the face file itself is missing" do subject.stubs(:require). raises(LoadError, 'no such file to load -- puppet/face/bar').then. raises(LoadError, 'no such file to load -- puppet/face/0.0.1/bar') subject["bar", '0.0.1'].should be_false end it "should register the version loaded by `:current` as `:current`" do subject.expects(:require).with do |file| subject.instance_variable_get("@faces")[:huzzah]['2.0.1'] = :huzzah_face file == 'puppet/face/huzzah' end subject["huzzah", :current] subject.instance_variable_get("@faces")[:huzzah][:current].should == :huzzah_face end context "with something on disk" do it "should register the version loaded from `puppet/face/{name}` as `:current`" do subject["huzzah", '2.0.1'].should be subject["huzzah", :current].should be Puppet::Face[:huzzah, '2.0.1'].should == Puppet::Face[:huzzah, :current] end it "should index :current when the code was pre-required" do subject.instance_variable_get("@faces")[:huzzah].should_not be_key :current require 'puppet/face/huzzah' subject[:huzzah, :current].should be_true end end it "should not cause an invalid face to be enumerated later" do subject[:there_is_no_face, :current].should be_false subject.faces.should_not include :there_is_no_face end end describe "::get_action_for_face" do it "should return an action on the current face" do Puppet::Face::FaceCollection.get_action_for_face(:huzzah, :bar, :current). should be_an_instance_of Puppet::Interface::Action end it "should return an action on an older version of a face" do action = Puppet::Face::FaceCollection. get_action_for_face(:huzzah, :obsolete, :current) action.should be_an_instance_of Puppet::Interface::Action action.face.version.should == SemVer.new('1.0.0') end it "should load the full older version of a face" do action = Puppet::Face::FaceCollection. get_action_for_face(:huzzah, :obsolete, :current) action.face.version.should == SemVer.new('1.0.0') action.face.should be_action :obsolete_in_core end it "should not add obsolete actions to the current version" do action = Puppet::Face::FaceCollection. get_action_for_face(:huzzah, :obsolete, :current) action.face.version.should == SemVer.new('1.0.0') action.face.should be_action :obsolete_in_core current = Puppet::Face[:huzzah, :current] current.version.should == SemVer.new('2.0.1') current.should_not be_action :obsolete_in_core current.should_not be_action :obsolete end end describe "::register" do it "should store the face by name" do face = Puppet::Face.new(:my_face, '0.0.1') subject.register(face) subject.instance_variable_get("@faces").should == { :my_face => { face.version => face } } end end describe "::underscorize" do faulty = [1, "23foo", "#foo", "$bar", "sturm und drang", :"sturm und drang"] valid = { "Foo" => :foo, :Foo => :foo, "foo_bar" => :foo_bar, :foo_bar => :foo_bar, "foo-bar" => :foo_bar, :"foo-bar" => :foo_bar, "foo_bar23" => :foo_bar23, :foo_bar23 => :foo_bar23, } valid.each do |input, expect| it "should map #{input.inspect} to #{expect.inspect}" do result = subject.underscorize(input) result.should == expect end end faulty.each do |input| it "should fail when presented with #{input.inspect} (#{input.class})" do expect { subject.underscorize(input) }. to raise_error ArgumentError, /not a valid face name/ end end end context "faulty faces" do before :each do $:.unshift "#{PuppetSpec::FIXTURE_DIR}/faulty_face" end after :each do $:.delete_if {|x| x == "#{PuppetSpec::FIXTURE_DIR}/faulty_face"} end it "should not die if a face has a syntax error" do subject.faces.should be_include :help subject.faces.should_not be_include :syntax @logs.should_not be_empty @logs.first.message.should =~ /syntax error/ end end end