free_mutant/spec/unit/mutant/actor/receiver_spec.rb
Markus Schirp d8e6805206 Fix actor race condition
* Use the `ConditionVariable` primitive to fix rece between stopped
  receiver Thread and its wake signal.
* Race was only observable via synthetical benchmarks and explicit
  sleeps between unlocking receiver mutex and Thread.stop
* Simplifies code a lot as thread must not be passed around anymore
2014-12-06 04:37:20 +00:00

56 lines
2 KiB
Ruby

RSpec.describe Mutant::Actor::Receiver do
let(:messages) { double('Messages') }
let(:mutex) { double('Mutex') }
let(:condition_variable) { double('Condition Variable') }
let(:message) { double('Message') }
let(:object) { described_class.new(condition_variable, mutex, messages) }
describe '#call' do
subject { object.call }
context 'when messages contains a message' do
before do
expect(mutex).to receive(:synchronize).and_yield.ordered
expect(messages).to receive(:empty?).and_return(false).ordered
expect(messages).to receive(:shift).and_return(message).ordered
end
it { should be(message) }
end
context 'when messages initially contains no message' do
before do
# 1rst failing try
expect(mutex).to receive(:synchronize).and_yield.ordered
expect(messages).to receive(:empty?).and_return(true).ordered
expect(condition_variable).to receive(:wait).with(mutex).ordered
# 2nd successful try
expect(mutex).to receive(:synchronize).and_yield.ordered
expect(messages).to receive(:empty?).and_return(false).ordered
expect(messages).to receive(:shift).and_return(message).ordered
end
it 'waits for message' do
should be(message)
end
end
context 'when messages contains no message but thread gets waken without message arrived' do
before do
# 1rst failing try
expect(mutex).to receive(:synchronize).and_yield.ordered
expect(messages).to receive(:empty?).and_return(true).ordered
expect(condition_variable).to receive(:wait).with(mutex).ordered
# 2nd failing try
expect(mutex).to receive(:synchronize).and_yield.ordered
expect(messages).to receive(:empty?).and_return(true).ordered
expect(condition_variable).to receive(:wait).with(mutex).ordered
end
it 'fails with error' do
expect { subject }.to raise_error(Mutant::Actor::ProtocolError)
end
end
end
end