require 'rails_helper'

describe Dunlop::ExecutionBatchPid do

  context "#lock" do

    context 'no id provided' do
      subject { Dunlop::ExecutionBatchPid.new }

      it "gets the lock and releases it when done" do
        subject.locked?.should == false
        subject.lock do
          subject.locked?.should == true
        end
        subject.locked?.should == false
      end

      it "raises when lock is already set" do
        subject.locked?.should == false
        subject.lock do
          lambda{ subject.lock { 1 } }.should raise_error('lock already taken')
          subject.locked?.should == true
        end
        subject.locked?.should == false
      end
    end

    context 'with id provided' do
      let(:batch_pid_1) { Dunlop::ExecutionBatchPid.new(:one) }
      let(:batch_pid_2) { Dunlop::ExecutionBatchPid.new(:two) }

      it "gets the lock and releases it when done" do
        batch_pid_1.locked?.should == false
        batch_pid_1.lock do
          batch_pid_1.locked?.should == true
        end
        batch_pid_1.locked?.should == false
      end

      it "raises when lock is already set" do
        batch_pid_1.locked?.should == false
        batch_pid_1.lock do
          lambda{ batch_pid_1.lock { 1 } }.should raise_error('lock already taken')
          batch_pid_1.locked?.should == true
        end
        batch_pid_1.locked?.should == false
        lambda{ batch_pid_1.lock { 1 } }.should_not raise_error
      end

      it "allows other id to lock in parallel" do
        batch_pid_1.locked?.should == false
        batch_pid_2.locked?.should == false
        batch_pid_1.lock do
          batch_pid_1.locked?.should == true
          batch_pid_2.locked?.should == false
          batch_pid_2.lock do
            batch_pid_1.locked?.should == true
            batch_pid_2.locked?.should == true
          end
          batch_pid_1.locked?.should == true
          batch_pid_2.locked?.should == false
        end
        batch_pid_1.locked?.should == false
        batch_pid_2.locked?.should == false
      end

      it "raises other id if lock is already set in parallel" do
        batch_pid_1.locked?.should == false
        batch_pid_2.locked?.should == false
        batch_pid_1.lock do
          lambda{ batch_pid_1.lock { 1 } }.should raise_error('lock already taken')
          lambda{ batch_pid_2.lock { 1 } }.should_not raise_error
          batch_pid_1.locked?.should == true
          batch_pid_2.locked?.should == false
          batch_pid_2.lock do
            lambda{ batch_pid_1.lock { 1 } }.should raise_error('lock already taken')
            lambda{ batch_pid_2.lock { 1 } }.should raise_error('lock already taken')
            batch_pid_1.locked?.should == true
            batch_pid_2.locked?.should == true
          end
          lambda{ batch_pid_1.lock { 1 } }.should raise_error('lock already taken')
          lambda{ batch_pid_2.lock { 1 } }.should_not raise_error
          batch_pid_1.locked?.should == true
          batch_pid_2.locked?.should == false
        end
        batch_pid_1.locked?.should == false
        batch_pid_2.locked?.should == false
        lambda{ batch_pid_1.lock { 1 } }.should_not raise_error
        lambda{ batch_pid_2.lock { 1 } }.should_not raise_error
      end
    end

  end

end
