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
@@ -0,0 +1,181 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Connection pool timing test' do
4
+ before(:all) do
5
+ if !SpecConfig.instance.stress_spec?
6
+ skip 'Stress spec not enabled'
7
+ end
8
+
9
+ ClientRegistry.instance.close_all_clients
10
+
11
+ # This set up is taken from the step_down_spec file. In a future PR, ClusterTools
12
+ # may be modified so this set up is no longer necessary.
13
+ if ClusterConfig.instance.fcv_ish >= '4.2' && ClusterConfig.instance.topology == :replica_set
14
+ ClusterTools.instance.set_election_timeout(5)
15
+ ClusterTools.instance.set_election_handoff(false)
16
+ end
17
+ end
18
+
19
+ after(:all) do
20
+ if ClusterConfig.instance.fcv_ish >= '4.2' && ClusterConfig.instance.topology == :replica_set
21
+ ClusterTools.instance.set_election_timeout(10)
22
+ ClusterTools.instance.set_election_handoff(true)
23
+ ClusterTools.instance.reset_priorities
24
+ end
25
+ end
26
+
27
+ let(:client) do
28
+ authorized_client.with(options.merge(monitoring: true))
29
+ end
30
+
31
+ let!(:collection) do
32
+ client[authorized_collection.name].tap do |collection|
33
+ collection.drop
34
+ collection.insert_many(documents)
35
+ end
36
+ end
37
+
38
+ let(:documents) do
39
+ [].tap do |documents|
40
+ 10000.times do |i|
41
+ documents << { a: i}
42
+ end
43
+ end
44
+ end
45
+
46
+ let(:operation_threads) do
47
+ [].tap do |threads|
48
+ thread_count.times do |i|
49
+ threads << Thread.new do
50
+ 100.times do |j|
51
+ collection.find(a: i+j).to_a
52
+ sleep 0.01
53
+ collection.find(a: i+j).to_a
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+
60
+ let(:thread_count) { 5 }
61
+
62
+ context 'when there is no max idle time' do
63
+ let(:options) do
64
+ { max_pool_size: 10, min_pool_size: 5 }
65
+ end
66
+
67
+ let(:threads) { operation_threads }
68
+
69
+ it 'does not error' do
70
+ start = Time.now
71
+ expect {
72
+ threads.collect { |t| t.join }
73
+ }.not_to raise_error
74
+ puts "[Connection Pool Timing] Duration with no max idle time: #{Time.now - start}"
75
+ end
76
+ end
77
+
78
+ context 'when there is a low max idle time' do
79
+ let(:options) do
80
+ { max_pool_size: 10, min_pool_size: 5, max_idle_time: 0.1 }
81
+ end
82
+
83
+ let(:threads) { operation_threads }
84
+
85
+ it 'does not error' do
86
+ start = Time.now
87
+ expect {
88
+ threads.collect { |t| t.join }
89
+ }.not_to raise_error
90
+ puts "[Connection Pool Timing] Duration with low max idle time: #{Time.now - start}"
91
+ end
92
+ end
93
+
94
+ context 'when clear is called periodically' do
95
+ let(:options) do
96
+ { max_pool_size: 10, min_pool_size: 5 }
97
+ end
98
+
99
+ let(:threads) do
100
+ threads = operation_threads
101
+ threads << Thread.new do
102
+ 10.times do
103
+ sleep 0.1
104
+ client.cluster.next_primary.pool.clear
105
+ end
106
+ end
107
+ threads
108
+ end
109
+
110
+ it 'does not error' do
111
+ start = Time.now
112
+ expect {
113
+ threads.collect { |t| t.join }
114
+ }.not_to raise_error
115
+ puts "[Connection Pool Timing] Duration when clear is called periodically: #{Time.now - start}"
116
+ end
117
+ end
118
+
119
+ context 'when primary is changed, then more operations are performed' do
120
+ min_server_fcv '4.2'
121
+ require_topology :replica_set
122
+
123
+ let(:options) do
124
+ { max_pool_size: 10, min_pool_size: 5 }
125
+ end
126
+
127
+ let(:more_threads) do
128
+ PossiblyConcurrentArray.new.tap do |more_threads|
129
+ 5.times do |i|
130
+ more_threads << Thread.new do
131
+ 10.times do |j|
132
+ collection.find(a: i+j).to_a
133
+ sleep 0.01
134
+ collection.find(a: i+j).to_a
135
+ end
136
+ end
137
+ end
138
+ end
139
+ end
140
+
141
+ let(:threads) do
142
+ threads = PossiblyConcurrentArray.new
143
+
144
+ 5.times do |i|
145
+ threads << Thread.new do
146
+ 10.times do |j|
147
+ collection.find(a: i+j).to_a
148
+ sleep 0.01
149
+ collection.find(a: i+j).to_a
150
+ end
151
+ end
152
+ end
153
+
154
+ threads << Thread.new do
155
+ # Wait for other threads to terminate first, otherwise we get an error
156
+ # when trying to perform operations during primary change
157
+ sleep 1
158
+
159
+ @primary_chane_start = Time.now
160
+ ClusterTools.instance.change_primary
161
+ @primary_change_end = Time.now
162
+
163
+ # Primary change is complete; execute more operations
164
+ more_threads.collect { |t| t.join }
165
+ end
166
+ threads
167
+ end
168
+
169
+ it 'does not error' do
170
+ threads
171
+ start = Time.now
172
+ expect do
173
+ threads.each do |t|
174
+ t.join
175
+ end
176
+ end.not_to raise_error
177
+ puts "[Connection Pool Timing] Duration before primary change: #{@primary_chane_start - start}. "\
178
+ "Duration after primary change: #{Time.now - @primary_change_end}"
179
+ end
180
+ end
181
+ end
@@ -0,0 +1,113 @@
1
+ # Copyright (C) 2014-2019 MongoDB, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ RSpec::Matchers.define :have_blank_credentials do
15
+ match do |client|
16
+ %i(auth_mech auth_mech_properties auth_source password user).all? do |key|
17
+ client.options[key].nil?
18
+ end
19
+ end
20
+
21
+ failure_message do |client|
22
+ "Expected client to have blank credentials, but got the following credentials: \n\n" +
23
+ client.options.inspect
24
+ end
25
+ end
26
+
27
+ module Mongo
28
+ module Auth
29
+ class Spec
30
+
31
+ attr_reader :description
32
+ attr_reader :tests
33
+
34
+ def initialize(file)
35
+ file = File.new(file)
36
+ @spec = YAML.load(ERB.new(file.read).result)
37
+ file.close
38
+ @description = File.basename(file)
39
+ end
40
+
41
+ def tests
42
+ @tests ||= @spec['tests'].collect do |spec|
43
+ Test.new(spec)
44
+ end
45
+ end
46
+ end
47
+
48
+ class Test
49
+ attr_reader :description
50
+ attr_reader :uri_string
51
+
52
+ def initialize(spec)
53
+ @spec = spec
54
+ @description = @spec['description']
55
+ @uri_string = @spec['uri']
56
+ end
57
+
58
+ def valid?
59
+ @spec['valid']
60
+ end
61
+
62
+ def credential
63
+ @spec['credential']
64
+ end
65
+
66
+ def client
67
+ @client ||= ClientRegistry.instance.new_local_client(@spec['uri'], monitoring_io: false)
68
+ end
69
+
70
+ def expected_credential
71
+ expected_credential = {
72
+ 'auth_source' => expected_auth_source,
73
+ }
74
+
75
+ if credential['username']
76
+ expected_credential['user'] = credential['username']
77
+ expected_credential['password'] = credential['password']
78
+ end
79
+
80
+ if credential['mechanism']
81
+ expected_credential['auth_mech'] = expected_auth_mech
82
+ end
83
+
84
+ if credential['mechanism_properties']
85
+ expected_credential['auth_mech_properties'] = expected_auth_mech_properties
86
+ end
87
+
88
+ expected_credential
89
+ end
90
+
91
+ def received_credential
92
+ client.options.select do |k, _|
93
+ %w(auth_mech auth_mech_properties auth_source password user).include?(k)
94
+ end
95
+ end
96
+
97
+ private
98
+
99
+ def expected_auth_mech
100
+ Mongo::URI::AUTH_MECH_MAP[credential['mechanism']]
101
+ end
102
+
103
+ def expected_auth_mech_properties
104
+ credential['mechanism_properties'].keys.map(&:downcase)
105
+ end
106
+
107
+ def expected_auth_source
108
+ return :external if credential['source'] == '$external'
109
+ credential['source']
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,63 @@
1
+ require 'singleton'
2
+ require 'ostruct'
3
+
4
+ module Mongo
5
+ module BackgroundThread
6
+
7
+ alias :start_without_tracking! :start!
8
+
9
+ def start!
10
+ start_without_tracking!.tap do |thread|
11
+ BackgroundThreadRegistry.instance.register(self, thread)
12
+ end
13
+ end
14
+ end
15
+ end
16
+
17
+ class BackgroundThreadRegistry
18
+ include Singleton
19
+
20
+ def initialize
21
+ @lock = Mutex.new
22
+ @records = []
23
+ end
24
+
25
+ def register(object, thread)
26
+ @lock.synchronize do
27
+ @records << OpenStruct.new(
28
+ thread: thread,
29
+ object: object,
30
+ example: $current_example,
31
+ )
32
+ end
33
+ end
34
+
35
+ def verify_empty!
36
+ @lock.synchronize do
37
+ alive_thread_records = @records.select { |record| record.thread.alive? }
38
+ if alive_thread_records.any?
39
+ msg = "Live background threads after closing all clients:"
40
+ alive_thread_records.each do |record|
41
+ msg << "\n #{record.object}"
42
+ if record.object.respond_to?(:options)
43
+ msg << "\n #{record.object.options}"
44
+ end
45
+ msg << "\n in #{record.example.id} #{record.example.full_description}"
46
+ end
47
+ raise msg
48
+ end
49
+ @records.clear
50
+ end
51
+ end
52
+ end
53
+
54
+ RSpec.configure do |config|
55
+ config.around do |example|
56
+ $current_example = example
57
+ begin
58
+ example.run
59
+ ensure
60
+ $current_example = nil
61
+ end
62
+ end
63
+ end
@@ -209,7 +209,16 @@ class ClientRegistry
209
209
 
