mongo 2.10.5 → 2.11.0.rc0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (191) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/CONTRIBUTING.md +1 -1
  5. data/lib/mongo.rb +2 -0
  6. data/lib/mongo/address.rb +4 -0
  7. data/lib/mongo/address/validator.rb +99 -0
  8. data/lib/mongo/auth.rb +7 -2
  9. data/lib/mongo/auth/user.rb +1 -7
  10. data/lib/mongo/background_thread.rb +135 -0
  11. data/lib/mongo/bulk_write/transformable.rb +3 -3
  12. data/lib/mongo/client.rb +74 -16
  13. data/lib/mongo/cluster.rb +193 -41
  14. data/lib/mongo/cluster/periodic_executor.rb +31 -43
  15. data/lib/mongo/cluster/sdam_flow.rb +26 -3
  16. data/lib/mongo/cluster/srv_monitor.rb +127 -0
  17. data/lib/mongo/collection/view/readable.rb +3 -5
  18. data/lib/mongo/collection/view/writable.rb +3 -3
  19. data/lib/mongo/cursor/builder/get_more_command.rb +1 -4
  20. data/lib/mongo/cursor/builder/kill_cursors_command.rb +5 -23
  21. data/lib/mongo/cursor/builder/op_get_more.rb +2 -2
  22. data/lib/mongo/cursor/builder/op_kill_cursors.rb +5 -24
  23. data/lib/mongo/error.rb +1 -0
  24. data/lib/mongo/error/auth_error.rb +1 -1
  25. data/lib/mongo/error/connection_check_out_timeout.rb +7 -8
  26. data/lib/mongo/error/invalid_address.rb +24 -0
  27. data/lib/mongo/error/notable.rb +2 -2
  28. data/lib/mongo/error/operation_failure.rb +3 -3
  29. data/lib/mongo/error/pool_closed_error.rb +11 -4
  30. data/lib/mongo/event.rb +1 -1
  31. data/lib/mongo/grid/file.rb +0 -5
  32. data/lib/mongo/grid/file/chunk.rb +0 -2
  33. data/lib/mongo/grid/fs_bucket.rb +13 -15
  34. data/lib/mongo/grid/stream/write.rb +3 -9
  35. data/lib/mongo/loggable.rb +5 -1
  36. data/lib/mongo/monitoring.rb +1 -0
  37. data/lib/mongo/monitoring/event/cmap/connection_check_out_failed.rb +7 -0
  38. data/lib/mongo/monitoring/event/cmap/connection_checked_in.rb +11 -3
  39. data/lib/mongo/monitoring/event/cmap/connection_checked_out.rb +11 -3
  40. data/lib/mongo/monitoring/event/cmap/pool_closed.rb +11 -3
  41. data/lib/mongo/monitoring/event/cmap/pool_created.rb +12 -3
  42. data/lib/mongo/monitoring/unified_sdam_log_subscriber.rb +62 -0
  43. data/lib/mongo/operation/shared/executable.rb +5 -10
  44. data/lib/mongo/operation/shared/sessions_supported.rb +1 -5
  45. data/lib/mongo/protocol/get_more.rb +1 -2
  46. data/lib/mongo/protocol/kill_cursors.rb +13 -6
  47. data/lib/mongo/protocol/serializers.rb +4 -20
  48. data/lib/mongo/retryable.rb +9 -34
  49. data/lib/mongo/semaphore.rb +1 -1
  50. data/lib/mongo/server.rb +113 -42
  51. data/lib/mongo/server/connection.rb +12 -5
  52. data/lib/mongo/server/connection_pool.rb +250 -40
  53. data/lib/mongo/server/connection_pool/populator.rb +58 -0
  54. data/lib/mongo/server/description.rb +9 -2
  55. data/lib/mongo/server/monitor.rb +68 -93
  56. data/lib/mongo/server/monitor/connection.rb +2 -0
  57. data/lib/mongo/server_selector/selectable.rb +13 -5
  58. data/lib/mongo/session.rb +0 -13
  59. data/lib/mongo/srv.rb +17 -0
  60. data/lib/mongo/srv/monitor.rb +96 -0
  61. data/lib/mongo/srv/resolver.rb +130 -0
  62. data/lib/mongo/srv/result.rb +126 -0
  63. data/lib/mongo/srv/warning_result.rb +35 -0
  64. data/lib/mongo/uri.rb +45 -55
  65. data/lib/mongo/uri/srv_protocol.rb +89 -42
  66. data/lib/mongo/version.rb +1 -1
  67. data/mongo.gemspec +3 -4
  68. data/spec/README.md +6 -1
  69. data/spec/enterprise_auth/kerberos_spec.rb +7 -6
  70. data/spec/integration/change_stream_examples_spec.rb +0 -4
  71. data/spec/integration/client_construction_spec.rb +14 -2
  72. data/spec/integration/connect_single_rs_name_spec.rb +2 -2
  73. data/spec/integration/connection_pool_populator_spec.rb +296 -0
  74. data/spec/integration/connection_spec.rb +31 -22
  75. data/spec/integration/cursor_reaping_spec.rb +1 -2
  76. data/spec/integration/docs_examples_spec.rb +0 -4
  77. data/spec/integration/heartbeat_events_spec.rb +17 -15
  78. data/spec/integration/reconnect_spec.rb +144 -1
  79. data/spec/integration/retryable_writes_errors_spec.rb +0 -4
  80. data/spec/integration/retryable_writes_spec.rb +36 -36
  81. data/spec/integration/sdam_error_handling_spec.rb +31 -25
  82. data/spec/integration/sdam_events_spec.rb +2 -6
  83. data/spec/integration/server_monitor_spec.rb +28 -0
  84. data/spec/integration/server_selector_spec.rb +7 -5
  85. data/spec/integration/srv_monitoring_spec.rb +360 -0
  86. data/spec/integration/step_down_spec.rb +4 -6
  87. data/spec/lite_spec_helper.rb +22 -0
  88. data/spec/mongo/address/validator_spec.rb +51 -0
  89. data/spec/mongo/auth/cr_spec.rb +1 -29
  90. data/spec/mongo/auth/ldap_spec.rb +1 -29
  91. data/spec/mongo/auth/scram/conversation_spec.rb +0 -2
  92. data/spec/mongo/auth/scram/negotiation_spec.rb +1 -1
  93. data/spec/mongo/auth/scram_spec.rb +1 -29
  94. data/spec/mongo/auth/user/view_spec.rb +1 -36
  95. data/spec/mongo/auth/user_spec.rb +0 -12
  96. data/spec/mongo/auth/x509_spec.rb +1 -29
  97. data/spec/mongo/bulk_write_spec.rb +2 -2
  98. data/spec/mongo/client_construction_spec.rb +56 -15
  99. data/spec/mongo/client_spec.rb +31 -27
  100. data/spec/mongo/cluster/periodic_executor_spec.rb +16 -0
  101. data/spec/mongo/cluster/srv_monitor_spec.rb +214 -0
  102. data/spec/mongo/cluster/topology/replica_set_spec.rb +16 -11
  103. data/spec/mongo/cluster/topology/sharded_spec.rb +12 -9
  104. data/spec/mongo/cluster/topology/single_spec.rb +20 -11
  105. data/spec/mongo/cluster_spec.rb +45 -29
  106. data/spec/mongo/collection/view/map_reduce_spec.rb +14 -9
  107. data/spec/mongo/collection/view/readable_spec.rb +0 -16
  108. data/spec/mongo/collection_spec.rb +0 -44
  109. data/spec/mongo/cursor/builder/get_more_command_spec.rb +2 -4
  110. data/spec/mongo/cursor/builder/op_get_more_spec.rb +2 -4
  111. data/spec/mongo/cursor_spec.rb +27 -7
  112. data/spec/mongo/monitoring/event/cmap/connection_checked_in_spec.rb +10 -3
  113. data/spec/mongo/monitoring/event/cmap/connection_checked_out_spec.rb +10 -3
  114. data/spec/mongo/monitoring/event/cmap/pool_closed_spec.rb +10 -3
  115. data/spec/mongo/monitoring/event/cmap/pool_created_spec.rb +10 -3
  116. data/spec/mongo/operation/delete/op_msg_spec.rb +17 -8
  117. data/spec/mongo/operation/insert/op_msg_spec.rb +50 -35
  118. data/spec/mongo/operation/update/op_msg_spec.rb +14 -7
  119. data/spec/mongo/retryable_spec.rb +52 -31
  120. data/spec/mongo/server/app_metadata_spec.rb +0 -8
  121. data/spec/mongo/server/connection_auth_spec.rb +5 -2
  122. data/spec/mongo/server/connection_pool/populator_spec.rb +101 -0
  123. data/spec/mongo/server/connection_pool_spec.rb +256 -107
  124. data/spec/mongo/server/connection_spec.rb +22 -33
  125. data/spec/mongo/server/description_spec.rb +42 -4
  126. data/spec/mongo/server/monitor/connection_spec.rb +22 -11
  127. data/spec/mongo/server/monitor_spec.rb +66 -107
  128. data/spec/mongo/server_spec.rb +82 -60
  129. data/spec/mongo/session/session_pool_spec.rb +1 -5
  130. data/spec/mongo/session_spec.rb +0 -4
  131. data/spec/mongo/socket/ssl_spec.rb +2 -2
  132. data/spec/mongo/srv/monitor_spec.rb +211 -0
  133. data/spec/mongo/srv/result_spec.rb +54 -0
  134. data/spec/mongo/uri/srv_protocol_spec.rb +30 -15
  135. data/spec/mongo/uri_spec.rb +125 -4
  136. data/spec/spec_helper.rb +6 -0
  137. data/spec/spec_tests/auth_spec.rb +39 -0
  138. data/spec/spec_tests/cmap_spec.rb +55 -8
  139. data/spec/spec_tests/connection_string_spec.rb +6 -31
  140. data/spec/spec_tests/data/auth/connection-string.yml +297 -0
  141. data/spec/spec_tests/data/cmap/pool-checkout-error-closed.yml +4 -1
  142. data/spec/spec_tests/data/cmap/pool-create-with-options.yml +1 -0
  143. data/spec/spec_tests/data/command_monitoring/insertMany.yml +1 -1
  144. data/spec/spec_tests/data/connection_string/invalid-uris.yml +20 -0
  145. data/spec/spec_tests/data/connection_string/valid-auth.yml +16 -0
  146. data/spec/spec_tests/data/connection_string/valid-warnings.yml +26 -30
  147. data/spec/spec_tests/data/transactions/abort.yml +3 -3
  148. data/spec/spec_tests/data/transactions/error-labels.yml +3 -3
  149. data/spec/spec_tests/data/transactions_api/callback-retry.yml +3 -3
  150. data/spec/spec_tests/data/uri_options/auth-options.yml +1 -1
  151. data/spec/spec_tests/max_staleness_spec.rb +7 -2
  152. data/spec/spec_tests/retryable_reads_spec.rb +0 -31
  153. data/spec/spec_tests/sdam_monitoring_spec.rb +12 -12
  154. data/spec/spec_tests/sdam_spec.rb +4 -7
  155. data/spec/spec_tests/server_selection_spec.rb +6 -2
  156. data/spec/spec_tests/transactions_spec.rb +0 -2
  157. data/spec/spec_tests/uri_options_spec.rb +4 -2
  158. data/spec/stress/connection_pool_stress_spec.rb +203 -0
  159. data/spec/stress/connection_pool_timing_spec.rb +181 -0
  160. data/spec/support/auth.rb +113 -0
  161. data/spec/support/background_thread_registry.rb +63 -0
  162. data/spec/support/client_registry.rb +11 -2
  163. data/spec/support/cluster_config.rb +65 -46
  164. data/spec/support/cluster_tools.rb +2 -2
  165. data/spec/support/cmap.rb +13 -14
  166. data/spec/support/cmap/verifier.rb +4 -5
  167. data/spec/support/command_monitoring.rb +0 -5
  168. data/spec/support/common_shortcuts.rb +101 -1
  169. data/spec/support/constraints.rb +25 -0
  170. data/spec/support/dns.rb +13 -0
  171. data/spec/support/event_subscriber.rb +0 -7
  172. data/spec/support/json_ext_formatter.rb +5 -1
  173. data/spec/support/lite_constraints.rb +22 -6
  174. data/spec/support/local_resource_registry.rb +34 -0
  175. data/spec/support/sdam_monitoring.rb +115 -0
  176. data/spec/support/spec_config.rb +20 -6
  177. data/spec/support/spec_setup.rb +2 -2
  178. data/spec/support/transactions.rb +1 -1
  179. data/spec/support/transactions/test.rb +1 -1
  180. data/spec/support/utils.rb +1 -16
  181. metadata +685 -659
  182. metadata.gz.sig +0 -0
  183. data/lib/mongo/event/description_changed.rb +0 -52
  184. data/spec/integration/bson_symbol_spec.rb +0 -34
  185. data/spec/integration/crud_spec.rb +0 -45
  186. data/spec/integration/get_more_spec.rb +0 -32
  187. data/spec/integration/grid_fs_bucket_spec.rb +0 -48
  188. data/spec/integration/retryable_errors_spec.rb +0 -265
  189. data/spec/integration/size_limit_spec.rb~12e1e9c4f... RUBY-2242 Fix zlib compression (#2021) +0 -98
  190. data/spec/mongo/cursor/builder/op_kill_cursors_spec.rb +0 -56
  191. data/spec/runners/sdam/verifier.rb +0 -88
@@ -1,14 +1,22 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe 'Connections' do
4
- before(:all) do
5
- ClientRegistry.instance.close_all_clients
4
+ clean_slate
5
+
6
+ let(:client) do
7
+ ClientRegistry.instance.global_client('authorized').tap do |client|
8
+ stop_monitoring(client)
9
+ end
6
10
  end
7
11
 
8
- let(:client) { ClientRegistry.instance.global_client('authorized') }
9
12
  let(:server) { client.cluster.servers.first }
10
13
 
11
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'>
12
20
  fails_on_jruby
13
21
 
14
22
  context 'network error during handshake' do
@@ -74,17 +82,17 @@ describe 'Connections' do
74
82
 
75
83
  # need to use the primary here, otherwise a secondary will be
76
84
  # changed to unknown which wouldn't alter topology
77
- let(:server) { client.cluster.servers.detect { |s| s.primary? } }
85
+ let(:server) { client.cluster.next_primary }
78
86
 
79
87
  it 'changes topology type' do
80
88
  # wait for topology to get discovered
81
- client.database.command(ismaster: 1)
89
+ client.cluster.next_primary
82
90
 
83
91
  expect(client.cluster.topology.class).to eql(Mongo::Cluster::Topology::ReplicaSetWithPrimary)
84
92
 
85
93
  # stop background monitoring to prevent it from racing with the test
86
- client.cluster.servers.each do |server|
87
- server.monitor.stop!(true)
94
+ client.cluster.servers_list.each do |server|
95
+ server.monitor.stop!
88
96
  end
89
97
 
90
98
  connection
@@ -98,12 +106,11 @@ describe 'Connections' do
98
106
  context 'error during handshake to primary in a replica set' do
99
107
  require_topology :replica_set
100
108
 
101
- let(:server) { client.cluster.servers.detect { |server| server.primary? } }
109
+ let(:server) { client.cluster.next_primary }
102
110
 
103
111
  before do
104
- ClientRegistry.instance.close_all_clients
105
112
  # insert to perform server selection and get topology to primary
106
- client[:test].insert_one(foo: 'bar')
113
+ client.cluster.next_primary
107
114
  end
108
115
 
109
116
  it 'sets cluster type to replica set without primary' do
@@ -148,17 +155,19 @@ describe 'Connections' do
148
155
  server.monitor.instance_variable_set('@description',
149
156
  Mongo::Server::Description.new(server.address))
150
157
 
151
- # now pretend an ismaster returned a different range
152
- features = Mongo::Server::Description::Features.new(0..3)
153
- # the second Features instantiation is for SDAM event publication
154
- expect(Mongo::Server::Description::Features).to receive(:new).twice.and_return(features)
158
+ RSpec::Mocks.with_temporary_scope do
159
+ # now pretend an ismaster returned a different range
160
+ features = Mongo::Server::Description::Features.new(0..3)
161
+ # the second Features instantiation is for SDAM event publication
162
+ expect(Mongo::Server::Description::Features).to receive(:new).twice.and_return(features)
155
163
 
156
- connection = Mongo::Server::Connection.new(server, server.options)
157
- expect(connection.connect!).to be true
164
+ connection = Mongo::Server::Connection.new(server, server.options)
165
+ expect(connection.connect!).to be true
158
166
 
159
- # ismaster response should update server description via sdam flow,
160
- # which includes wire version range
161
- expect(server.features.server_wire_versions.max).to eq(3)
167
+ # ismaster response should update server description via sdam flow,
168
+ # which includes wire version range
169
+ expect(server.features.server_wire_versions.max).to eq(3)
170
+ end
162
171
  end
163
172
  end
164
173
 
@@ -173,8 +182,8 @@ describe 'Connections' do
173
182
 
174
183
  it 'performs SDAM flow' do
175
184
  client['foo'].insert_one(bar: 1)
176
- client.cluster.servers.each do |server|
177
- server.monitor.stop!(true)
185
+ client.cluster.servers_list.each do |server|
186
+ server.monitor.stop!
178
187
  end
179
188
  expect(client.cluster.topology.class).to eq(Mongo::Cluster::Topology::ReplicaSetWithPrimary)
180
189
 
@@ -184,7 +193,7 @@ describe 'Connections' do
184
193
  end
185
194
 
186
195
  # overwrite server description
187
- server.monitor.instance_variable_set('@description', Mongo::Server::Description.new(
196
+ server.instance_variable_set('@description', Mongo::Server::Description.new(
188
197
  server.address))
189
198
 
190
199
  # overwrite topology
@@ -59,8 +59,7 @@ 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'] &&
63
- event.command['cursors'].map { |c| Utils.int64_value(c) }.include?(cursor_id)
62
+ event.command['killCursors'] && event.command['cursors'].include?(cursor_id)
64
63
  end
65
64
 
66
65
  expect(started_event).not_to be_nil
@@ -1,10 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe 'aggregation examples in Ruby' do
4
- before(:all) do
5
- ClientRegistry.instance.close_all_clients
6
- end
7
-
8
4
  let(:client) do
9
5
  authorized_client
10
6
  end
@@ -25,11 +25,9 @@ end
25
25
  describe 'Heartbeat events' do
26
26
  class HeartbeatEventsSpecTestException < StandardError; end
27
27
 
28
- let(:subscriber) { TestHeartbeatSubscriber.new }
28
+ clean_slate_for_all
29
29
 
30
- before(:all) do
31
- ClientRegistry.instance.close_all_clients
32
- end
30
+ let(:subscriber) { TestHeartbeatSubscriber.new }
33
31
 
34
32
  before do
35
33
  Mongo::Monitoring::Global.subscribe(Mongo::Monitoring::SERVER_HEARTBEAT, subscriber)
@@ -39,8 +37,11 @@ describe 'Heartbeat events' do
39
37
  Mongo::Monitoring::Global.unsubscribe(Mongo::Monitoring::SERVER_HEARTBEAT, subscriber)
40
38
  end
41
39
 
42
- let(:client) { new_local_client([SpecConfig.instance.addresses.first],
43
- authorized_client.options.merge(server_selection_timeout: 0.1, connect: :direct)) }
40
+ let(:address_str) { ClusterConfig.instance.primary_address_str }
41
+
42
+ let(:client) { new_local_client([address_str],
43
+ SpecConfig.instance.all_test_options.merge(
44
+ server_selection_timeout: 0.1, connect: :direct)) }
44
45
 
45
46
  it 'notifies on successful heartbeats' do
46
47
  client.database.command(ismaster: 1)
@@ -48,12 +49,12 @@ describe 'Heartbeat events' do
48
49
  started_event = subscriber.started_events.first
49
50
  expect(started_event).not_to be nil
50
51
  expect(started_event.address).to be_a(Mongo::Address)
51
- expect(started_event.address.seed).to eq(SpecConfig.instance.addresses.first)
52
+ expect(started_event.address.seed).to eq(address_str)
52
53
 
53
54
  succeeded_event = subscriber.succeeded_events.first
54
55
  expect(succeeded_event).not_to be nil
55
56
  expect(succeeded_event.address).to be_a(Mongo::Address)
56
- expect(succeeded_event.address.seed).to eq(SpecConfig.instance.addresses.first)
57
+ expect(succeeded_event.address.seed).to eq(address_str)
57
58
 
58
59
  failed_event = subscriber.failed_events.first
59
60
  expect(failed_event).to be nil
@@ -70,7 +71,7 @@ describe 'Heartbeat events' do
70
71
  started_event = subscriber.started_events.first
71
72
  expect(started_event).not_to be nil
72
73
  expect(started_event.address).to be_a(Mongo::Address)
73
- expect(started_event.address.seed).to eq(SpecConfig.instance.addresses.first)
74
+ expect(started_event.address.seed).to eq(address_str)
74
75
 
75
76
  succeeded_event = subscriber.succeeded_events.first
76
77
  expect(succeeded_event).to be nil
@@ -80,13 +81,13 @@ describe 'Heartbeat events' do
80
81
  expect(failed_event.error).to be exc
81
82
  expect(failed_event.failure).to be exc
82
83
  expect(failed_event.address).to be_a(Mongo::Address)
83
- expect(failed_event.address.seed).to eq(SpecConfig.instance.addresses.first)
84
+ expect(failed_event.address.seed).to eq(address_str)
84
85
  end
85
86
 
86
87
  context 'when monitoring option is false' do
87
- let(:client) { new_local_client([SpecConfig.instance.addresses.first],
88
- authorized_client.options.merge(server_selection_timeout: 0.1, connect: :direct,
89
- monitoring: false)) }
88
+ let(:client) { new_local_client([address_str],
89
+ SpecConfig.instance.all_test_options.merge(
90
+ server_selection_timeout: 0.1, connect: :direct, monitoring: false)) }
90
91
 
91
92
  shared_examples_for 'does not notify on heartbeats' do
92
93
  it 'does not notify on heartbeats' do
@@ -105,8 +106,9 @@ describe 'Heartbeat events' do
105
106
  client.subscribe(Mongo::Monitoring::SERVER_HEARTBEAT, subscriber)
106
107
  end
107
108
 
108
- new_local_client([SpecConfig.instance.addresses.first],
109
- authorized_client.options.merge(server_selection_timeout: 0.1, connect: :direct,
109
+ new_local_client([address_str],
110
+ SpecConfig.instance.all_test_options.merge(
111
+ server_selection_timeout: 0.1, connect: :direct,
110
112
  monitoring: false, sdam_proc: sdam_proc))
111
113
  end
112
114
 
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  describe 'Client after reconnect' do
4
4
  let(:client) { authorized_client }
5
5
 
6
- it 'works' do
6
+ it 'is a functioning client' do
7
7
  client['test'].insert_one('testk' => 'testv')
8
8
 
9
9
  client.reconnect
@@ -28,4 +28,147 @@ describe 'Client after reconnect' do
28
28
  expect(new_thread).not_to eq(thread)
29
29
  expect(new_thread).to be_alive
30
30
  end
31
+
32
+ context 'with min_pool_size > 0' do
33
+ let(:client) { authorized_client.with(min_pool_size: 1) }
34
+
35
+ it 'recreates connection pool populator thread' do
36
+ server = client.cluster.next_primary
37
+ thread = server.pool.populator.instance_variable_get('@thread')
38
+ expect(thread).to be_alive
39
+
40
+ thread.kill
41
+ # context switch to let the thread get killed
42
+ sleep 0.1
43
+ expect(thread).not_to be_alive
44
+
45
+ client.reconnect
46
+
47
+ new_server = client.cluster.next_primary
48
+ new_thread = new_server.pool.populator.instance_variable_get('@thread')
49
+ expect(new_thread).not_to eq(thread)
50
+ expect(new_thread).to be_alive
51
+ end
52
+ end
53
+
54
+ context 'SRV monitor thread' do
55
+
56
+ let(:uri) do
57
+ "mongodb+srv://test1.test.build.10gen.cc/?tls=#{SpecConfig.instance.ssl?}&tlsInsecure=true".tap do |uri|
58
+ puts "Constructed URI: #{uri}"
59
+ end
60
+ end
61
+
62
+ # Debug logging to troubleshoot failures in Evergreen
63
+ let(:logger) do
64
+ Logger.new(STDERR). tap do |logger|
65
+ logger.level = :debug
66
+ end
67
+ end
68
+
69
+ let(:client) do
70
+ ClientRegistry.instance.register_local_client(
71
+ Mongo::Client.new(uri, server_selection_timeout: 3.86,
72
+ logger: logger))
73
+ end
74
+
75
+ let(:wait_for_discovery) do
76
+ client.cluster.next_primary
77
+ end
78
+
79
+ let(:wait_for_discovery_again) do
80
+ client.cluster.next_primary
81
+ end
82
+
83
+ shared_examples_for 'recreates SRV monitor' do
84
+ # JRuby produces this error:
85
+ # RSpec::Expectations::ExpectationNotMetError: expected nil to respond to `alive?`
86
+ # for this assertion:
87
+ # expect(thread).not_to be_alive
88
+ # This is bizarre because if thread was nil, the earlier call to
89
+ # thread.kill should've similarly failed, but it doesn't.
90
+ fails_on_jruby
91
+
92
+ it 'recreates SRV monitor' do
93
+ wait_for_discovery
94
+
95
+ expect(client.cluster.topology).to be_a(expected_topology_cls)
96
+ thread = client.cluster.srv_monitor.instance_variable_get('@thread')
97
+ expect(thread).to be_alive
98
+
99
+ thread.kill
100
+ # context switch to let the thread get killed
101
+ sleep 0.1
102
+ expect(thread).not_to be_alive
103
+
104
+ client.reconnect
105
+
106
+ wait_for_discovery_again
107
+
108
+ new_thread = client.cluster.srv_monitor.instance_variable_get('@thread')
109
+ expect(new_thread).not_to eq(thread)
110
+ expect(new_thread).to be_alive
111
+ end
112
+ end
113
+
114
+ context 'in sharded topology' do
115
+ require_topology :sharded
116
+ require_default_port_deployment
117
+ require_multi_shard
118
+
119
+ let(:expected_topology_cls) { Mongo::Cluster::Topology::Sharded }
120
+
121
+ it_behaves_like 'recreates SRV monitor'
122
+ end
123
+
124
+ context 'in unknown topology' do
125
+
126
+ # JRuby apparently does not implement non-blocking UDP I/O which is used
127
+ # by RubyDNS:
128
+ # NotImplementedError: recvmsg_nonblock is not implemented
129
+ fails_on_jruby
130
+
131
+ let(:uri) do
132
+ "mongodb+srv://test-fake.test.build.10gen.cc/"
133
+ end
134
+
135
+ let(:client) do
136
+ ClientRegistry.instance.register_local_client(
137
+ Mongo::Client.new(uri, server_selection_timeout: 3.89,
138
+ resolv_options: {
139
+ nameserver: 'localhost',
140
+ nameserver_port: [['localhost', 5300], ['127.0.0.1', 5300]],
141
+ },
142
+ logger: logger))
143
+ end
144
+
145
+ let(:expected_topology_cls) { Mongo::Cluster::Topology::Unknown }
146
+
147
+ let(:wait_for_discovery) do
148
+ # Since the entire test is done in unknown topology, we cannot use
149
+ # next_primary to wait for the client to discover the topology.
150
+ sleep 5
151
+ end
152
+
153
+ let(:wait_for_discovery_again) do
154
+ sleep 5
155
+ end
156
+
157
+ around do |example|
158
+ require 'support/dns'
159
+
160
+ rules = [
161
+ ['_mongodb._tcp.test-fake.test.build.10gen.cc', :srv,
162
+ [0, 0, 2799, 'localhost.test.build.10gen.cc'],
163
+ ],
164
+ ]
165
+
166
+ mock_dns(rules) do
167
+ example.run
168
+ end
169
+ end
170
+
171
+ it_behaves_like 'recreates SRV monitor'
172
+ end
173
+ end
31
174
  end
@@ -18,10 +18,6 @@ describe 'Retryable writes errors tests' do
18
18
  authorized_client.with(retry_writes: true)
19
19
  end
20
20
 
21
- after do
22
- client.close(true)
23
- end
24
-
25
21
  context 'when a retryable write is attempted' do
26
22
  it 'raises an actionable error message' do
27
23
  expect {
@@ -102,22 +102,22 @@ describe 'Retryable writes integration tests' do
102
102
  end
103
103
 
104
104
  it 'does not retry writes' do
105
- expect do
105
+ expect {
106
106
  operation
107
- end.to raise_error(Mongo::Error::OperationFailure, /other error/)
107
+ }.to raise_error(Mongo::Error::OperationFailure, /other error/)
108
108
  expect(expectation).to eq(unsuccessful_retry_value)
109
109
  end
110
110
 
111
111
  it 'indicates server used for operation' do
112
- expect do
112
+ expect {
113
113
  operation
114
- end.to raise_error(Mongo::Error::OperationFailure, /on #{ClusterConfig.instance.primary_address_str}/)
114
+ }.to raise_error(Mongo::Error::OperationFailure, /on #{ClusterConfig.instance.primary_address_str}/)
115
115
  end
116
116
 
117
117
  it 'indicates first attempt' do
118
- expect do
118
+ expect {
119
119
  operation
120
- end.to raise_error(Mongo::Error::OperationFailure, /attempt 1/)
120
+ }.to raise_error(Mongo::Error::OperationFailure, /attempt 1/)
121
121
  end
122
122
  end
123
123
  end
@@ -144,9 +144,9 @@ describe 'Retryable writes integration tests' do
144
144
  end
145
145
 
146
146
  it 'does not retry writes and raises the original error' do
147
- expect do
147
+ expect {
148
148
  operation
149
- end.to raise_error(error)
149
+ }.to raise_error(error)
150
150
  expect(expectation).to eq(unsuccessful_retry_value)
151
151
  end
152
152
  end
@@ -158,9 +158,9 @@ describe 'Retryable writes integration tests' do
158
158
  end
159
159
 
160
160
  it 'does not retry writes and raises the original error' do
161
- expect do
161
+ expect {
162
162
  operation
163
- end.to raise_error(error)
163
+ }.to raise_error(error)
164
164
  expect(expectation).to eq(unsuccessful_retry_value)
165
165
  end
166
166
  end
@@ -172,9 +172,9 @@ describe 'Retryable writes integration tests' do
172
172
  end
173
173
 
174
174
  it 'does not retry writes and raises the original error' do
175
- expect do
175
+ expect {
176
176
  operation
177
- end.to raise_error(error)
177
+ }.to raise_error(error)
178
178
  expect(expectation).to eq(unsuccessful_retry_value)
179
179
  end
180
180
  end
@@ -211,22 +211,22 @@ describe 'Retryable writes integration tests' do
211
211
  end
212
212
 
213
213
  it 'raises the second error' do
214
- expect do
214
+ expect {
215
215
  operation
216
- end.to raise_error(second_error)
216
+ }.to raise_error(second_error)
217
217
  expect(expectation).to eq(unsuccessful_retry_value)
218
218
  end
219
219
 
220
220
  it 'indicates server used for operation' do
221
- expect do
221
+ expect {
222
222
  operation
223
- end.to raise_error(Mongo::Error, /on #{ClusterConfig.instance.primary_address_str}/)
223
+ }.to raise_error(Mongo::Error, /on #{ClusterConfig.instance.primary_address_str}/)
224
224
  end
225
225
 
226
226
  it 'indicates second attempt' do
227
- expect do
227
+ expect {
228
228
  operation
229
- end.to raise_error(Mongo::Error, /attempt 2/)
229
+ }.to raise_error(Mongo::Error, /attempt 2/)
230
230
  end
231
231
  end
232
232
 
@@ -237,9 +237,9 @@ describe 'Retryable writes integration tests' do
237
237
  end
238
238
 
239
239
  it 'raises the second error' do
240
- expect do
240
+ expect {
241
241
  operation
242
- end.to raise_error(second_error)
242
+ }.to raise_error(second_error)
243
243
  expect(expectation).to eq(unsuccessful_retry_value)
244
244
  end
245
245
  end
@@ -251,9 +251,9 @@ describe 'Retryable writes integration tests' do
251
251
  end
252
252
 
253
253
  it 'raises the second error' do
254
- expect do
254
+ expect {
255
255
  operation
256
- end.to raise_error(second_error)
256
+ }.to raise_error(second_error)
257
257
  expect(expectation).to eq(unsuccessful_retry_value)
258
258
  end
259
259
  end
@@ -265,9 +265,9 @@ describe 'Retryable writes integration tests' do
265
265
  end
266
266
 
267
267
  it 'does not retry writes and raises the first error' do
268
- expect do
268
+ expect {
269
269
  operation
270
- end.to raise_error(error)
270
+ }.to raise_error(error)
271
271
  expect(expectation).to eq(unsuccessful_retry_value)
272
272
  end
273
273
  end
@@ -279,28 +279,28 @@ describe 'Retryable writes integration tests' do
279
279
  end
280
280
 
281
281
  it 'raises the first error' do
282
- expect do
282
+ expect {
283
283
  operation
284
- end.to raise_error(error)
284
+ }.to raise_error(error)
285
285
  expect(expectation).to eq(unsuccessful_retry_value)
286
286
  end
287
287
 
288
288
  it 'indicates server used for operation' do
289
- expect do
289
+ expect {
290
290
  operation
291
- end.to raise_error(Mongo::Error, /on #{ClusterConfig.instance.primary_address_str}/)
291
+ }.to raise_error(Mongo::Error, /on #{ClusterConfig.instance.primary_address_str}/)
292
292
  end
293
293
 
294
294
  it 'indicates first attempt' do
295
- expect do
295
+ expect {
296
296
  operation
297
- end.to raise_error(Mongo::Error, /attempt 1/)
297
+ }.to raise_error(Mongo::Error, /attempt 1/)
298
298
  end
299
299
 
300
300
  it 'indicates retry was performed' do
301
- expect do
301
+ expect {
302
302
  operation
303
- end.to raise_error(Mongo::Error, /later retry failed: StandardError/)
303
+ }.to raise_error(Mongo::Error, /later retry failed: StandardError/)
304
304
  end
305
305
  end
306
306
  end
@@ -319,9 +319,9 @@ describe 'Retryable writes integration tests' do
319
319
  end
320
320
 
321
321
  it 'does not retry writes' do
322
- expect do
322
+ expect {
323
323
  operation
324
- end.to raise_error(Mongo::Error::SocketError)
324
+ }.to raise_error(Mongo::Error::SocketError)
325
325
  expect(expectation).to eq(unsuccessful_retry_value)
326
326
  end
327
327
  end
@@ -341,9 +341,9 @@ describe 'Retryable writes integration tests' do
341
341
  end
342
342
 
343
343
  it 'does not retry writes' do
344
- expect do
344
+ expect {
345
345
  operation
346
- end.to raise_error(Mongo::Error::SocketError)
346
+ }.to raise_error(Mongo::Error::SocketError)
347
347
  expect(expectation).to eq(unsuccessful_retry_value)
348
348
  end
349
349
  end