spec/mongo/retryable_spec.rb in mongo-2.12.4 vs spec/mongo/retryable_spec.rb in mongo-2.13.0.beta1

- old
+ new

@@ -216,15 +216,17 @@ context 'when the retry fails once and then succeeds' do let(:max_read_retries) { 2 } before do expect(retryable).to receive(:select_server).ordered - expect(operation).to receive(:execute).and_raise(error).ordered + expect(operation).to receive(:execute).and_raise(error.dup).ordered expect(client).to receive(:read_retry_interval).and_return(0.1).ordered expect(retryable).to receive(:select_server).ordered - expect(operation).to receive(:execute).and_raise(error).ordered + # Since exception is mutated when notes are added to it, + # we need to ensure each attempt starts with a pristine exception. + expect(operation).to receive(:execute).and_raise(error.dup).ordered expect(client).to receive(:read_retry_interval).and_return(0.1).ordered expect(retryable).to receive(:select_server).ordered expect(operation).to receive(:execute).and_return(true).ordered end @@ -348,79 +350,63 @@ it 'executes the operation twice' do expect(retryable.write).to be true end end - context 'when a not master error occurs' do - - before do - expect(operation).to receive(:execute).and_raise( - Mongo::Error::OperationFailure.new('not master')).ordered - expect(cluster).to receive(:scan!).and_return(true).ordered - expect(operation).to receive(:execute).and_return(true).ordered + context 'when an operation failure error occurs with a RetryableWriteError label' do + let(:error) do + Mongo::Error::OperationFailure.new(nil, nil, labels: ['RetryableWriteError']) end - it_behaves_like 'executes the operation twice' - end - - context 'when a node is recovering error occurs' do - before do - expect(operation).to receive(:execute).and_raise( - Mongo::Error::OperationFailure.new('node is recovering')).ordered + expect(operation).to receive(:execute).and_raise(error).ordered expect(cluster).to receive(:scan!).and_return(true).ordered expect(operation).to receive(:execute).and_return(true).ordered end it_behaves_like 'executes the operation twice' end - context 'when a retryable error occurs with a code' do - + context 'when an operation failure error occurs without a RetryableWriteError label' do before do - expect(operation).to receive(:execute).and_raise( - Mongo::Error::OperationFailure.new('message missing', nil, - :code => 91, :code_name => 'ShutdownInProgress')).ordered - expect(cluster).to receive(:scan!).and_return(true).ordered - expect(operation).to receive(:execute).and_return(true).ordered - end - - it_behaves_like 'executes the operation twice' - end - - context 'when a normal operation failure occurs' do - - before do expect(operation).to receive(:execute).and_raise(Mongo::Error::OperationFailure).ordered end it 'raises an exception' do expect { retryable.write }.to raise_error(Mongo::Error::OperationFailure) end end - context 'when a socket error occurs' do + context 'when a socket error occurs with a RetryableWriteError label' do + let(:error) do + error = Mongo::Error::SocketError.new('socket error') + error.add_label('RetryableWriteError') + error + end before do - expect(operation).to receive(:execute).and_raise( - Mongo::Error::SocketError.new('socket error')).ordered + expect(operation).to receive(:execute).and_raise(error).ordered end it 'raises an exception' do expect { retryable.write }.to raise_error(Mongo::Error::SocketError) end end - context 'when a socket timeout occurs' do + context 'when a socket timeout error occurs with a RetryableWriteError label' do + let(:error) do + error = Mongo::Error::SocketTimeoutError.new('socket timeout error') + error.add_label('RetryableWriteError') + error + end before do - expect(operation).to receive(:execute).and_raise( - Mongo::Error::SocketTimeoutError.new('socket timeout')).ordered + expect(operation).to receive(:execute).and_raise(error).ordered end it 'raises an exception' do expect { retryable.write @@ -439,11 +425,10 @@ expect { retryable.write }.to raise_error(Mongo::Error::UnsupportedCollation) end end - end describe '#write_with_retry - modern' do let(:retryable) do @@ -473,88 +458,104 @@ it 'executes the operation twice' do expect(retryable.write).to be true end end - context 'when a not master error occurs' do + context 'when an operation failure error occurs with a RetryableWriteError label' do + let(:error) do + Mongo::Error::OperationFailure.new(nil, nil, labels: ['RetryableWriteError']) + end before do server = cluster.next_primary - expect(operation).to receive(:execute).and_raise( - Mongo::Error::OperationFailure.new('not master')).ordered + expect(operation).to receive(:execute).and_raise(error).ordered expect(operation).to receive(:execute).and_return(true).ordered end it_behaves_like 'executes the operation twice' end - context 'when a node is recovering error occurs' do - + context 'when an operation failure error occurs without a RetryableWriteError label' do before do - server = cluster.next_primary - expect(operation).to receive(:execute).and_raise( - Mongo::Error::OperationFailure.new('node is recovering')).ordered - expect(operation).to receive(:execute).and_return(true).ordered + expect(operation).to receive(:execute).and_raise(Mongo::Error::OperationFailure).ordered end - it_behaves_like 'executes the operation twice' + it 'raises an exception' do + expect { + retryable.write + }.to raise_error(Mongo::Error::OperationFailure) + end end - context 'when a retryable error occurs with a code' do + context 'when a socket error occurs with a RetryableWriteError label' do + let(:error) do + error = Mongo::Error::SocketError.new('socket error') + error.add_label('RetryableWriteError') + error + end before do - server = cluster.next_primary - expect(operation).to receive(:execute).and_raise( - Mongo::Error::OperationFailure.new('message missing', nil, - :code => 91, :code_name => 'ShutdownInProgress')).ordered + expect(operation).to receive(:execute).and_raise(error).ordered + # This is where the server would be marked unknown, but since + # we are not tracking which server the operation was sent to, + # we are not able to assert this. + # There is no explicit cluster scan requested. expect(operation).to receive(:execute).and_return(true).ordered end it_behaves_like 'executes the operation twice' end - context 'when a normal operation failure occurs' do + context 'when a socket error occurs without a RetryableWriteError label' do + let(:error) do + Mongo::Error::SocketError.new('socket error') + end before do - expect(operation).to receive(:execute).and_raise(Mongo::Error::OperationFailure).ordered + expect(operation).to receive(:execute).and_raise(error).ordered end it 'raises an exception' do expect { retryable.write - }.to raise_error(Mongo::Error::OperationFailure) + }.to raise_error(Mongo::Error::SocketError) end end - context 'when a socket error occurs' do + context 'when a socket timeout occurs with a RetryableWriteError label' do + let(:error) do + error = Mongo::Error::SocketTimeoutError.new('socket timeout error') + error.add_label('RetryableWriteError') + error + end before do - expect(operation).to receive(:execute).and_raise( - Mongo::Error::SocketError.new('socket error')).ordered + expect(operation).to receive(:execute).and_raise(error).ordered # This is where the server would be marked unknown, but since # we are not tracking which server the operation was sent to, # we are not able to assert this. - # There is no explicit cluster scan requested. + # There is no explicit cluster scan requested (and the operation may + # end up being sent to the same server it was sent to originally). expect(operation).to receive(:execute).and_return(true).ordered end it_behaves_like 'executes the operation twice' end - context 'when a socket timeout occurs' do + context 'when a socket timeout occurs without a RetryableWriteError label' do + let(:error) do + Mongo::Error::SocketTimeoutError.new('socket timeout error') + end before do - expect(operation).to receive(:execute).and_raise( - Mongo::Error::SocketTimeoutError.new('socket timeout')).ordered - # This is where the server would be marked unknown, but since - # we are not tracking which server the operation was sent to, - # we are not able to assert this. - # There is no explicit cluster scan requested (and the operation may - # end up being sent to the same server it was sent to originally). - expect(operation).to receive(:execute).and_return(true).ordered + expect(operation).to receive(:execute).and_raise(error).ordered end - it_behaves_like 'executes the operation twice' + it 'raises an exception' do + expect { + retryable.write + }.to raise_error(Mongo::Error::SocketTimeoutError) + end end context 'when a non-retryable exception occurs' do before do