210
210
  def close_local_clients
211
211
  @lock.synchronize do
212
- @local_clients.map(&:close)
212
+ @local_clients.each do |client|
213
+ cluster = client.cluster
214
+ # Disconnect this cluster if and only if it is not shared with
215
+ # any of the global clients we know about.
216
+ if @global_clients.none? { |name, global_client|
217
+ cluster.object_id == global_client.cluster.object_id
218
+ }
219
+ cluster.disconnect!
220
+ end
221
+ end
213
222
  @local_clients = []
214
223
  end
215
224
  end
@@ -219,7 +228,7 @@ class ClientRegistry
219
228
  close_local_clients
220
229
  @lock.synchronize do
221
230
  @global_clients.each do |name, client|
222
- client.close(true)
231
+ client.close
223
232
  end
224
233
  end
225
234
  end
@@ -3,36 +3,19 @@ require 'singleton'
3
3
  class ClusterConfig
4
4
  include Singleton
5
5
 
6
- def basic_client
7
- # Do not cache the result here so that if the client gets closed,
8
- # client registry reconnects it in subsequent tests
9
- ClientRegistry.instance.global_client('basic')
10
- end
11
-
12
6
  def single_server?
13
- basic_client.cluster.servers.length == 1
14
- end
15
-
16
- def mongos?
17
- if @mongos.nil?
18
- basic_client.cluster.next_primary
19
- @mongos = basic_client.cluster.topology.is_a?(Mongo::Cluster::Topology::Sharded)
20
- end
21
- @mongos
7
+ determine_cluster_config
8
+ @single_server
22
9
  end
