mongo 2.10.5 → 2.11.0.rc0

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 (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