spec/ripple/persistence_spec.rb in ripple-0.9.5 vs spec/ripple/persistence_spec.rb in ripple-1.0.0.beta

- old
+ new

@@ -1,31 +1,28 @@ -# Copyright 2010 Sean Cribbs, Sonian Inc., and Basho Technologies, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -require File.expand_path("../../spec_helper", __FILE__) +require 'spec_helper' describe Ripple::Document::Persistence do - require 'support/models/widget' + # require 'support/models/widget' before :each do @backend = mock("Backend") @client = Ripple.client @client.stub!(:backend).and_return(@backend) @bucket = Ripple.client.bucket("widgets") @widget = Widget.new(:size => 1000) end + it "forces the content type to 'application/json'" do + @widget.robject.content_type = 'application/not-json' + + @backend.should_receive(:store_object) do |obj, *_| + obj.content_type.should == 'application/json' + end + + @widget.save + end + it "should save a new object to Riak" do json = @widget.attributes.merge("_type" => "Widget").to_json @backend.should_receive(:store_object) do |obj, _, _, _| obj.raw_data.should == json obj.key.should be_nil @@ -110,29 +107,33 @@ @widget.should_not be_a_new_record @widget.changes.should be_blank end it "should allow unexpected exceptions to be raised" do - robject = mock("robject", :key => @widget.key, "data=" => true) + robject = mock("robject", :key => @widget.key, "data=" => true, "content_type=" => true) robject.should_receive(:store).and_raise(Riak::HTTPFailedRequest.new(:post, 200, 404, {}, "404 not found")) @widget.stub!(:robject).and_return(robject) lambda { @widget.save }.should raise_error(Riak::FailedRequest) end - it "should reload a saved object" do + it "should reload a saved object, including associations" do json = @widget.attributes.merge(:_type => "Widget").to_json @backend.should_receive(:store_object) do |obj, _, _, _| obj.raw_data.should == json obj.key.should be_nil # Simulate loading the response with the key obj.key = "new_widget" end @widget.save @backend.should_receive(:reload_object) do |obj, _| obj.key.should == "new_widget" + obj.content_type = 'application/json' obj.raw_data = '{"name":"spring","size":10,"shipped_at":"Sat, 01 Jan 2000 20:15:01 -0000","_type":"Widget"}' + obj end + + @widget.widget_parts.should_receive(:reset) @widget.reload @widget.changes.should be_blank @widget.name.should == "spring" @widget.size.should == 10 @widget.shipped_at.should == Time.utc(2000,"jan",1,20,15,1) @@ -148,11 +149,11 @@ @widget.should be_frozen end it "should destroy all saved objects" do @widget.should_receive(:destroy).and_return(true) - Widget.should_receive(:all).and_yield(@widget) + Widget.should_receive(:list).and_yield(@widget) Widget.destroy_all.should be_true end it "should freeze an unsaved object when destroying" do @backend.should_not_receive(:delete_object) @@ -205,8 +206,123 @@ widget = Widget.new widget.key = "gear" widget.instance_variable_set(:@new, false) widget.send(:robject).should_receive(:delete).with({:rw => 1}) widget.destroy + end + end + + shared_examples_for "saving a parent document with linked child documents" do + before(:each) do + @backend.stub(:store_object) + end + + it 'saves new children when the parent is saved' do + children.each do |child| + child.stub(:new? => true) + child.should_receive(:save) + end + parent.save + end + + it 'saves children that have changes when the parent is saved' do + children.each do |child| + child.stub(:new? => false) + child.stub(:changed? => true) + child.should_receive(:save) + end + parent.save + end + + it 'does not save children that have no changes and are not new when the parent is saved' do + children.each do |child| + child.stub(:new? => false) + child.stub(:changed? => false) + child.should_not_receive(:save) + end + parent.save + end + end + + context "for a document with a many linked association" do + before(:all) do + # check assumptions of these examples + Widget.associations[:widget_parts].should be_many + Widget.associations[:widget_parts].should be_linked + end + + it_behaves_like "saving a parent document with linked child documents" do + let(:parent) { Widget.new(:name => 'fizzbuzz') } + let(:children) { %w[ fizz buzz ].map { |n| WidgetPart.new(:name => n) } } + + before(:each) do + children.each { |c| parent.widget_parts << c } + end + end + end + + describe "for a document with a one linked association" do + before(:all) do + # check assumptions of these examples + Invoice.associations[:customer].should be_one + Invoice.associations[:customer].should be_linked + end + + it_behaves_like "saving a parent document with linked child documents" do + let(:parent) { Invoice.new } + let(:children) { [Customer.new] } + + before(:each) do + parent.customer = children.first + end + end + end + + shared_examples_for "embedded association persistence logic" do + before(:each) do + @backend.stub(:store_object) + end + + it "does not save children when the parent is saved" do + children.each do |child| + child.stub(:new? => true, :changed? => true) + child.should_not_receive(:save) + end + + parent.save + end + end + + describe "for a document with a many embedded association" do + before(:all) do + # check assumptions of these examples + Clock.associations[:modes].should be_many + Clock.associations[:modes].should be_embedded + end + + it_behaves_like "embedded association persistence logic" do + let(:parent) { Clock.new } + let(:children) { [1, 2].map { |i| Mode.new } } + + before(:each) do + children.each { |c| parent.modes << c } + end + end + end + + describe "for a document with a one embedded association" do + before(:all) do + # check assumptions of these examples + Parent.associations[:child].should be_one + Parent.associations[:child].should be_embedded + end + + it_behaves_like "embedded association persistence logic" do + let(:parent) { Parent.new } + let(:children) { [Child.new(:name => 'Bobby', :age => 9)] } + + before(:each) do + parent.child = children.first + end end end end