mongo 2.11.0 → 2.11.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/Rakefile +24 -0
  5. data/lib/mongo/address.rb +53 -37
  6. data/lib/mongo/auth.rb +30 -10
  7. data/lib/mongo/auth/cr.rb +1 -0
  8. data/lib/mongo/auth/cr/conversation.rb +13 -13
  9. data/lib/mongo/auth/ldap.rb +2 -1
  10. data/lib/mongo/auth/ldap/conversation.rb +9 -12
  11. data/lib/mongo/auth/scram.rb +1 -0
  12. data/lib/mongo/auth/scram/conversation.rb +36 -27
  13. data/lib/mongo/auth/user.rb +7 -1
  14. data/lib/mongo/auth/x509.rb +2 -1
  15. data/lib/mongo/auth/x509/conversation.rb +9 -9
  16. data/lib/mongo/bulk_write/transformable.rb +3 -3
  17. data/lib/mongo/client.rb +17 -6
  18. data/lib/mongo/cluster.rb +67 -49
  19. data/lib/mongo/cluster/sdam_flow.rb +87 -3
  20. data/lib/mongo/collection/view/readable.rb +3 -1
  21. data/lib/mongo/collection/view/writable.rb +3 -3
  22. data/lib/mongo/cursor/builder/kill_cursors_command.rb +8 -1
  23. data/lib/mongo/cursor/builder/op_kill_cursors.rb +8 -1
  24. data/lib/mongo/database.rb +1 -1
  25. data/lib/mongo/grid/file.rb +5 -0
  26. data/lib/mongo/grid/file/chunk.rb +2 -0
  27. data/lib/mongo/grid/fs_bucket.rb +15 -13
  28. data/lib/mongo/grid/stream/write.rb +9 -3
  29. data/lib/mongo/protocol/serializers.rb +12 -2
  30. data/lib/mongo/retryable.rb +33 -8
  31. data/lib/mongo/server.rb +13 -6
  32. data/lib/mongo/server/connection.rb +15 -8
  33. data/lib/mongo/server/connection_base.rb +7 -4
  34. data/lib/mongo/server/description.rb +34 -21
  35. data/lib/mongo/server/monitor.rb +1 -1
  36. data/lib/mongo/server/monitor/connection.rb +2 -3
  37. data/lib/mongo/session.rb +10 -10
  38. data/lib/mongo/socket.rb +10 -1
  39. data/lib/mongo/uri.rb +1 -1
  40. data/lib/mongo/version.rb +1 -1
  41. data/mongo.gemspec +1 -1
  42. data/spec/README.md +13 -0
  43. data/spec/integration/auth_spec.rb +27 -8
  44. data/spec/integration/bson_symbol_spec.rb +34 -0
  45. data/spec/integration/client_construction_spec.rb +14 -0
  46. data/spec/integration/client_options_spec.rb +5 -5
  47. data/spec/integration/connection_spec.rb +57 -9
  48. data/spec/integration/crud_spec.rb +45 -0
  49. data/spec/integration/cursor_reaping_spec.rb +2 -1
  50. data/spec/integration/grid_fs_bucket_spec.rb +48 -0
  51. data/spec/integration/retryable_errors_spec.rb +204 -39
  52. data/spec/integration/retryable_writes_spec.rb +36 -36
  53. data/spec/integration/size_limit_spec.rb~12e1e9c4f... RUBY-2242 Fix zlib compression (#2021) +98 -0
  54. data/spec/lite_spec_helper.rb +1 -0
  55. data/spec/mongo/address_spec.rb +19 -13
  56. data/spec/mongo/auth/ldap/conversation_spec.rb +1 -1
  57. data/spec/mongo/auth/scram/conversation_spec.rb +25 -14
  58. data/spec/mongo/auth/user/view_spec.rb +36 -1
  59. data/spec/mongo/auth/user_spec.rb +12 -0
  60. data/spec/mongo/auth/x509/conversation_spec.rb +1 -1
  61. data/spec/mongo/bulk_write_spec.rb +2 -2
  62. data/spec/mongo/client_construction_spec.rb +1 -21
  63. data/spec/mongo/cluster_spec.rb +57 -0
  64. data/spec/mongo/collection/view/map_reduce_spec.rb +1 -1
  65. data/spec/mongo/collection_spec.rb +26 -2
  66. data/spec/mongo/cursor/builder/op_kill_cursors_spec.rb +56 -0
  67. data/spec/mongo/server/connection_spec.rb +76 -8
  68. data/spec/mongo/server/monitor/connection_spec.rb +14 -7
  69. data/spec/mongo/socket/ssl_spec.rb +132 -98
  70. data/spec/mongo/socket/tcp_spec.rb +1 -9
  71. data/spec/mongo/uri_spec.rb +1 -1
  72. data/spec/runners/sdam/verifier.rb +91 -0
  73. data/spec/spec_tests/data/sdam/rs/primary_address_change.yml +29 -0
  74. data/spec/spec_tests/data/sdam/rs/primary_mismatched_me.yml +27 -23
  75. data/spec/spec_tests/data/sdam/rs/primary_to_no_primary_mismatched_me.yml +56 -79
  76. data/spec/spec_tests/data/sdam/sharded/primary_address_change.yml +21 -0
  77. data/spec/spec_tests/data/sdam/sharded/primary_mismatched_me.yml +22 -0
  78. data/spec/spec_tests/data/sdam/single/primary_address_change.yml +24 -0
  79. data/spec/spec_tests/data/sdam/single/primary_mismatched_me.yml +25 -0
  80. data/spec/spec_tests/data/sdam_monitoring/replica_set_with_me_mismatch.yml +159 -0
  81. data/spec/spec_tests/data/sdam_monitoring/{replica_set_other_seed.yml → replica_set_with_primary_change.yml} +97 -101
  82. data/spec/spec_tests/data/sdam_monitoring/replica_set_with_primary_removal.yml +22 -18
  83. data/spec/spec_tests/data/sdam_monitoring/standalone_to_rs_with_me_mismatch.yml +90 -0
  84. data/spec/spec_tests/sdam_monitoring_spec.rb +9 -4
  85. data/spec/support/cluster_config.rb +36 -0
  86. data/spec/support/cluster_tools.rb +5 -3
  87. data/spec/support/command_monitoring.rb +1 -1
  88. data/spec/support/constraints.rb +18 -18
  89. data/spec/support/lite_constraints.rb +8 -0
  90. data/spec/support/sdam_monitoring.rb +0 -115
  91. data/spec/support/server_discovery_and_monitoring.rb +2 -0
  92. data/spec/support/spec_config.rb +1 -1
  93. data/spec/support/utils.rb +11 -1
  94. metadata +687 -659
  95. metadata.gz.sig +3 -2
@@ -82,6 +82,20 @@ describe 'Client construction' do
82
82
  expect(client.cluster.topology).to be_a(Mongo::Cluster::Topology::Single)
83
83
  expect(client.options[:connect]).to eq :direct
84
84
  end
85
+
86
+ context 'direct connection with mismached me' do
87
+ let(:address) { ClusterConfig.instance.alternate_address.to_s }
88
+
89
+ let(:client) do
90
+ new_local_client([address], SpecConfig.instance.test_options)
91
+ end
92
+
93
+ let(:server) { client.cluster.next_primary }
94
+
95
+ it 'sets server type to primary' do
96
+ expect(server.description).to be_primary
97
+ end
98
+ end
85
99
  end
86
100
 
87
101
  context 'in sharded topology' do
@@ -38,7 +38,7 @@ describe 'Client options' do
38
38
  end
39
39
  end
40
40
 
41
- shared_examples_for 'auth mechanism that uses database or default auth source' do |default_auth_source:|
41
+ shared_examples_for 'auth mechanism that uses database or default auth source' do |default_auth_source|
42
42
  context 'where no database is provided' do
43
43
  context 'with URI options' do
44
44
  let(:credentials) { "#{user}:#{pwd}@" }
@@ -198,7 +198,7 @@ describe 'Client options' do
198
198
  let(:auth_mech_sym) { :mongodb_cr }
199
199
 
200
200
  it_behaves_like 'a supported auth mechanism'
201
- it_behaves_like 'auth mechanism that uses database or default auth source', default_auth_source: 'admin'
201
+ it_behaves_like 'auth mechanism that uses database or default auth source', 'admin'
202
202
  it_behaves_like 'an auth mechanism that doesn\'t support auth_mech_properties'
203
203
  end
204
204
 
@@ -207,7 +207,7 @@ describe 'Client options' do
207
207
  let(:auth_mech_sym) { :scram }
208
208
 
209
209
  it_behaves_like 'a supported auth mechanism'
210
- it_behaves_like 'auth mechanism that uses database or default auth source', default_auth_source: 'admin'
210
+ it_behaves_like 'auth mechanism that uses database or default auth source', 'admin'
211
211
  it_behaves_like 'an auth mechanism that doesn\'t support auth_mech_properties'
212
212
  end
213
213
 
@@ -216,7 +216,7 @@ describe 'Client options' do
216
216
  let(:auth_mech_sym) { :scram256 }
217
217
 
218
218
  it_behaves_like 'a supported auth mechanism'
219
- it_behaves_like 'auth mechanism that uses database or default auth source', default_auth_source: 'admin'
219
+ it_behaves_like 'auth mechanism that uses database or default auth source', 'admin'
220
220
  it_behaves_like 'an auth mechanism that doesn\'t support auth_mech_properties'
221
221
  end
222
222
 
@@ -263,7 +263,7 @@ describe 'Client options' do
263
263
  let(:auth_mech_sym) { :plain }
264
264
 
265
265
  it_behaves_like 'a supported auth mechanism'
266
- it_behaves_like 'auth mechanism that uses database or default auth source', default_auth_source: '$external'
266
+ it_behaves_like 'auth mechanism that uses database or default auth source', '$external'
267
267
  it_behaves_like 'an auth mechanism with ssl'
268
268
  it_behaves_like 'an auth mechanism that doesn\'t support auth_mech_properties'
269
269
  end
@@ -12,17 +12,18 @@ describe 'Connections' do
12
12
  let(:server) { client.cluster.servers.first }
13
13
 
14
14
  describe '#connect!' do
15
- # On JRuby 9.2.7.0, this line:
16
- # expect_any_instance_of(Mongo::Socket).to receive(:write).and_raise(exception)
17
- # ... appears to produce a moment in which Mongo::Socket#write is undefined
18
- # entirely, resulting in this failure:
19
- # RSpec::Expectations::ExpectationNotMetError: expected Mongo::Error::SocketError, got #<NameError: undefined method `write' for class `Mongo::Socket'>
20
- fails_on_jruby
15
+
16
+ let(:connection) do
17
+ Mongo::Server::Connection.new(server, server.options)
18
+ end
21
19
 
22
20
  context 'network error during handshake' do
23
- let(:connection) do
24
- Mongo::Server::Connection.new(server, server.options)
25
- end
21
+ # On JRuby 9.2.7.0, this line:
22
+ # expect_any_instance_of(Mongo::Socket).to receive(:write).and_raise(exception)
23
+ # ... appears to produce a moment in which Mongo::Socket#write is undefined
24
+ # entirely, resulting in this failure:
25
+ # RSpec::Expectations::ExpectationNotMetError: expected Mongo::Error::SocketError, got #<NameError: undefined method `write' for class `Mongo::Socket'>
26
+ fails_on_jruby
26
27
 
27
28
  let(:exception) { Mongo::Error::SocketError }
28
29
 
@@ -120,6 +121,53 @@ describe 'Connections' do
120
121
  expect(client.cluster.topology).to be_a(Mongo::Cluster::Topology::ReplicaSetNoPrimary)
121
122
  end
122
123
  end
124
+
125
+ describe 'number of sockets created' do
126
+
127
+ before do
128
+ server
129
+ end
130
+
131
+ shared_examples_for 'is 1 per connection' do
132
+ it 'is 1 per connection' do
133
+ # Instantiating a connection object should not create any sockets
134
+ RSpec::Mocks.with_temporary_scope do
135
+ expect(socket_cls).not_to receive(:new)
136
+
137
+ connection
138
+ end
139
+
140
+ # When the connection connects, exactly one socket should be created
141
+ # (and subsequently connected)
142
+ RSpec::Mocks.with_temporary_scope do
143
+ expect(socket_cls).to receive(:new).and_call_original
144
+
145
+ connection.connect!
146
+ end
147
+ end
148
+ end
149
+
150
+ let(:socket_cls) { ::Socket }
151
+
152
+ it_behaves_like 'is 1 per connection'
153
+
154
+ context 'connection to Unix domain socket' do
155
+ # Server does not allow Unix socket connections when TLS is enabled
156
+ require_no_tls
157
+
158
+ let(:port) { SpecConfig.instance.any_port }
159
+
160
+ let(:client) do
161
+ new_local_client(["/tmp/mongodb-#{port}.sock"], connect: :direct).tap do |client|
162
+ stop_monitoring(client)
163
+ end
164
+ end
165
+
166
+ let(:socket_cls) { ::UNIXSocket }
167
+
168
+ it_behaves_like 'is 1 per connection'
169
+ end
170
+ end
123
171
  end
124
172
 
125
173
  describe 'wire protocol version range update' do
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'CRUD operations' do
4
+ let(:collection) { authorized_client['crud_integration'] }
5
+
6
+ before do
7
+ collection.delete_many
8
+ end
9
+
10
+ describe 'upsert' do
11
+ context 'with default write concern' do
12
+ it 'upserts' do
13
+ collection.count_documents({}).should == 0
14
+
15
+ res = collection.find(_id: 'foo').update_one({'$set' => {foo: 'bar'}}, upsert: true)
16
+
17
+ res.documents.first['upserted'].length.should == 1
18
+
19
+ collection.count_documents({}).should == 1
20
+ end
21
+ end
22
+
23
+ context 'unacknowledged write' do
24
+ let(:unack_collection) do
25
+ collection.with(write_concern: {w: 0})
26
+ end
27
+
28
+ before do
29
+ unack_collection.write_concern.acknowledged?.should be false
30
+ end
31
+
32
+ it 'upserts' do
33
+ unack_collection.count_documents({}).should == 0
34
+
35
+ res = unack_collection.find(_id: 'foo').update_one({'$set' => {foo: 'bar'}}, upsert: true)
36
+
37
+ # since write concern is unacknowledged, wait for the data to be
38
+ # persisted (hopefully)
39
+ sleep 0.25
40
+
41
+ unack_collection.count_documents({}).should == 1
42
+ end
43
+ end
44
+ end
45
+ end
@@ -59,7 +59,8 @@ describe 'Cursor reaping' do
59
59
  client.cluster.instance_variable_get('@periodic_executor').execute
60
60
 
61
61
  started_event = EventSubscriber.started_events.detect do |event|
62
- event.command['killCursors'] && event.command['cursors'].map(&:value).include?(cursor_id)
62
+ event.command['killCursors'] &&
63
+ event.command['cursors'].map { |c| Utils.int64_value(c) }.include?(cursor_id)
63
64
  end
64
65
 
65
66
  expect(started_event).not_to be_nil
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'GridFS bucket integration' do
4
+ let(:fs) do
5
+ authorized_client.database.fs
6
+ end
7
+
8
+ describe 'UTF-8 string write' do
9
+ let(:data) { "hello\u2210" }
10
+
11
+ before do
12
+ data.length.should_not == data.bytesize
13
+ end
14
+
15
+ shared_examples 'round-trips' do
16
+ it 'round-trips' do
17
+ stream = fs.open_upload_stream('test') do |stream|
18
+ stream.write(data_to_write)
19
+ end
20
+
21
+ actual = nil
22
+ fs.open_download_stream(stream.file_id) do |stream|
23
+ actual = stream.read
24
+ end
25
+
26
+ actual.encoding.name.should == 'ASCII-8BIT'
27
+ actual.should == data.dup.force_encoding('binary')
28
+ end
29
+ end
30
+
31
+ context 'in binary encoding' do
32
+ let(:data_to_write) do
33
+ data.force_encoding('binary').freeze
34
+ end
35
+
36
+ it_behaves_like 'round-trips'
37
+ end
38
+
39
+ context 'in UTF-8 encoding' do
40
+ let(:data_to_write) do
41
+ data.encoding.name.should == 'UTF-8'
42
+ data.freeze
43
+ end
44
+
45
+ it_behaves_like 'round-trips'
46
+ end
47
+ end
48
+ end
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe 'Retryable writes tests' do
3
+ describe 'Failing retryable operations' do
4
4
  # Requirement for fail point
5
5
  min_server_fcv '4.0'
6
6
 
@@ -9,22 +9,12 @@ describe 'Retryable writes tests' do
9
9
  end
10
10
 
11
11
  let(:collection) do
12
- client['retryable-writes-error-spec']
12
+ client['retryable-errors-spec']
13
13
  end
14
14
 
15
- context 'when retry fails' do
15
+ context 'when operation fails' do
16
16
  require_topology :replica_set
17
17
 
18
- let(:fail_point_command) do
19
- {
20
- configureFailPoint: 'failCommand',
21
- mode: {times: 1},
22
- data: {
23
- failCommands: ['find'],
24
- errorCode: 11600,
25
- },
26
- }
27
- end
28
18
 
29
19
  let(:clear_fail_point_command) do
30
20
  {
@@ -34,17 +24,13 @@ describe 'Retryable writes tests' do
34
24
  end
35
25
 
36
26
  after do
37
- ClusterTools.instance.direct_client_for_each_server do |client|
27
+ ClusterTools.instance.direct_client_for_each_data_bearing_server do |client|
38
28
  client.use(:admin).database.command(clear_fail_point_command)
39
29
  end
40
30
  end
41
31
 
42
32
  let(:collection) do
43
- client['retryable-writes-error-spec', read: {mode: :secondary_preferred}]
44
- end
45
-
46
- let(:events) do
47
- events = EventSubscriber.command_started_events('find')
33
+ client['retryable-errors-spec', read: {mode: :secondary_preferred}]
48
34
  end
49
35
 
50
36
  let(:first_server) do
@@ -59,41 +45,220 @@ describe 'Retryable writes tests' do
59
45
  end
60
46
  end
61
47
 
62
- let(:perform_read) do
63
- client.cluster.servers_list.each do |server|
64
- server.monitor.stop!
48
+ shared_context 'read operation' do
49
+ let(:fail_point_command) do
50
+ {
51
+ configureFailPoint: 'failCommand',
52
+ mode: {times: 1},
53
+ data: {
54
+ failCommands: ['find'],
55
+ errorCode: 11600,
56
+ },
57
+ }
58
+ end
59
+
60
+ let(:set_fail_point) do
61
+ client.cluster.servers_list.each do |server|
62
+ server.monitor.stop!
63
+ end
64
+
65
+ ClusterTools.instance.direct_client_for_each_data_bearing_server do |client|
66
+ client.use(:admin).database.command(fail_point_command)
67
+ end
68
+ end
69
+
70
+ let(:operation_exception) do
71
+ set_fail_point
72
+
73
+ begin
74
+ collection.find(a: 1).to_a
75
+ rescue Mongo::Error::OperationFailure => exception
76
+ else
77
+ fail('Expected operation to fail')
78
+ end
79
+
80
+ puts exception.message
81
+
82
+ exception
83
+ end
84
+
85
+ let(:events) do
86
+ EventSubscriber.command_started_events('find')
87
+ end
88
+ end
89
+
90
+ shared_context 'write operation' do
91
+ let(:fail_point_command) do
92
+ {
93
+ configureFailPoint: 'failCommand',
94
+ mode: {times: 2},
95
+ data: {
96
+ failCommands: ['insert'],
97
+ errorCode: 11600,
98
+ },
99
+ }
65
100
  end
66
101
 
67
- ClusterTools.instance.direct_client_for_each_server do |client|
102
+ let(:set_fail_point) do
68
103
  client.use(:admin).database.command(fail_point_command)
69
104
  end
70
105
 
71
- begin
72
- collection.find(a: 1).to_a
73
- rescue Mongo::Error::OperationFailure => @exception
74
- else
75
- fail('Expected operation to fail')
106
+ let(:operation_exception) do
107
+ set_fail_point
108
+
109
+ begin
110
+ collection.insert_one(a: 1)
111
+ rescue Mongo::Error::OperationFailure => exception
112
+ else
113
+ fail('Expected operation to fail')
114
+ end
115
+
116
+ #puts exception.message
117
+
118
+ exception
119
+ end
120
+
121
+ let(:events) do
122
+ EventSubscriber.command_started_events('insert')
123
+ end
124
+ end
125
+
126
+ shared_examples_for 'failing retry' do
127
+
128
+ it 'indicates second attempt' do
129
+ expect(operation_exception.message).to include('attempt 2')
130
+ expect(operation_exception.message).not_to include('attempt 1')
131
+ expect(operation_exception.message).not_to include('attempt 3')
132
+ end
133
+
134
+ it 'publishes two events' do
135
+
136
+ expect(events.length).to eq(2)
137
+ end
138
+ end
139
+
140
+ shared_examples_for 'failing single attempt' do
141
+
142
+ it 'does not indicate attempt' do
143
+ expect(operation_exception.message).not_to include('attempt 1')
144
+ expect(operation_exception.message).not_to include('attempt 2')
145
+ expect(operation_exception.message).not_to include('attempt 3')
146
+ end
147
+
148
+ it 'publishes one event' do
149
+
150
+ expect(events.length).to eq(1)
151
+ end
152
+ end
153
+
154
+ shared_examples_for 'failing retry on the same server' do
155
+ it 'is reported on the server of the second attempt' do
156
+ expect(operation_exception.message).to include(second_server.address.seed)
157
+ end
158
+ end
159
+
160
+ shared_examples_for 'failing retry on a different server' do
161
+ it 'is reported on the server of the second attempt' do
162
+ expect(operation_exception.message).not_to include(first_server.address.seed)
163
+ expect(operation_exception.message).to include(second_server.address.seed)
76
164
  end
77
165
 
78
- puts @exception.message
166
+ it 'marks servers used in both attempts unknown' do
167
+ operation_exception
168
+
169
+ expect(first_server).to be_unknown
170
+
171
+ expect(second_server).to be_unknown
172
+ end
79
173
 
80
- expect(events.length).to eq(2)
81
- expect(events.first.address.seed).not_to eq(events.last.address.seed)
174
+ it 'publishes events for the different server addresses' do
175
+
176
+ expect(events.length).to eq(2)
177
+ expect(events.first.address.seed).not_to eq(events.last.address.seed)
178
+ end
82
179
  end
83
180
 
84
- it 'is reported on the server of the second attempt' do
85
- perform_read
181
+ shared_examples_for 'modern retry' do
182
+ it 'indicates modern retry' do
183
+ expect(operation_exception.message).to include('modern retry')
184
+ expect(operation_exception.message).not_to include('legacy retry')
185
+ expect(operation_exception.message).not_to include('retries disabled')
186
+ end
187
+ end
86
188
 
87
- expect(@exception.message).not_to include(first_server.address.seed)
88
- expect(@exception.message).to include(second_server.address.seed)
189
+ shared_examples_for 'legacy retry' do
190
+ it 'indicates legacy retry' do
191
+ expect(operation_exception.message).to include('legacy retry')
192
+ expect(operation_exception.message).not_to include('modern retry')
193
+ expect(operation_exception.message).not_to include('retries disabled')
194
+ end
89
195
  end
90
196
 
91
- it 'marks servers used in both attempts unknown' do
92
- perform_read
197
+ shared_examples_for 'disabled retry' do
198
+ it 'indicates retries are disabled' do
199
+ expect(operation_exception.message).to include('retries disabled')
200
+ expect(operation_exception.message).not_to include('legacy retry')
201
+ expect(operation_exception.message).not_to include('modern retry')
202
+ end
203
+ end
204
+
205
+ context 'when read is retried and retry fails' do
206
+ include_context 'read operation'
207
+
208
+ context 'modern read retries' do
209
+ require_wired_tiger_on_36
93
210
 
94
- expect(first_server).to be_unknown
211
+ let(:client) do
212
+ subscribed_client.with(retry_reads: true)
213
+ end
95
214
 
96
- expect(second_server).to be_unknown
215
+ it_behaves_like 'failing retry'
216
+ it_behaves_like 'modern retry'
217
+ end
218
+
219
+ context 'legacy read retries' do
220
+ let(:client) do
221
+ subscribed_client.with(retry_reads: false, read_retry_interval: 0)
222
+ end
223
+
224
+ it_behaves_like 'failing retry'
225
+ it_behaves_like 'legacy retry'
226
+ end
227
+ end
228
+
229
+ context 'when read retries are disabled' do
230
+ let(:client) do
231
+ subscribed_client.with(retry_reads: false, max_read_retries: 0)
232
+ end
233
+
234
+ include_context 'read operation'
235
+
236
+ it_behaves_like 'failing single attempt'
237
+ it_behaves_like 'disabled retry'
238
+ end
239
+
240
+ context 'when write is retried and retry fails' do
241
+ include_context 'write operation'
242
+
243
+ context 'modern write retries' do
244
+ require_wired_tiger_on_36
245
+
246
+ let(:client) do
247
+ subscribed_client.with(retry_writes: true)
248
+ end
249
+
250
+ it_behaves_like 'failing retry'
251
+ it_behaves_like 'modern retry'
252
+ end
253
+
254
+ context 'legacy write' do
255
+ let(:client) do
256
+ subscribed_client.with(retry_writes: false)
257
+ end
258
+
259
+ it_behaves_like 'failing retry'
260
+ it_behaves_like 'legacy retry'
261
+ end
97
262
  end
98
263
  end
99
264
  end