describe Ridley::ChefObject do let(:resource) { double('chef-resource') } describe "ClassMethods" do subject { Class.new(described_class) } describe "::new" do it "mass assigns the given attributes" do new_attrs = { name: "a name" } subject.any_instance.should_receive(:mass_assign).with(new_attrs) subject.new(resource, new_attrs) end end describe "::set_chef_type" do it "sets the chef_type attr on the class" do subject.set_chef_type("environment") subject.chef_type.should eql("environment") end end describe "::set_chef_json_class" do it "sets the chef_json_class attr on the class" do subject.set_chef_json_class("Chef::Environment") subject.chef_json_class.should eql("Chef::Environment") end end describe "::set_chef_id" do it "sets the chef_id attribute on the class" do subject.set_chef_id(:environment) subject.chef_id.should eql(:environment) end end describe "::chef_type" do it "returns the underscored name of the including class if nothing is set" do subject.chef_type.should eql(subject.class.name.underscore) end end describe "::chef_json_class" do it "returns the chef_json if nothing has been set" do subject.chef_json_class.should be_nil end end describe "::chef_id" do it "returns nil if nothing is set" do subject.chef_id.should be_nil end end end subject do Class.new(described_class).new(resource) end describe "#save" do context "when the object is valid" do before(:each) { subject.stub(:valid?).and_return(true) } it "sends a create message to the implementing class" do updated = double('updated') updated.stub(:_attributes_).and_return(Hash.new) resource.should_receive(:create).with(subject).and_return(updated) subject.save end context "when there is an HTTPConflict" do it "sends the update message to self" do updated = double('updated') updated.stub(:[]).and_return(Hash.new) updated.stub(:_attributes_).and_return(Hash.new) resource.should_receive(:create).and_raise(Ridley::Errors::HTTPConflict.new(updated)) subject.should_receive(:update).and_return(updated) subject.save end end end context "when the object is invalid" do before(:each) { subject.stub(:valid?).and_return(false) } it "raises an InvalidResource error" do lambda { subject.save }.should raise_error(Ridley::Errors::InvalidResource) end end end describe "#update" do context "when the object is valid" do let(:updated) do updated = double('updated') updated.stub(:[]).and_return(Hash.new) updated.stub(:_attributes_).and_return(Hash.new) updated end before(:each) { subject.stub(:valid?).and_return(true) } it "sends an update message to the implementing class" do resource.should_receive(:update).with(subject).and_return(updated) subject.update end it "returns true" do resource.should_receive(:update).with(subject).and_return(updated) subject.update.should eql(true) end end context "when the object is invalid" do before(:each) { subject.stub(:valid?).and_return(false) } it "raises an InvalidResource error" do lambda { subject.update }.should raise_error(Ridley::Errors::InvalidResource) end end end describe "#chef_id" do it "returns the value of the chef_id attribute" do subject.class.attribute(:name) subject.class.stub(:chef_id) { :name } subject.mass_assign(name: "reset") subject.chef_id.should eql("reset") end end describe "#reload" do let(:updated_subject) { double('updated_subject', _attributes_: { fake_attribute: "some_value" }) } before(:each) do subject.class.attribute(:fake_attribute) resource.should_receive(:find).with(subject).and_return(updated_subject) end it "returns itself" do subject.reload.should eql(subject) end it "sets the attributes of self to include those of the reloaded object" do subject.reload subject.get_attribute(:fake_attribute).should eql("some_value") end end describe "comparable" do subject do Class.new(described_class) do set_chef_id "name" attribute "name" attribute "other_extra" attribute "extra" end end let(:one) { subject.new(resource) } let(:two) { subject.new(resource) } context "given two objects with the same value for their 'chef_id'" do before(:each) do one.mass_assign(name: "reset", other_extra: "stuff") two.mass_assign(name: "reset", extra: "stuff") end it "is equal" do one.should be_eql(two) end end context "given two objects with different values for their 'chef_id'" do before(:each) do one.mass_assign(name: "jamie", other_extra: "stuff") two.mass_assign(name: "winsor", extra: "stuff") end it "is not equal" do one.should_not be_eql(two) end end end describe "uniqueness" do subject do Class.new(described_class) do set_chef_id "name" attribute "name" attribute "other_extra" attribute "extra" end end let(:one) { subject.new(resource) } let(:two) { subject.new(resource) } context "given an array of objects with the same value for their 'chef_id'" do let(:nodes) do one.mass_assign(name: "reset", other_extra: "stuff") two.mass_assign(name: "reset", extra: "stuff") [ one, two ] end it "returns only one unique element" do nodes.uniq.should have(1).item end end context "given an array of objects with different values for their 'chef_id'" do let(:nodes) do one.mass_assign(name: "jamie", other_extra: "stuff") two.mass_assign(name: "winsor", extra: "stuff") [ one, two ] end it "returns all of the elements" do nodes.uniq.should have(2).item end end end end