require 'spec_helper' require 'hiera/backend/yaml_backend' class Hiera module Backend describe Yaml_backend do before do Hiera.stubs(:debug) Hiera.stubs(:warn) @backend = Yaml_backend.new @backend.stubs(:stale?).returns(true) end describe "#initialize" do it "should announce its creation" do # because other specs checks this Hiera.expects(:debug).with("Hiera YAML backend starting") Yaml_backend.new end end describe "#lookup" do it "should look for data in all sources" do Backend.expects(:datasources).multiple_yields(["one"], ["two"]) Backend.expects(:datafile).with(:yaml, {}, "one", "yaml").returns(nil) Backend.expects(:datafile).with(:yaml, {}, "two", "yaml").returns(nil) @backend.lookup("key", {}, nil, :priority) end it "should pick data earliest source that has it for priority searches" do Backend.expects(:datasources).multiple_yields(["one"], ["two"]) Backend.expects(:datafile).with(:yaml, {}, "one", "yaml").returns("/nonexisting/one.yaml") Backend.expects(:datafile).with(:yaml, {}, "two", "yaml").returns(nil).never YAML.expects(:load_file).with("/nonexisting/one.yaml").returns(YAML.load("---\nkey: answer")) @backend.lookup("key", {}, nil, :priority).should == "answer" end it "should not look up missing data files" do Backend.expects(:datasources).multiple_yields(["one"]) Backend.expects(:datafile).with(:yaml, {}, "one", "yaml").returns(nil) YAML.expects(:load_file).never @backend.lookup("key", {}, nil, :priority) end it "should return nil for empty data files" do Backend.expects(:datasources).multiple_yields(["one"]) Backend.expects(:datafile).with(:yaml, {}, "one", "yaml").returns("/nonexisting/one.yaml") YAML.expects(:load_file).with("/nonexisting/one.yaml").returns(YAML.load("")) @backend.lookup("key", {}, nil, :priority).should be_nil end it "should build an array of all data sources for array searches" do Backend.expects(:datasources).multiple_yields(["one"], ["two"]) Backend.expects(:datafile).with(:yaml, {}, "one", "yaml").returns("/nonexisting/one.yaml") Backend.expects(:datafile).with(:yaml, {}, "two", "yaml").returns("/nonexisting/two.yaml") YAML.expects(:load_file).with("/nonexisting/one.yaml").returns(YAML.load("---\nkey: answer")) YAML.expects(:load_file).with("/nonexisting/two.yaml").returns(YAML.load("---\nkey: answer")) @backend.lookup("key", {}, nil, :array).should == ["answer", "answer"] end it "should ignore empty hash of data sources for hash searches" do Backend.expects(:datasources).multiple_yields(["one"], ["two"]) Backend.expects(:datafile).with(:yaml, {}, "one", "yaml").returns("/nonexisting/one.yaml") Backend.expects(:datafile).with(:yaml, {}, "two", "yaml").returns("/nonexisting/two.yaml") YAML.expects(:load_file).with("/nonexisting/one.yaml").returns(YAML.load("")) YAML.expects(:load_file).with("/nonexisting/two.yaml").returns(YAML.load("---\nkey:\n a: answer")) @backend.lookup("key", {}, nil, :hash).should == {"a" => "answer"} end it "should build a merged hash of data sources for hash searches" do Backend.expects(:datasources).multiple_yields(["one"], ["two"]) Backend.expects(:datafile).with(:yaml, {}, "one", "yaml").returns("/nonexisting/one.yaml") Backend.expects(:datafile).with(:yaml, {}, "two", "yaml").returns("/nonexisting/two.yaml") YAML.expects(:load_file).with("/nonexisting/one.yaml").returns(YAML.load("---\nkey:\n a: answer")) YAML.expects(:load_file).with("/nonexisting/two.yaml").returns(YAML.load("---\nkey:\n a: wrong\n b: answer")) @backend.lookup("key", {}, nil, :hash).should == {"a" => "answer", "b" => "answer"} end it "should fail when trying to << a Hash" do Backend.expects(:datasources).multiple_yields(["one"], ["two"]) Backend.expects(:datafile).with(:yaml, {}, "one", "yaml").returns("/nonexisting/one.yaml") Backend.expects(:datafile).with(:yaml, {}, "two", "yaml").returns("/nonexisting/two.yaml") YAML.expects(:load_file).with("/nonexisting/one.yaml").returns(YAML.load("---\nkey:\n- a\n- answer")) YAML.expects(:load_file).with("/nonexisting/two.yaml").returns(YAML.load("---\nkey:\n a: answer")) lambda {@backend.lookup("key", {}, nil, :array)}.should raise_error(Exception, "Hiera type mismatch: expected Array and got Hash") end it "should fail when trying to merge an Array" do Backend.expects(:datasources).multiple_yields(["one"], ["two"]) Backend.expects(:datafile).with(:yaml, {}, "one", "yaml").returns("/nonexisting/one.yaml") Backend.expects(:datafile).with(:yaml, {}, "two", "yaml").returns("/nonexisting/two.yaml") YAML.expects(:load_file).with("/nonexisting/one.yaml").returns(YAML.load("---\nkey:\n a: answer")) YAML.expects(:load_file).with("/nonexisting/two.yaml").returns(YAML.load("---\nkey:\n- a\n- wrong")) lambda {@backend.lookup("key", {}, nil, :hash)}.should raise_error(Exception, "Hiera type mismatch: expected Hash and got Array") end it "should parse the answer for scope variables" do Backend.expects(:datasources).yields("one") Backend.expects(:datafile).with(:yaml, {"rspec" => "test"}, "one", "yaml").returns("/nonexisting/one.yaml") YAML.expects(:load_file).with("/nonexisting/one.yaml").returns(YAML.load("---\nkey: 'test_%{rspec}'")) @backend.lookup("key", {"rspec" => "test"}, nil, :priority).should == "test_test" end it "should retain datatypes found in yaml files" do Backend.expects(:datasources).yields("one").times(3) Backend.expects(:datafile).with(:yaml, {}, "one", "yaml").returns("/nonexisting/one.yaml").times(3) YAML.expects(:load_file).with("/nonexisting/one.yaml").returns(YAML.load("---\nstringval: 'string'\nboolval: true\nnumericval: 1")).times(3) @backend.lookup("stringval", {}, nil, :priority).should == "string" @backend.lookup("boolval", {}, nil, :priority).should == true @backend.lookup("numericval", {}, nil, :priority).should == 1 end end end describe '#stale?' do before do Hiera.stubs(:debug) Hiera.stubs(:warn) @backend = Yaml_backend.new @fakestat = Struct.new(:ino, :mtime, :size) end def create_yaml_file(data, path) File.open(path, 'w') do |f| f.write(data) end end def update_file(data, path) File.open(path, 'a') do |f| f.write(data) end end it 'should report a stale cache if a data lookup has not been performed' do tmp_yamlfile = Pathname(Dir.mktmpdir('yaml')) + 'yamlfile' create_yaml_file({'foo' => 'bar'}.to_yaml, tmp_yamlfile) @backend.stale?(tmp_yamlfile).should == true end describe 'lookup tests' do before(:each) do @tmp_yamlfile = Pathname(Dir.mktmpdir('yaml')) + 'yamlfile' create_yaml_file({'foo' => 'bar'}.to_yaml, @tmp_yamlfile) Backend.expects(:datasources).yields("one") Backend.expects(:datafile).with(:yaml, {}, "one", "yaml").returns(@tmp_yamlfile) end it 'should not report a stale cache after a data lookup' do @backend.stale?(@tmp_yamlfile).should == true @backend.lookup('foo', {}, nil, :priority).should == 'bar' @backend.stale?(@tmp_yamlfile).should == false end [:ino, :mtime, :size].each do |attribute| it "should report a stale cache if a backend file's #{attribute} has changed" do @stat_instance = @fakestat.new(1234, 1234, 1234) File.expects(:stat).with(@tmp_yamlfile).returns(@stat_instance).twice @backend.stale?(@tmp_yamlfile).should == true @backend.lookup('foo', {}, nil, :priority).should == 'bar' @backend.stale?(@tmp_yamlfile).should == false @stat_instance[attribute] += 1 File.unstub && File.expects(:stat).with(@tmp_yamlfile).returns(@stat_instance) @backend.stale?(@tmp_yamlfile).should == true end end end end end end