+#!/usr/bin/env rspec
+
+require 'spec_helper'
+
+module MCollective
+ describe Cache do
+ before do
+ @locks_mutex = Cache.instance_variable_set("@locks_mutex", Mutex.new)
+ @cache_locks = Cache.instance_variable_set("@cache_locks", {})
+ @cache = Cache.instance_variable_set("@cache", {})
+ end
+
+ describe "#check_cache!" do
+ it "should correctly check for valid caches" do
+ Cache.expects(:has_cache?).with("rspec").returns(true)
+ Cache.expects(:has_cache?).with("fail").returns(false)
+
+ Cache.check_cache!("rspec")
+ expect { Cache.check_cache!("fail") }.to raise_code("Could not find a cache called '%{cache_name}'", :cache_name => "fail")
+ end
+ end
+
+ describe "#setup" do
+ it "should use a mutex to manage access to the cache" do
+ @locks_mutex.expects(:synchronize).yields
+ Cache.setup("x").should == true
+ @cache.should == {"x" => {:max_age => 300.0}}
+ end
+
+ it "should correctly setup a new cache" do
+ @locks_mutex.expects(:synchronize).twice.yields
+ Cache.setup("rspec1", 300)
+ @cache["rspec1"].should == {:max_age => 300.0}
+
+ Cache.setup("rspec2")
+ @cache["rspec2"].should == {:max_age => 300.0}
+ end
+ end
+
+ describe "#has_cache?" do
+ it "should correctly report presense of a cache" do
+ Cache.setup("rspec")
+ Cache.has_cache?("rspec").should == true
+ Cache.has_cache?("fail").should == false
+ end
+ end
+
+ describe "#delete!" do
+ it "should delete the cache and return true" do
+ Cache.expects(:check_cache!).with("rspec")
+
+ Cache.setup("rspec")
+ Cache.delete!("rspec").should == true
+ end
+ end
+
+ describe "#write" do
+ it "should write to the cache" do
+ time = Time.now
+ Time.expects(:now).returns(time)
+ Cache.expects(:check_cache!).with("rspec")
+
+ Cache.setup("rspec")
+ Cache.write("rspec", :key, :val).should == :val
+
+ @cache["rspec"][:key][:value].should == :val
+ @cache["rspec"][:key][:cache_create_time].should == time
+ end
+ end
+
+ describe "#read" do
+ it "should read a written entry correctly" do
+ Cache.setup("rspec")
+ Cache.write("rspec", :key, :val)
+
+ Cache.expects(:check_cache!).with("rspec")
+ Cache.expects(:ttl).with("rspec", :key).returns(1)
+
+ Cache.read("rspec", :key).should == :val
+ end
+
+ it "should raise on expired reads" do
+ Cache.setup("rspec")
+ Cache.write("rspec", :key, :val)
+
+ Cache.expects(:ttl).returns(0)
+
+ Cache.expects(:check_cache!).with("rspec")
+
+ expect { Cache.read("rspec", :key) }.to raise_code("Cache expired on '%{cache_name}' key '%{item}'", :cache_name => "rspec", :item => :key)
+ end
+ end
+
+ describe "#invalidate!" do
+ it "should return false for unknown keys" do
+ Cache.expects(:check_cache!).with("rspec")
+
+ @locks_mutex.expects(:synchronize).yields
+
+ Cache.setup("rspec")
+ Cache.invalidate!("rspec", "no_such_key").should == false
+ end
+
+ it "should delete the key" do
+ Cache.setup("rspec")
+ Cache.write("rspec", "valid_key", "rspec")
+
+ Cache.expects(:check_cache!).with("rspec")
+ @cache["rspec"].expects(:delete).with("valid_key")
+
+ Cache.invalidate!("rspec", "valid_key")
+ end
+ end
+
+ describe "#ttl" do
+ it "should detect invalid key names" do
+ Cache.expects(:check_cache!).with("rspec")
+ Cache.setup("rspec", 300)
+ expect { Cache.ttl("rspec", :key) }.to raise_code("No item called '%{item}' for cache '%{cache_name}'", :cache_name => "rspec", :item => :key)
+ end
+
+ it "should return >0 for valid" do
+ Cache.setup("rspec", 300)
+ Cache.write("rspec", :key, :val)
+
+ Cache.expects(:check_cache!).with("rspec")
+ Cache.ttl("rspec", :key).should >= 0
+ end
+
+ it "should return <0 for expired messages" do
+ Cache.setup("rspec", 300)
+ Cache.write("rspec", :key, :val)
+
+ time = Time.now + 600
+ Time.expects(:now).returns(time)
+
+ Cache.expects(:check_cache!).with("rspec")
+ Cache.ttl("rspec", :key).should <= 0
+ end
+ end
+
+ describe "#synchronize" do
+ it "should use the correct mutex" do
+ Cache.expects(:check_cache!).with("rspec")
+ Cache.setup("rspec")
+
+ rspec_lock = @cache_locks["rspec"]
+ rspec_lock.expects(:synchronize).yields
+
+ @cache_locks.expects("[]").with("rspec").returns(rspec_lock)
+
+ ran = 0
+ Cache.synchronize("rspec") do
+ ran = 1
+ end
+
+ ran.should == 1
+ end
+ end
+ end
+end