require File.expand_path("../../spec_helper", __FILE__) module Hotseat describe Queue do ######################## ### Helper methods ### ######################## def reset_test_queue! reset_test_db! @q = Hotseat.make_queue DB end def sample_doc(var=nil) {:field => var || 'value' } end # Returns the new doc id's def create_some_docs(n=3) (1..n).map {|i| DB.save_doc(sample_doc(i))['id'] } end # Returns unsaved new docs def create_new_docs(n=3) docs=[] (1..n).each {|i| docs< true doc = DB.get(@doc_id) doc.should_not have_key(@q.config[:object_name]) end it "should save any changes made in the block" do @q.remove(@doc_id) do |doc| doc['field'] = 'changed value' doc['another_field'] = 'another value' end doc = DB.get(@doc_id) doc['field'].should == 'changed value' doc['another_field'].should == 'another value' end end describe "#remove_bulk" do before(:each) do reset_test_queue! enqueue( create_some_docs(10) ) @leased = @q.lease 8 @doc_ids = @leased.take(5).map{|doc| doc['_id'] } end it "should unlock leased documents" do @q.remove_bulk @doc_ids docs = DB.get_bulk(@doc_ids)['rows'].map{|row| row['doc']} docs.each do |doc| doc.should have_key(@q.config[:object_name]) doc[@q.config[:object_name]].should_not have_key('lock') end end it "should remove multiple documents from the queue" do @q.remove_bulk @doc_ids pending_docs = @q.get 3 # ensure we get all remaining pending docs pending_ids = pending_docs.map{|doc| doc['_id'] } (pending_ids - @doc_ids).should eql(pending_ids) end it "should report docs whose lock was already removed" do rem_ids = @doc_ids.take(2) @q.remove_bulk rem_ids res = @q.remove_bulk @doc_ids res['errors'].should have(2).errors res['errors'].map{|err| err['id']}.should == rem_ids end it "should report docs that are missing from the database" do rem_ids = @doc_ids.take(2) docs = rem_ids.map{|id| @q.db.get(id) } docs.each {|doc| @q.db.delete_doc(doc) } res = @q.remove_bulk @doc_ids res['errors'].should have(2).errors res['errors'].map{|err| err['id']}.should == rem_ids end it "should leave queue history in the document (mark as done) by default" do @q.remove_bulk @doc_ids docs = DB.get_bulk(@doc_ids)['rows'].map{|row| row['doc']} docs.each do |doc| doc.should have_key(@q.config[:object_name]) doc[@q.config[:object_name]].should have_key('done') end end it "should delete queue history from the document when forget=true" do @q.remove_bulk @doc_ids, :forget => true docs = DB.get_bulk(@doc_ids)['rows'].map{|row| row['doc']} docs.each do |doc| doc.should_not have_key(@q.config[:object_name]) end end end describe "#undo" do before(:all) do reset_test_queue! doc_ids = create_some_docs(3) enqueue doc_ids @done_ids = [doc_ids[1]] @undone_ids = [doc_ids[0], doc_ids[2]] @done_ids.each do |done_id| done_doc = DB.get done_id @q.mark_done done_doc done_doc.save end end it "should mark the done document as pending again" do @q.undo @done_ids.first done_doc = DB.get @done_ids.first patch = done_doc[@q.config[:object_name]] patch.should_not have_key('done') patch.should_not have_key('lock') end it "should raise an error if the document is not done" do undone_doc = DB.get @undone_ids.first expect { @q.undo @undone_ids.first }.to raise_error(Hotseat::QueueError) end end describe "#undo_bulk" do before(:each) do reset_test_queue! doc_ids = create_some_docs(5) enqueue doc_ids @done_docs = doc_ids[0..2].map{|id| DB.get id } @done_docs.each do |doc| @q.mark_done doc doc.save end end it "should mark all 'done' documents as pending again" do @q.undo_bulk @done_docs.map{|doc| doc['_id']} @q.num_done.should == 0 @q.num_pending.should == 5 end it "should leave not-done documents intact" do @q.lease @q.undo_bulk @done_docs.map{|doc| doc['_id']} @q.num_locked.should == 1 @q.num_pending.should == 4 end end describe "#num_done" do it "should return the number of documents done" do reset_test_queue! enqueue( create_some_docs(10) ) @leased = @q.lease 8 @doc_ids = @leased.take(5).map{|doc| doc['_id'] } @q.remove_bulk @doc_ids @q.num_done.should == 5 end end describe "#num_all" do it "should return the total number of documents in the queue" do reset_test_queue! enqueue( create_some_docs(10) ) @leased = @q.lease 8 @doc_ids = @leased.take(5).map{|doc| doc['_id'] } @q.remove_bulk @doc_ids @q.num_all.should == 10 end end describe "#forget" do it "should delete queue history from a document" do reset_test_queue! enqueue( create_some_docs(1) ) doc_id = @q.get.first['_id'] @q.forget doc_id doc = DB.get(doc_id) doc.should_not have_key(@q.config[:object_name]) end end describe "#forget_bulk" do it "should delete queue history from multiple document" do reset_test_queue! enqueue( create_some_docs(3) ) doc_ids = @q.get(3).map{|doc| doc['_id'] } @q.forget_bulk doc_ids @q.db.bulk_load(doc_ids)['rows'].map{|row| row['doc']}.each do |doc| doc.should_not have_key(@q.config[:object_name]) end end end describe "#purge" do before do reset_test_queue! enqueue( create_some_docs(10) ) leased = @q.lease 5 @q.remove_bulk leased.take(2) end it "should remove (and forget) all documents from the queue" do @q.purge @q.num_all.should == 0 end end context "when two queues are defined on the same DB" do before do reset_test_db! @doc_ids = create_some_docs(10) @q1 = Hotseat.make_queue(DB, :design_doc_name => 'hotseat1_queue', :object_name => 'hotseat1') @q2 = Hotseat.make_queue(DB, :design_doc_name => 'hotseat2_queue', :object_name => 'hotseat2') end it "#add should add a doc to the specified queue only" do @q1.add @doc_ids[0] @q2.add @doc_ids[1] DB.get(@doc_ids[0]).should have_key(@q1.config[:object_name]) DB.get(@doc_ids[0]).should_not have_key(@q2.config[:object_name]) DB.get(@doc_ids[1]).should have_key(@q2.config[:object_name]) DB.get(@doc_ids[1]).should_not have_key(@q1.config[:object_name]) end it "#lease should lease docs from the specified queue" do @q1.add_bulk @doc_ids[0, 5] @q2.add_bulk @doc_ids[5, 5] doc1 = @q1.lease.first @doc_ids[0, 5].should include(doc1['_id']) @q2.lease(3).each do |doc| @doc_ids[5, 5].should include(doc['_id']) end end end end end