#! /usr/bin/env ruby require 'spec_helper' require 'facter/util/loader' # loader subclass for making assertions about file/directory ordering class TestLoader < Facter::Util::Loader def loaded_files @loaded_files ||= [] end def load_file(file) loaded_files << file super end end describe Facter::Util::Loader do before :each do Facter::Util::Loader.any_instance.unstub(:load_all) end it "should have a method for loading individual facts by name" do Facter::Util::Loader.new.should respond_to(:load) end it "should have a method for loading all facts" do Facter::Util::Loader.new.should respond_to(:load_all) end it "should have a method for returning directories containing facts" do Facter::Util::Loader.new.should respond_to(:search_path) end describe "#valid_seach_path?" do before :each do @loader = Facter::Util::Loader.new @settings = mock 'settings' @settings.stubs(:value).returns "/eh" end it "should cache the result of a previous check" do Pathname.any_instance.expects(:absolute?).returns(true).once # we explicitly want two calls here to check that we get # the second from the cache @loader.should be_valid_search_path "/foo" @loader.should be_valid_search_path "/foo" end # Used to have test for " " as a directory since that should # be a relative directory, but on Windows in both 1.8.7 and # 1.9.3 it is an absolute directory (WTF Windows). Considering # we didn't have a valid use case for a " " directory, the # test was removed. [ '.', '..', '...', '.foo', '../foo', 'foo', 'foo/bar', 'foo/../bar', ' /', ' \/', ].each do |dir| it "should be false for relative path #{dir}" do @loader.should_not be_valid_search_path dir end end [ '/.', '/..', '/...', '/.foo', '/../foo', '/foo', '/foo/bar', '/foo/../bar', '/ ', '/ /..', ].each do |dir| it "should be true for absolute path #{dir}" do @loader.should be_valid_search_path dir end end end describe "when determining the search path" do before do @loader = Facter::Util::Loader.new @settings = mock 'settings' @settings.stubs(:value).returns "/eh" end it "should include the facter subdirectory of all paths in ruby LOAD_PATH" do dirs = $LOAD_PATH.collect { |d| File.join(d, "facter") } @loader.stubs(:valid_search_path?).returns(true) paths = @loader.search_path dirs.each do |dir| paths.should be_include(dir) end end it "should warn the user when an invalid search path has been excluded" do dirs = $LOAD_PATH.collect { |d| File.join(d, "facter") } @loader.stubs(:valid_search_path?).returns(false) dirs.each do |dir| Facter.expects(:debugonce).with("Relative directory #{dir} removed from search path.").once end paths = @loader.search_path end it "should exclude invalid search paths" do dirs = $LOAD_PATH.collect { |d| File.join(d, "facter") } @loader.stubs(:valid_search_path?).returns(false) paths = @loader.search_path dirs.each do |dir| paths.should_not be_include(dir) end end it "should include all search paths registered with Facter" do Facter.expects(:search_path).returns %w{/one /two} paths = @loader.search_path paths.should be_include("/one") paths.should be_include("/two") end describe "and the FACTERLIB environment variable is set" do it "should include all paths in FACTERLIB" do Facter::Util::Resolution.with_env "FACTERLIB" => "/one/path#{File::PATH_SEPARATOR}/two/path" do paths = @loader.search_path %w{/one/path /two/path}.each do |dir| paths.should be_include(dir) end end end end end describe "when loading facts" do before do @loader = Facter::Util::Loader.new @loader.stubs(:search_path).returns [] end it "should load values from the matching environment variable if one is present" do Facter.expects(:add).with("testing") Facter::Util::Resolution.with_env "facter_testing" => "yayness" do @loader.load(:testing) end end it "should load any files in the search path with names matching the fact name" do @loader.expects(:search_path).returns %w{/one/dir /two/dir} FileTest.stubs(:exist?).returns false FileTest.expects(:exist?).with("/one/dir/testing.rb").returns true FileTest.expects(:exist?).with("/two/dir/testing.rb").returns true Kernel.expects(:load).with("/one/dir/testing.rb") Kernel.expects(:load).with("/two/dir/testing.rb") @loader.load(:testing) end it 'should load any ruby files in directories matching the fact name in the search path in sorted order regardless of the order returned by Dir.entries' do @loader = TestLoader.new @loader.stubs(:search_path).returns %w{/one/dir} FileTest.stubs(:exist?).returns false FileTest.stubs(:directory?).with("/one/dir/testing").returns true @loader.stubs(:search_path).returns %w{/one/dir} Dir.stubs(:entries).with("/one/dir/testing").returns %w{foo.rb bar.rb} %w{/one/dir/testing/foo.rb /one/dir/testing/bar.rb}.each do |f| File.stubs(:directory?).with(f).returns false Kernel.stubs(:load).with(f) end @loader.load(:testing) @loader.loaded_files.should == %w{/one/dir/testing/bar.rb /one/dir/testing/foo.rb} end it "should load any ruby files in directories matching the fact name in the search path" do @loader.expects(:search_path).returns %w{/one/dir} FileTest.stubs(:exist?).returns false FileTest.expects(:directory?).with("/one/dir/testing").returns true Dir.expects(:entries).with("/one/dir/testing").returns %w{two.rb} Kernel.expects(:load).with("/one/dir/testing/two.rb") @loader.load(:testing) end it "should not load files that don't end in '.rb'" do @loader.expects(:search_path).returns %w{/one/dir} FileTest.stubs(:exist?).returns false FileTest.expects(:directory?).with("/one/dir/testing").returns true Dir.expects(:entries).with("/one/dir/testing").returns %w{one} Kernel.expects(:load).never @loader.load(:testing) end end describe "when loading all facts" do before :each do @loader = Facter::Util::Loader.new @loader.stubs(:search_path).returns [] FileTest.stubs(:directory?).returns true end it "should skip directories that do not exist" do @loader.expects(:search_path).returns %w{/one/dir} FileTest.expects(:directory?).with("/one/dir").returns false Dir.expects(:entries).with("/one/dir").never @loader.load_all end it "should load all files in all search paths" do @loader.expects(:search_path).returns %w{/one/dir /two/dir} Dir.expects(:entries).with("/one/dir").returns %w{a.rb b.rb} Dir.expects(:entries).with("/two/dir").returns %w{c.rb d.rb} %w{/one/dir/a.rb /one/dir/b.rb /two/dir/c.rb /two/dir/d.rb}.each { |f| Kernel.expects(:load).with(f) } @loader.load_all end it "should load all files in all subdirectories in all search paths" do @loader.expects(:search_path).returns %w{/one/dir /two/dir} Dir.expects(:entries).with("/one/dir").returns %w{a} Dir.expects(:entries).with("/two/dir").returns %w{b} %w{/one/dir/a /two/dir/b}.each { |f| File.expects(:directory?).with(f).returns true } Dir.expects(:entries).with("/one/dir/a").returns %w{c.rb} Dir.expects(:entries).with("/two/dir/b").returns %w{d.rb} %w{/one/dir/a/c.rb /two/dir/b/d.rb}.each { |f| Kernel.expects(:load).with(f) } @loader.load_all end it 'should load all files in sorted order for any given directory regardless of the order returned by Dir.entries' do @loader = TestLoader.new @loader.stubs(:search_path).returns %w{/one/dir} Dir.stubs(:entries).with("/one/dir").returns %w{foo.rb bar.rb} %w{/one/dir}.each { |f| File.stubs(:directory?).with(f).returns true } %w{/one/dir/foo.rb /one/dir/bar.rb}.each do |f| File.stubs(:directory?).with(f).returns false Kernel.expects(:load).with(f) end @loader.load_all @loader.loaded_files.should == %w{/one/dir/bar.rb /one/dir/foo.rb} end it "should not load files in the util subdirectory" do @loader.expects(:search_path).returns %w{/one/dir} Dir.expects(:entries).with("/one/dir").returns %w{util} File.expects(:directory?).with("/one/dir/util").returns true Dir.expects(:entries).with("/one/dir/util").never @loader.load_all end it "should not load files in a lib subdirectory" do @loader.expects(:search_path).returns %w{/one/dir} Dir.expects(:entries).with("/one/dir").returns %w{lib} File.expects(:directory?).with("/one/dir/lib").returns true Dir.expects(:entries).with("/one/dir/lib").never @loader.load_all end it "should not load files in '.' or '..'" do @loader.expects(:search_path).returns %w{/one/dir} Dir.expects(:entries).with("/one/dir").returns %w{. ..} File.expects(:entries).with("/one/dir/.").never File.expects(:entries).with("/one/dir/..").never @loader.load_all end it "should not raise an exception when a file is unloadable" do @loader.expects(:search_path).returns %w{/one/dir} Dir.expects(:entries).with("/one/dir").returns %w{a.rb} Kernel.expects(:load).with("/one/dir/a.rb").raises(LoadError) @loader.expects(:warn) lambda { @loader.load_all }.should_not raise_error end it "should load all facts from the environment" do Facter.expects(:add).with('one') Facter.expects(:add).with('two') Facter::Util::Resolution.with_env "facter_one" => "yayness", "facter_two" => "boo" do @loader.load_all end end it "should only load all facts one time" do @loader.expects(:load_env).once @loader.load_all @loader.load_all end end it "should load facts on the facter search path only once" do facterlibdir = File.expand_path(File.dirname(__FILE__) + '../../../fixtures/unit/util/loader') Facter::Util::Resolution.with_env 'FACTERLIB' => facterlibdir do Facter::Util::Loader.new.load_all Facter.value(:nosuchfact).should be_nil end end end