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,9 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe 'SDAM error handling' do
4
- before(:all) do
5
- ClientRegistry.instance.close_all_clients
6
- end
4
+ clean_slate_for_all
7
5
 
8
6
  # These tests operate on specific servers, and don't work in a multi
9
7
  # shard cluster where multiple servers are equally eligible
@@ -16,63 +14,72 @@ describe 'SDAM error handling' do
16
14
  shared_examples_for 'marks server unknown' do
17
15
  it 'marks server unknown' do
18
16
  expect(server).not_to be_unknown
19
- operation
20
- expect(server).to be_unknown
17
+ RSpec::Mocks.with_temporary_scope do
18
+ operation
19
+ expect(server).to be_unknown
20
+ end
21
21
  end
22
22
  end
23
23
 
24
24
  shared_examples_for 'does not mark server unknown' do
25
25
  it 'does not mark server unknown' do
26
26
  expect(server).not_to be_unknown
27
- operation
28
- expect(server).not_to be_unknown
27
+ RSpec::Mocks.with_temporary_scope do
28
+ operation
29
+ expect(server).not_to be_unknown
30
+ end
29
31
  end
30
32
  end
31
33
 
32
34
  shared_examples_for 'requests server scan' do
33
35
  it 'requests server scan' do
34
- expect(server.monitor.scan_semaphore).to receive(:signal)
35
- operation
36
+ RSpec::Mocks.with_temporary_scope do
37
+ expect(server.scan_semaphore).to receive(:signal)
38
+ operation
39
+ end
36
40
  end
37
41
  end
38
42
 
39
43
  shared_examples_for 'does not request server scan' do
40
44
  it 'does not request server scan' do
41
- expect(server.monitor.scan_semaphore).not_to receive(:signal)
42
- operation
45
+ RSpec::Mocks.with_temporary_scope do
46
+ expect(server.scan_semaphore).not_to receive(:signal)
47
+ operation
48
+ end
43
49
  end
44
50
  end
45
51
 
46
52
  shared_examples_for 'clears connection pool' do
47
53
  it 'clears connection pool' do
48
54
  generation = server.pool.generation
49
- operation
50
- new_generation = server.pool.generation
51
- # Temporary hack to allow repeated pool clears
52
- expect(new_generation).to be >= generation + 1
55
+ RSpec::Mocks.with_temporary_scope do
56
+ operation
57
+ new_generation = server.pool.generation
58
+ expect(new_generation).to eq(generation + 1)
59
+ end
53
60
  end
54
61
  end
55
62
 
56
63
  shared_examples_for 'does not clear connection pool' do
57
64
  it 'does not clear connection pool' do
58
65
  generation = server.pool.generation
59
- operation
60
- new_generation = server.pool.generation
61
- expect(new_generation).to eq(generation)
66
+ RSpec::Mocks.with_temporary_scope do
67
+ operation
68
+ new_generation = server.pool.generation
69
+ expect(new_generation).to eq(generation)
70
+ end
62
71
  end
63
72
  end
64
73
 
65
74
  describe 'when there is an error during an operation' do
66
75
 
67
76
  before do
68
- wait_for_all_servers(client.cluster)
77
+ client.cluster.next_primary
78
+ stop_monitoring(client)
69
79
  # we also need a connection to the primary so that our error
70
80
  # expectations do not get triggered during handshakes which
71
81
  # have different behavior from non-handshake errors
72
82
  client.database.command(ping: 1)
73
- client.cluster.servers_list.each do |server|
74
- server.monitor.stop!
75
- end
76
83
  end
77
84
 
78
85
  let(:operation) do
@@ -89,8 +96,7 @@ describe 'SDAM error handling' do
89
96
  context 'server 4.2 or higher' do
90
97
  min_server_fcv '4.2'
91
98
 
92
- # Due to RUBY-1894 backport, the pool is cleared here
93
- it_behaves_like 'clears connection pool'
99
+ it_behaves_like 'does not clear connection pool'
94
100
  end
95
101
 
96
102
  context 'server 4.0 or lower' do
@@ -183,7 +189,7 @@ describe 'SDAM error handling' do
183
189
  let(:operation) do
184
190
  expect(server.monitor.connection).not_to be nil
185
191
  expect(server.monitor.connection).to receive(:ismaster).at_least(:once).and_raise(exception)
186
- server.monitor.scan_semaphore.broadcast
192
+ server.scan_semaphore.broadcast
187
193
  6.times do
