mongo 2.11.0 → 2.11.5

Sign up to get free protection for your applications and to get access to all the features.
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