23
10
 
24
11
  def replica_set_name
25
- @replica_set_name ||= begin
26
- basic_client.cluster.next_primary
27
- basic_client.cluster.topology.replica_set_name
28
- end
12
+ determine_cluster_config
13
+ @replica_set_name
29
14
  end
30
15
 
31
16
  def server_version
32
- @server_version ||= begin
33
- client = ClientRegistry.instance.global_client('authorized')
34
- client.database.command(buildInfo: 1).first['version']
35
- end
17
+ determine_cluster_config
18
+ @server_version
36
19
  end
37
20
 
38
21
  def short_server_version
@@ -40,11 +23,8 @@ class ClusterConfig
40
23
  end
41
24
 
42
25
  def fcv
43
- @fcv ||= begin
44
- client = ClientRegistry.instance.global_client('root_authorized')
45
- rv = client.use(:admin).command(getParameter: 1, featureCompatibilityVersion: 1).first['featureCompatibilityVersion']
46
- rv['version'] || rv
47
- end
26
+ determine_cluster_config
27
+ @fcv
48
28
  end
49
29
 
50
30
  # Per https://jira.mongodb.org/browse/SERVER-39052, working with FCV
@@ -52,7 +32,7 @@ class ClusterConfig
52
32
  # less than 3.4. This method returns FCV on 3.4+ servers when in single
