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