summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuke Kanies <luke@madstop.com>2008-05-19 22:09:00 -0500
committerLuke Kanies <luke@madstop.com>2008-05-19 22:09:00 -0500
commit3b6a614b02676b8201262605ff982aa9de96a65c (patch)
tree8c475104275a54a3c06bdb5d4f195799ac9d884e
parent77ee4ec6ca56973ce315358864722a152557857f (diff)
parent0820819e0f7e81f2e68893258145877f756b5395 (diff)
downloadpuppet-3b6a614b02676b8201262605ff982aa9de96a65c.tar.gz
puppet-3b6a614b02676b8201262605ff982aa9de96a65c.tar.xz
puppet-3b6a614b02676b8201262605ff982aa9de96a65c.zip
Merge commit 'plathrop/fix-1228' into 0.24.x
-rw-r--r--lib/puppet/util/storage.rb4
-rwxr-xr-xspec/unit/util/storage.rb237
2 files changed, 241 insertions, 0 deletions
diff --git a/lib/puppet/util/storage.rb b/lib/puppet/util/storage.rb
index 9358a28e9..dc4e9cd71 100644
--- a/lib/puppet/util/storage.rb
+++ b/lib/puppet/util/storage.rb
@@ -6,6 +6,10 @@ class Puppet::Util::Storage
include Singleton
include Puppet::Util
+ def self.state
+ return @@state
+ end
+
def initialize
self.class.load
end
diff --git a/spec/unit/util/storage.rb b/spec/unit/util/storage.rb
new file mode 100755
index 000000000..55d1d1f61
--- /dev/null
+++ b/spec/unit/util/storage.rb
@@ -0,0 +1,237 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../spec_helper'
+
+require 'yaml'
+require 'tempfile'
+
+require 'puppet/util/storage'
+
+describe Puppet::Util::Storage do
+ before(:all) do
+ Puppet[:statedir] = Dir.tmpdir()
+ end
+
+ before(:each) do
+ Puppet::Util::Storage.clear()
+ end
+
+ describe "when caching a symbol" do
+ it "should return an empty hash" do
+ Puppet::Util::Storage.cache(:yayness).should == {}
+ Puppet::Util::Storage.cache(:more_yayness).should == {}
+ end
+
+ it "should add the symbol to its internal state" do
+ Puppet::Util::Storage.cache(:yayness)
+ Puppet::Util::Storage.state().should == {:yayness=>{}}
+ end
+
+ it "should not clobber existing state when caching additional objects" do
+ Puppet::Util::Storage.cache(:yayness)
+ Puppet::Util::Storage.state().should == {:yayness=>{}}
+ Puppet::Util::Storage.cache(:bubblyness)
+ Puppet::Util::Storage.state().should == {:yayness=>{},:bubblyness=>{}}
+ end
+ end
+
+ describe "when caching a Puppet::Type" do
+ before(:all) do
+ @file_test = Puppet.type(:file).create(:name => "/yayness", :check => %w{checksum type})
+ @exec_test = Puppet.type(:exec).create(:name => "/bin/ls /yayness")
+ end
+
+ it "should return an empty hash" do
+ Puppet::Util::Storage.cache(@file_test).should == {}
+ Puppet::Util::Storage.cache(@exec_test).should == {}
+ end
+
+ it "should add the resource ref to its internal state" do
+ Puppet::Util::Storage.state().should == {}
+ Puppet::Util::Storage.cache(@file_test)
+ Puppet::Util::Storage.state().should == {"File[/yayness]"=>{}}
+ Puppet::Util::Storage.cache(@exec_test)
+ Puppet::Util::Storage.state().should == {"File[/yayness]"=>{}, "Exec[/bin/ls /yayness]"=>{}}
+ end
+ end
+
+ describe "when caching invalid objects" do
+ before(:all) do
+ @bogus_objects = [ {}, [], "foo", 42, nil, Tempfile.new('storage_test') ]
+ end
+
+ it "should raise an ArgumentError" do
+ @bogus_objects.each do |object|
+ proc { Puppet::Util::Storage.cache(object) }.should raise_error()
+ end
+ end
+
+ it "should not add anything to its internal state" do
+ @bogus_objects.each do |object|
+ begin
+ Puppet::Util::Storage.cache(object)
+ rescue
+ Puppet::Util::Storage.state().should == {}
+ end
+ end
+ end
+ end
+
+ it "should clear its internal state when clear() is called" do
+ Puppet::Util::Storage.cache(:yayness)
+ Puppet::Util::Storage.state().should == {:yayness=>{}}
+ Puppet::Util::Storage.clear()
+ Puppet::Util::Storage.state().should == {}
+ end
+
+ describe "when loading from the state file" do
+ describe "when the state file/directory does not exist" do
+ before(:each) do
+ transient = Tempfile.new('storage_test')
+ @path = transient.path()
+ transient.close!()
+ end
+
+ it "should not fail to load()" do
+ FileTest.exists?(@path).should be_false()
+ Puppet[:statedir] = @path
+ proc { Puppet::Util::Storage.load() }.should_not raise_error()
+ Puppet[:statefile] = @path
+ proc { Puppet::Util::Storage.load() }.should_not raise_error()
+ end
+
+ it "should not lose its internal state when load() is called" do
+ FileTest.exists?(@path).should be_false()
+
+ Puppet::Util::Storage.cache(:yayness)
+ Puppet::Util::Storage.state().should == {:yayness=>{}}
+
+ Puppet[:statefile] = @path
+ proc { Puppet::Util::Storage.load() }.should_not raise_error()
+
+ Puppet::Util::Storage.state().should == {:yayness=>{}}
+ end
+ end
+
+ describe "when the state file/directory exists" do
+ before(:each) do
+ @state_file = Tempfile.new('storage_test')
+ @saved_statefile = Puppet[:statefile]
+ Puppet[:statefile] = @state_file.path()
+ end
+
+ it "should overwrite its internal state if load() is called" do
+ # Should the state be overwritten even if Puppet[:statefile] is not valid YAML?
+ Puppet::Util::Storage.cache(:yayness)
+ Puppet::Util::Storage.state().should == {:yayness=>{}}
+
+ proc { Puppet::Util::Storage.load() }.should_not raise_error()
+ Puppet::Util::Storage.state().should == {}
+ end
+
+ it "should restore its internal state if the state file contains valid YAML" do
+ test_yaml = {'File["/yayness"]'=>{"name"=>{:a=>:b,:c=>:d}}}
+ YAML.expects(:load).returns(test_yaml)
+
+ proc { Puppet::Util::Storage.load() }.should_not raise_error()
+ Puppet::Util::Storage.state().should == test_yaml
+ end
+
+ it "should initialize with a clear internal state if the state file does not contain valid YAML" do
+ @state_file.write(:booness)
+
+ proc { Puppet::Util::Storage.load() }.should_not raise_error()
+ Puppet::Util::Storage.state().should == {}
+ end
+
+ it "should raise an error if the state file does not contain valid YAML and cannot be renamed" do
+ @state_file.write(:booness)
+ File.chmod(0000, @state_file.path())
+
+ proc { Puppet::Util::Storage.load() }.should raise_error()
+ end
+
+ it "should attempt to rename the state file if the file is corrupted" do
+ # We fake corruption by causing YAML.load to raise an exception
+ YAML.expects(:load).raises(Puppet::Error)
+ File.expects(:rename).at_least_once
+
+ proc { Puppet::Util::Storage.load() }.should_not raise_error()
+ end
+
+ it "should fail gracefully on load() if the state file is not a regular file" do
+ @state_file.close!()
+ Dir.mkdir(Puppet[:statefile])
+ File.expects(:rename).returns(0)
+
+ proc { Puppet::Util::Storage.load() }.should_not raise_error()
+
+ Dir.rmdir(Puppet[:statefile])
+ end
+
+ it "should fail gracefully on load() if it cannot get a read lock on the state file" do
+ Puppet::Util.expects(:readlock).yields(false)
+ test_yaml = {'File["/yayness"]'=>{"name"=>{:a=>:b,:c=>:d}}}
+ YAML.expects(:load).returns(test_yaml)
+
+ proc { Puppet::Util::Storage.load() }.should_not raise_error()
+ Puppet::Util::Storage.state().should == test_yaml
+ end
+
+ after(:each) do
+ @state_file.close!()
+ Puppet[:statefile] = @saved_statefile
+ end
+ end
+ end
+
+ describe "when storing to the state file" do
+ before(:each) do
+ @state_file = Tempfile.new('storage_test')
+ @saved_statefile = Puppet[:statefile]
+ Puppet[:statefile] = @state_file.path()
+ end
+
+ it "should create the state file if it does not exist" do
+ @state_file.close!()
+ FileTest.exists?(Puppet[:statefile]).should be_false()
+ Puppet::Util::Storage.cache(:yayness)
+
+ proc { Puppet::Util::Storage.store() }.should_not raise_error()
+ FileTest.exists?(Puppet[:statefile]).should be_true()
+ end
+
+ it "should raise an exception if the state file is not a regular file" do
+ @state_file.close!()
+ Dir.mkdir(Puppet[:statefile])
+ Puppet::Util::Storage.cache(:yayness)
+
+ proc { Puppet::Util::Storage.store() }.should raise_error()
+
+ Dir.rmdir(Puppet[:statefile])
+ end
+
+ it "should raise an exception if it cannot get a write lock on the state file" do
+ Puppet::Util.expects(:writelock).yields(false)
+ Puppet::Util::Storage.cache(:yayness)
+
+ proc { Puppet::Util::Storage.store() }.should raise_error()
+ end
+
+ it "should load() the same information that it store()s" do
+ Puppet::Util::Storage.cache(:yayness)
+
+ Puppet::Util::Storage.state().should == {:yayness=>{}}
+ proc { Puppet::Util::Storage.store() }.should_not raise_error()
+ Puppet::Util::Storage.clear()
+ Puppet::Util::Storage.state().should == {}
+ proc { Puppet::Util::Storage.load() }.should_not raise_error()
+ Puppet::Util::Storage.state().should == {:yayness=>{}}
+ end
+
+ after(:each) do
+ @state_file.close!()
+ Puppet[:statefile] = @saved_statefile
+ end
+ end
+end