188
194
  sleep 0.5
189
195
  if server.unknown?
@@ -3,10 +3,6 @@ require 'spec_helper'
3
3
  describe 'SDAM events' do
4
4
  let(:subscriber) { Mongo::SDAMMonitoring::TestSubscriber.new }
5
5
 
6
- before do
7
- ClientRegistry.instance.close_all_clients
8
- end
9
-
10
6
  describe 'server closed event' do
11
7
  it 'is published when client is closed' do
12
8
  client = ClientRegistry.instance.new_local_client(
@@ -17,7 +13,7 @@ describe 'SDAM events' do
17
13
  client.database.command(ismaster: 1)
18
14
  expect(subscriber.events).to be_empty
19
15
 
20
- client.close(true)
16
+ client.close
21
17
 
22
18
  expect(subscriber.events).not_to be_empty
23
19
  event = subscriber.first_event('server_closed_event')
@@ -35,7 +31,7 @@ describe 'SDAM events' do
35
31
  client.database.command(ismaster: 1)
36
32
  expect(subscriber.events).to be_empty
37
33
 
38
- client.close(true)
34
+ client.close
39
35
 
40
36
  expect(subscriber.events).not_to be_empty
41
37
  event = subscriber.first_event('topology_closed_event')
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Server::Monitor' do
4
+
5
+ let(:client) do
6
+ new_local_client([ClusterConfig.instance.primary_address_str],
7
+ SpecConfig.instance.test_options.merge(SpecConfig.instance.auth_options.merge(
8
+ heartbeat_frequency: 1)))
9
+ end
10
+
11
+ it 'refreshes server descriptions in background', retry: 3 do
12
+ server = client.cluster.next_primary
13
+
14
+ expect(server.description).not_to be_unknown
15
+
16
+ server.unknown!
17
+
18
+ # This is racy, especially in JRuby, because the monitor may have
19
+ # already run and updated the description. Because of this we retry
20
+ # the test a few times.
21
+ expect(server.description).to be_unknown
22
+
23
+ # Wait for background thread to update the description
24
+ sleep 1.5
25
+
26
+ expect(server.description).not_to be_unknown
27
+ end
28
+ end
@@ -31,7 +31,7 @@ describe 'Server selector' do
31
31
  result
32
32
  end.to raise_error(Mongo::Error::NoServerAvailable)
33
33
  time_passed = Time.now - start_time
34
- expect(time_passed < 1).to be true
34
+ expect(time_passed).to be < 1
35
35
  end
36
36
  end
37
37
 
@@ -39,7 +39,7 @@ describe 'Server selector' do
39
39
  context 'there is a known primary' do
40
40
  before do
41
41
  client.cluster.next_primary
42
- client.close(true)
42
+ client.close
43
43
  expect(client.cluster.connected?).to be false
44
44
  end
45
45
 
@@ -51,7 +51,7 @@ describe 'Server selector' do
51
51
  context 'there is no known primary' do
52
52
  before do
53
53
  primary_server = client.cluster.next_primary
54
- client.close(true)
54
+ client.close
55
55
  expect(client.cluster.connected?).to be false
56
56
  primary_server.unknown!
57
57
  end
@@ -66,10 +66,12 @@ describe 'Server selector' do
66
66
 
67
67
  context 'monitoring thread is dead' do
68
68
  before do
69
- client.cluster.servers.first.monitor.instance_variable_get('@thread').kill
69
+ client.cluster.servers.each do |server|
70
+ server.monitor.instance_variable_get('@thread').kill
71
+ end
70
72
  server = client.cluster.next_primary
71
73
  if server
72
- server.monitor.instance_variable_set('@description', Mongo::Server::Description.new({}))
74
+ server.instance_variable_set('@description', Mongo::Server::Description.new({}))
73
75
  end
74
76
  end
75
77
 
@@ -0,0 +1,360 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'SRV Monitoring' do
4
+ context 'with SRV lookups mocked at Resolver' do
5
+ let(:srv_result) do
6
+ double('srv result').tap do |result|
7
+ allow(result).to receive(:empty?).and_return(false)
8
+ allow(result).to receive(:address_strs).and_return(
9
+ [ClusterConfig.instance.primary_address_str])
10
+ end
11
+ end
12
+
13
+ let(:client) do
14
+ allow_any_instance_of(Mongo::Srv::Resolver).to receive(:get_records).and_return(srv_result)
15
+ allow_any_instance_of(Mongo::Srv::Resolver).to receive(:get_txt_options_string)
16
+
17
+ new_local_client_nmio('mongodb+srv://foo.a.b', server_selection_timeout: 3.15)
18
+ end
19
+
20
+ context 'standalone/replica set' do
21
+ require_topology :single, :replica_set
22
+
23
+ it 'does not create SRV monitor' do
24
+ expect(client.cluster.topology).to be_a(Mongo::Cluster::Topology::Unknown)
25
+
26
+ client.cluster.run_sdam_flow(
27
+ Mongo::Server::Description.new(ClusterConfig.instance.primary_address_str),
28
+ ClusterConfig.instance.primary_description,
29
+ )
30
+
31
+ expect(client.cluster.topology).not_to be_a(Mongo::Cluster::Topology::Unknown)
32
+
33
+ expect(client.cluster.instance_variable_get('@srv_monitor')).to be nil
34
+ end
35
+ end
36
+
37
+ context 'sharded cluster' do
38
+ require_topology :sharded
39
+
40
+ it 'creates SRV monitor' do
41
+ expect(client.cluster.topology).to be_a(Mongo::Cluster::Topology::Unknown)
42
+
43
+ # Since we force the cluster to run sdam flow which creates a monitor,
44
+ # we need to manually adjust its state.
45
+ client.cluster.instance_variable_set('@connecting', true)
46
+
47
+ client.cluster.run_sdam_flow(
48
+ Mongo::Server::Description.new(ClusterConfig.instance.primary_address_str),
49
+ ClusterConfig.instance.primary_description,
50
+ )
51
+
52
+ expect(client.cluster.topology).to be_a(Mongo::Cluster::Topology::Sharded)
53
+
54
+ expect(client.cluster.instance_variable_get('@srv_monitor')).to be_a(Mongo::Cluster::SrvMonitor)
55
+
56
+ # Close the client in the test rather than allowing our post-test cleanup
57
+ # to take care of it, since the client references test doubles.
58
+ client.close
59
+ end
60
+ end
61
+ end
62
+
63
+ # These tests require a sharded cluster to be launched on localhost:27017
64
+ # and localhost:27018, plus internet connectivity for SRV record lookups.
65
+ context 'end to end' do
66
+ require_default_port_deployment
67
+
68
+ # JRuby apparently does not implement non-blocking UDP I/O which is used
69
+ # by RubyDNS:
70
+ # NotImplementedError: recvmsg_nonblock is not implemented
71
+ fails_on_jruby
72
+
73
+ before(:all) do
74
+ require 'support/dns'
75
+ end
76
+
77
+ let(:uri) do
78
+ "mongodb+srv://test-fake.test.build.10gen.cc/?tls=#{SpecConfig.instance.ssl?}&tlsInsecure=true"
79
+ end
80
+
81
+ let(:logger) do
82
+ Logger.new(STDERR, level: Logger::DEBUG)
83
+ end
84
+
85
+ let(:client) do
86
+ new_local_client(uri,
87
+ server_selection_timeout: 3.16,
88
+ resolv_options: {
89
+ nameserver: 'localhost',
90
+ nameserver_port: [['localhost', 5300], ['127.0.0.1', 5300]],
91
+ },
92
+ logger: logger,
93
+ )
94
+ end
95
+
96
+ before do
97
+ # Expedite the polling process
98
+ allow_any_instance_of(Mongo::Cluster::SrvMonitor).to receive(:scan_interval).and_return(1)
99
+ end
100
+
101
+ context 'sharded cluster' do
102
+ require_topology :sharded
103
+ require_multi_shard
104
+
105
+ it 'updates topology via SRV records' do
106
+
107
+ rules = [
108
+ ['_mongodb._tcp.test-fake.test.build.10gen.cc', :srv,
109
+ [0, 0, 27017, 'localhost.test.build.10gen.cc'],
110
+ ],
111
+ ]
112
+
113
+ mock_dns(rules) do
114
+ client.cluster.next_primary
115
+ expect(client.cluster.topology).to be_a(Mongo::Cluster::Topology::Sharded)
116
+
117
+ address_strs = client.cluster.servers.map(&:address).map(&:seed).sort
118
+ expect(address_strs).to eq(%w(
119
+ localhost.test.build.10gen.cc:27017
120
+ ))
121
+ end
122
+
123
+ # In Evergreen there are replica set nodes on the next port number
124
+ # after mongos nodes, therefore the addresses in DNS need to accurately
125
+ # reflect how many mongos we have.
126
+
127
+ rules = [
128
+ ['_mongodb._tcp.test-fake.test.build.10gen.cc', :srv,
129
+ [0, 0, 27018, 'localhost.test.build.10gen.cc'],
130
+ [0, 0, 27017, 'localhost.test.build.10gen.cc'],
131
+ ],
132
+ ]
133
+
134
+ mock_dns(rules) do
135
+ 15.times do
136
+ address_strs = client.cluster.servers_list.map(&:address).map(&:seed).sort
137
+ if address_strs == %w(
138
+ localhost.test.build.10gen.cc:27017
139
+ localhost.test.build.10gen.cc:27018
140
+ )
141
+ then
142
+ break
143
+ end
144
+ sleep 1
145
+ end
146
+
147
+ address_strs = client.cluster.servers_list.map(&:address).map(&:seed).sort
148
+ expect(address_strs).to eq(%w(
149
+ localhost.test.build.10gen.cc:27017
150
+ localhost.test.build.10gen.cc:27018
151
+ ))
152
+ end
153
+
154
+ # And because we have only two mongos in Evergreen, test removal
155
+ # separately here.
156
+
157
+ rules = [
158
+ ['_mongodb._tcp.test-fake.test.build.10gen.cc', :srv,
159
+ [0, 0, 27018, 'localhost.test.build.10gen.cc'],
160
+ ],
161
+ ]
162
+
163
+ mock_dns(rules) do
164
+ 15.times do
165
+ address_strs = client.cluster.servers_list.map(&:address).map(&:seed).sort
166
+ if address_strs == %w(
167
+ localhost.test.build.10gen.cc:27018
168
+ )
169
+ then
170
+ break
171
+ end
172
+ sleep 1
173
+ end
174
+
175
+ address_strs = client.cluster.servers_list.map(&:address).map(&:seed).sort
176
+ expect(address_strs).to eq(%w(
177
+ localhost.test.build.10gen.cc:27018
178
+ ))
179
+
180
+ expect(client.cluster.srv_monitor).to be_running
181
+ end
182
+ end
183
+ end
184
+
185
+ context 'unknown topology' do
186
+
187
+ it 'updates topology via SRV records' do
188
+
189
+ rules = [
190
+ ['_mongodb._tcp.test-fake.test.build.10gen.cc', :srv,
191
+ [0, 0, 27999, 'localhost.test.build.10gen.cc'],
192
+ ],
193
+ ]
194
+
195
+ mock_dns(rules) do
196
+ expect(client.cluster.topology).to be_a(Mongo::Cluster::Topology::Unknown)
197
+
198
+ address_strs = client.cluster.servers_list.map(&:address).map(&:seed).sort
199
+ expect(address_strs).to eq(%w(
200
+ localhost.test.build.10gen.cc:27999
201
+ ))
202
+ end
203
+
204
+ rules = [
205
+ ['_mongodb._tcp.test-fake.test.build.10gen.cc', :srv,
206
+ [0, 0, 27998, 'localhost.test.build.10gen.cc'],
207
+ [0, 0, 27999, 'localhost.test.build.10gen.cc'],
208
+ ],
209
+ ]
210
+
211
+ mock_dns(rules) do
212
+ 15.times do
213
+ address_strs = client.cluster.servers_list.map(&:address).map(&:seed).sort
214
+ if address_strs == %w(
215
+ localhost.test.build.10gen.cc:27998
216
+ localhost.test.build.10gen.cc:27999
217
+ )
218
+ then
219
+ break
220
+ end
221
+ sleep 1
222
+ end
223
+
224
+ address_strs = client.cluster.servers_list.map(&:address).map(&:seed).sort
225
+ expect(address_strs).to eq(%w(
226
+ localhost.test.build.10gen.cc:27998
227
+ localhost.test.build.10gen.cc:27999
228
+ ))
229
+ end
230
+
231
+ rules = [
232
+ ['_mongodb._tcp.test-fake.test.build.10gen.cc', :srv,
233
+ [0, 0, 27997, 'localhost.test.build.10gen.cc'],
234
+ ],
235
+ ]
236
+
237
+ mock_dns(rules) do
238
+ 15.times do
239
+ address_strs = client.cluster.servers_list.map(&:address).map(&:seed).sort
240
+ if address_strs == %w(
241
+ localhost.test.build.10gen.cc:27997
242
+ )
243
+ then
244
+ break
245
+ end
246
+ sleep 1
247
+ end
248
+
249
+ address_strs = client.cluster.servers_list.map(&:address).map(&:seed).sort
250
+ expect(address_strs).to eq(%w(
251
+ localhost.test.build.10gen.cc:27997
252
+ ))
253
+
254
+ expect(client.cluster.topology).to be_a(Mongo::Cluster::Topology::Unknown)
255
+
256
+ expect(client.cluster.srv_monitor).to be_running
257
+ end
258
+ end
259
+ end
260
+
261
+ context 'unknown to sharded' do
262
+ require_topology :sharded
263
+
264
+ it 'updates topology via SRV records' do
265
+
266
+ rules = [
267
+ ['_mongodb._tcp.test-fake.test.build.10gen.cc', :srv,
268
+ [0, 0, 27999, 'localhost.test.build.10gen.cc'],
269
+ ],
270
+ ]
271
+
272
+ mock_dns(rules) do
273
+ expect(client.cluster.topology).to be_a(Mongo::Cluster::Topology::Unknown)
274
+
275
+ address_strs = client.cluster.servers_list.map(&:address).map(&:seed).sort
276
+ expect(address_strs).to eq(%w(
277
+ localhost.test.build.10gen.cc:27999
278
+ ))
279
+ end
280
+
281
+ rules = [
282
+ ['_mongodb._tcp.test-fake.test.build.10gen.cc', :srv,
283
+ [0, 0, 27017, 'localhost.test.build.10gen.cc'],
284
+ ],
285
+ ]
286
+
287
+ mock_dns(rules) do
288
+ 15.times do
289
+ address_strs = client.cluster.servers.map(&:address).map(&:seed).sort
290
+ if address_strs == %w(
291
+ localhost.test.build.10gen.cc:27017
292
+ )
293
+ then
294
+ break
295
+ end
296
+ sleep 1
297
+ end
298
+
299
+ address_strs = client.cluster.servers.map(&:address).map(&:seed).sort
300
+ expect(address_strs).to eq(%w(
301
+ localhost.test.build.10gen.cc:27017
302
+ ))
303
+ expect(client.cluster.topology).to be_a(Mongo::Cluster::Topology::Sharded)
304
+
305
+ expect(client.cluster.srv_monitor).to be_running
306
+ end
307
+ end
308
+ end
309
+
310
+ context 'unknown to replica set' do
311
+ require_topology :replica_set
312
+
313
+ it 'updates topology via SRV records then stops SRV monitor' do
314
+
315
+ rules = [
316
+ ['_mongodb._tcp.test-fake.test.build.10gen.cc', :srv,
317
+ [0, 0, 27999, 'localhost.test.build.10gen.cc'],
318
+ ],
319
+ ]
320
+
321
+ mock_dns(rules) do
322
+ expect(client.cluster.topology).to be_a(Mongo::Cluster::Topology::Unknown)
323
+
324
+ address_strs = client.cluster.servers_list.map(&:address).map(&:seed).sort
325
+ expect(address_strs).to eq(%w(
326
+ localhost.test.build.10gen.cc:27999
327
+ ))
328
+ end
329
+
330
+ rules = [
331
+ ['_mongodb._tcp.test-fake.test.build.10gen.cc', :srv,
332
+ [0, 0, 27017, 'localhost.test.build.10gen.cc'],
333
+ ],
334
+ ]
335
+
336
+ mock_dns(rules) do
337
+ 15.times do
338
+ address_strs = client.cluster.servers.map(&:address).map(&:seed).sort
339
+ if address_strs == %w(
340
+ localhost.test.build.10gen.cc:27017
341
+ )
342
+ then
343
+ break
344
+ end
345
+ sleep 1
346
+ end
347
+
348
+ address_strs = client.cluster.servers.map(&:address).map(&:seed).sort
349
+ # The actual address will be localhost:27017 or 127.0.0.1:27017,
350
+ # depending on how the replica set is configured.
351
+ expect(address_strs.any? { |str| str =~ /27017/ }).to be true
352
+ # Covers both NoPrimary and WithPrimary replica sets
353
+ expect(client.cluster.topology).to be_a(Mongo::Cluster::Topology::ReplicaSetNoPrimary)
354
+
355
+ expect(client.cluster.srv_monitor).not_to be_running
356
+ end
357
+ end
358
+ end
359
+ end
360
+ end