53
33
  # or RS topologies, and otherwise returns the major.minor server version.
54
34
  def fcv_ish
55
- if server_version >= '3.4' && !mongos?
35
+ if server_version >= '3.4' && topology != :sharded
56
36
  fcv
57
37
  else
58
38
  if short_server_version == '4.1'
@@ -64,18 +44,13 @@ class ClusterConfig
64
44
  end
65
45
 
66
46
  def primary_address
67
- @primary_address ||= begin
68
- client = ClientRegistry.instance.global_client('authorized')
69
- if client.cluster.topology.is_a?(Mongo::Cluster::Topology::ReplicaSetWithPrimary)
70
- client.cluster.servers.detect { |server| server.primary? }.address
71
- else
72
- client.cluster.servers.first.address
73
- end.seed
74
- end
47
+ determine_cluster_config
48
+ @primary_address
75
49
  end
76
50
 
77
51
  def primary_address_str
78
- primary_address
52
+ determine_cluster_config
53
+ @primary_address.seed
79
54
  end
80
55
 
81
56
  def primary_address_host
@@ -88,6 +63,11 @@ class ClusterConfig
88
63
  both.split(':')[1] || 27017
89
64
  end
90
65
 
66
+ def primary_description
67
+ determine_cluster_config
68
+ @primary_description
69
+ end
70
+
91
71
  # Try running a command on the admin database to see if the mongod was
92
72
  # started with auth.
93
73
  def auth_enabled?
@@ -102,14 +82,8 @@ class ClusterConfig
102
82
  end
103
83
 
104
84
  def topology
105
- @topology ||= begin
106
- topology = basic_client.cluster.topology.class.name.sub(/.*::/, '')
107
- topology = topology.gsub(/([A-Z])/) { |match| '_' + match.downcase }.sub(/^_/, '')
108
- if topology =~ /^replica_set/
109
- topology = 'replica_set'
110
- end
111
- topology.to_sym
112
- end
85
+ determine_cluster_config
86
+ @topology
113
87
  end
114
88
 
115
89
  def storage_engine
@@ -121,6 +95,9 @@ class ClusterConfig
121
95
  client = ClientRegistry.instance.global_client('root_authorized')
122
96
  if topology == :sharded
123
97
  shards = client.use(:admin).command(listShards: 1).first
98
+ if shards['shards'].empty?
99
+ raise 'Shards are empty'
100
+ end
124
101
  shard = shards['shards'].first
125
102
  address_str = shard['host'].sub(/^.*\//, '').sub(/,.*/, '')
126
103
  client = ClusterTools.instance.direct_client(address_str,
@@ -136,4 +113,46 @@ class ClusterConfig
136
113
  end
137
114
  end
138
115
  end
116
+
117
+ private
118
+
119
+ def determine_cluster_config
120
+ return if @primary_address
121
+
122
+ # Run all commands to figure out the cluster configuration from the same
123
+ # client. This is somewhat wasteful when running a single test, but reduces
124
+ # test runtime for the suite overall because all commands are sent on the
125
+ # same connection rather than each command connecting to the cluster by
126
+ # itself.
127
+ client = ClientRegistry.instance.global_client('root_authorized')
128
+
129
+ primary = client.cluster.next_primary
130
+ @primary_address = primary.address
131
+ @primary_description = primary.description
132
+ @replica_set_name = client.cluster.topology.replica_set_name
133
+
134
+ @topology ||= begin
135
+ topology = client.cluster.topology.class.name.sub(/.*::/, '')
136
+ topology = topology.gsub(/([A-Z])/) { |match| '_' + match.downcase }.sub(/^_/, '')
137
+ if topology =~ /^replica_set/
138
+ topology = 'replica_set'
139
+ end
140
+ topology.to_sym
141
+ end
142
+
143
+ @single_server = client.cluster.servers_list.length == 1
144
+
145
+ @server_version = client.database.command(buildInfo: 1).first['version']
146
+
147
+ if @topology != :sharded && short_server_version >= '3.4'
148
+ rv = client.use(:admin).command(getParameter: 1, featureCompatibilityVersion: 1).first['featureCompatibilityVersion']
149
+ @fcv = rv['version'] || rv
150
+ end
151
+ end
152
+
153
+ def basic_client
154
+ # Do not cache the result here so that if the client gets closed,
155
+ # client registry reconnects it in subsequent tests
156
+ ClientRegistry.instance.global_client('basic')
157
+ end
139
158
  end