spec/integration/retryable_errors_spec.rb in mongo-2.11.0 vs spec/integration/retryable_errors_spec.rb in mongo-2.11.1

- old
+ new

@@ -1,32 +1,22 @@ require 'spec_helper' -describe 'Retryable writes tests' do +describe 'Failing retryable operations' do # Requirement for fail point min_server_fcv '4.0' let(:client) do subscribed_client end let(:collection) do - client['retryable-writes-error-spec'] + client['retryable-errors-spec'] end - context 'when retry fails' do + context 'when operation fails' do require_topology :replica_set - let(:fail_point_command) do - { - configureFailPoint: 'failCommand', - mode: {times: 1}, - data: { - failCommands: ['find'], - errorCode: 11600, - }, - } - end let(:clear_fail_point_command) do { configureFailPoint: 'failCommand', mode: 'off', @@ -38,17 +28,13 @@ client.use(:admin).database.command(clear_fail_point_command) end end let(:collection) do - client['retryable-writes-error-spec', read: {mode: :secondary_preferred}] + client['retryable-errors-spec', read: {mode: :secondary_preferred}] end - let(:events) do - events = EventSubscriber.command_started_events('find') - end - let(:first_server) do client.cluster.servers_list.detect do |server| server.address.seed == events.first.address.seed end end @@ -57,43 +43,222 @@ client.cluster.servers_list.detect do |server| server.address.seed == events.last.address.seed end end - let(:perform_read) do - client.cluster.servers_list.each do |server| - server.monitor.stop! + shared_context 'read operation' do + let(:fail_point_command) do + { + configureFailPoint: 'failCommand', + mode: {times: 1}, + data: { + failCommands: ['find'], + errorCode: 11600, + }, + } end - ClusterTools.instance.direct_client_for_each_server do |client| + let(:set_fail_point) do + client.cluster.servers_list.each do |server| + server.monitor.stop! + end + + ClusterTools.instance.direct_client_for_each_server do |client| + client.use(:admin).database.command(fail_point_command) + end + end + + let(:operation_exception) do + set_fail_point + + begin + collection.find(a: 1).to_a + rescue Mongo::Error::OperationFailure => exception + else + fail('Expected operation to fail') + end + + puts exception.message + + exception + end + + let(:events) do + EventSubscriber.command_started_events('find') + end + end + + shared_context 'write operation' do + let(:fail_point_command) do + { + configureFailPoint: 'failCommand', + mode: {times: 2}, + data: { + failCommands: ['insert'], + errorCode: 11600, + }, + } + end + + let(:set_fail_point) do client.use(:admin).database.command(fail_point_command) end - begin - collection.find(a: 1).to_a - rescue Mongo::Error::OperationFailure => @exception - else - fail('Expected operation to fail') + let(:operation_exception) do + set_fail_point + + begin + collection.insert_one(a: 1) + rescue Mongo::Error::OperationFailure => exception + else + fail('Expected operation to fail') + end + + #puts exception.message + + exception end - puts @exception.message + let(:events) do + EventSubscriber.command_started_events('insert') + end + end - expect(events.length).to eq(2) - expect(events.first.address.seed).not_to eq(events.last.address.seed) + shared_examples_for 'failing retry' do + + it 'indicates second attempt' do + expect(operation_exception.message).to include('attempt 2') + expect(operation_exception.message).not_to include('attempt 1') + expect(operation_exception.message).not_to include('attempt 3') + end + + it 'publishes two events' do + + expect(events.length).to eq(2) + end end - it 'is reported on the server of the second attempt' do - perform_read + shared_examples_for 'failing single attempt' do - expect(@exception.message).not_to include(first_server.address.seed) - expect(@exception.message).to include(second_server.address.seed) + it 'does not indicate attempt' do + expect(operation_exception.message).not_to include('attempt 1') + expect(operation_exception.message).not_to include('attempt 2') + expect(operation_exception.message).not_to include('attempt 3') + end + + it 'publishes one event' do + + expect(events.length).to eq(1) + end end - it 'marks servers used in both attempts unknown' do - perform_read + shared_examples_for 'failing retry on the same server' do + it 'is reported on the server of the second attempt' do + expect(operation_exception.message).to include(second_server.address.seed) + end + end - expect(first_server).to be_unknown + shared_examples_for 'failing retry on a different server' do + it 'is reported on the server of the second attempt' do + expect(operation_exception.message).not_to include(first_server.address.seed) + expect(operation_exception.message).to include(second_server.address.seed) + end - expect(second_server).to be_unknown + it 'marks servers used in both attempts unknown' do + operation_exception + + expect(first_server).to be_unknown + + expect(second_server).to be_unknown + end + + it 'publishes events for the different server addresses' do + + expect(events.length).to eq(2) + expect(events.first.address.seed).not_to eq(events.last.address.seed) + end + end + + shared_examples_for 'modern retry' do + it 'indicates modern retry' do + expect(operation_exception.message).to include('modern retry') + expect(operation_exception.message).not_to include('legacy retry') + expect(operation_exception.message).not_to include('retries disabled') + end + end + + shared_examples_for 'legacy retry' do + it 'indicates legacy retry' do + expect(operation_exception.message).to include('legacy retry') + expect(operation_exception.message).not_to include('modern retry') + expect(operation_exception.message).not_to include('retries disabled') + end + end + + shared_examples_for 'disabled retry' do + it 'indicates retries are disabled' do + expect(operation_exception.message).to include('retries disabled') + expect(operation_exception.message).not_to include('legacy retry') + expect(operation_exception.message).not_to include('modern retry') + end + end + + context 'when read is retried and retry fails' do + include_context 'read operation' + + context 'modern read retries' do + require_wired_tiger_on_36 + + let(:client) do + subscribed_client.with(retry_reads: true) + end + + it_behaves_like 'failing retry' + it_behaves_like 'modern retry' + end + + context 'legacy read retries' do + let(:client) do + subscribed_client.with(retry_reads: false, read_retry_interval: 0) + end + + it_behaves_like 'failing retry' + it_behaves_like 'legacy retry' + end + end + + context 'when read retries are disabled' do + let(:client) do + subscribed_client.with(retry_reads: false, max_read_retries: 0) + end + + include_context 'read operation' + + it_behaves_like 'failing single attempt' + it_behaves_like 'disabled retry' + end + + context 'when write is retried and retry fails' do + include_context 'write operation' + + context 'modern write retries' do + require_wired_tiger_on_36 + + let(:client) do + subscribed_client.with(retry_writes: true) + end + + it_behaves_like 'failing retry' + it_behaves_like 'modern retry' + end + + context 'legacy write' do + let(:client) do + subscribed_client.with(retry_writes: false) + end + + it_behaves_like 'failing retry' + it_behaves_like 'legacy retry' + end end end end