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