spec/dynamoid/persistence_spec.rb in dynamoid-0.6.1 vs spec/dynamoid/persistence_spec.rb in dynamoid-0.7.0

- old
+ new

@@ -31,11 +31,29 @@ it 'assigns itself an id on save' do @address.save Dynamoid::Adapter.read("dynamoid_tests_addresses", @address.id)[:id].should == @address.id end - + + it 'prevents concurrent writes to tables with a lock_version' do + @address.save! + a1 = @address + a2 = Address.find(@address.id) + + a1.city = 'Seattle' + a2.city = 'San Francisco' + + a1.save! + expect { a2.save! }.to raise_exception(Dynamoid::Errors::ConditionalCheckFailedException) + end + + configured_with 'partitioning' do + it 'raises an error when attempting to use optimistic locking' do + expect { address.save! }.to raise_exception + end + end + it 'assigns itself an id on save only if it does not have one' do @address.id = 'test123' @address.save Dynamoid::Adapter.read("dynamoid_tests_addresses", 'test123').should_not be_empty @@ -87,18 +105,18 @@ it 'dumps and undump a serialized field' do @address.options = (hash = {:x => [1, 2], "foobar" => 3.14}) Address.undump(@address.send(:dump))[:options].should == hash end - + [true, false].each do |bool| it "dumps a #{bool} boolean field" do @address.deliverable = bool Address.undump(@address.send(:dump))[:deliverable].should == bool end end - + it 'raises on an invalid boolean value' do expect do @address.deliverable = true data = @address.send(:dump) data[:deliverable] = 'foo' @@ -140,24 +158,24 @@ it 'works with a HashWithIndifferentAccess' do hash = ActiveSupport::HashWithIndifferentAccess.new("city" => "Atlanta") lambda {Address.create(hash)}.should_not raise_error end - + context 'create' do { Tweet => ['with range', { :tweet_id => 1, :group => 'abc' }], Message => ['without range', { :message_id => 1, :text => 'foo', :time => DateTime.now }] }.each_pair do |clazz, fields| it "checks for existence of an existing object #{fields[0]}" do t1 = clazz.new(fields[1]) t2 = clazz.new(fields[1]) - + t1.save expect do t2.save! - end.to raise_exception AWS::DynamoDB::Errors::ConditionalCheckFailedException + end.to raise_exception Dynamoid::Errors::ConditionalCheckFailedException end end end context 'unknown fields' do @@ -175,26 +193,42 @@ it 'raises when undumping a column with an unknown field type' do expect do clazz.new(:deliverable => true) #undump is called here end.to raise_error(ArgumentError) end - + it 'raises when dumping a column with an unknown field type' do doc = clazz.new doc.deliverable = true expect do doc.dump end.to raise_error(ArgumentError) end end - + context 'update' do before :each do @tweet = Tweet.create(:tweet_id => 1, :group => 'abc', :count => 5, :tags => ['db', 'sql'], :user_name => 'john') end + it 'runs before_update callbacks when doing #update' do + CamelCase.any_instance.expects(:doing_before_update).once.returns(true) + + CamelCase.create(:color => 'blue').update do |t| + t.set(:color => 'red') + end + end + + it 'runs after_update callbacks when doing #update' do + CamelCase.any_instance.expects(:doing_after_update).once.returns(true) + + CamelCase.create(:color => 'blue').update do |t| + t.set(:color => 'red') + end + end + it 'support add/delete operation on a field' do @tweet.update do |t| t.add(:count => 3) t.delete(:tags => ['db']) end @@ -220,17 +254,48 @@ @tweet.update!(:if => { :count => 5 }) do |t| t.add(:count => 3) end }.to raise_error(Dynamoid::Errors::ConditionalCheckFailedException) end + + it 'prevents concurrent saves to tables with a lock_version' do + @address.save! + a2 = Address.find(@address.id) + a2.update! { |a| a.set(:city => "Chicago") } + + expect do + @address.city = "Seattle" + @address.save! + end.to raise_error(Dynamoid::Errors::ConditionalCheckFailedException) + end end context 'delete' do it 'deletes model with datetime range key' do lambda { msg = Message.create!(:message_id => 1, :time => DateTime.now, :text => "Hell yeah") msg.destroy }.should_not raise_error + end + end + + context 'single table inheritance' do + let(:car) { Car.create(power_locks: false) } + let(:sub) { NuclearSubmarine.create(torpedoes: 5) } + + it 'saves subclass objects in the parent table' do + c = car + Vehicle.find(c.id).should == c + end + + it 'loads subclass item when querying the parent table' do + c = car + s = sub + + Vehicle.all.to_a.tap { |v| + v.should include(c) + v.should include(s) + } end end end