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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/CONTRIBUTING.md +1 -1
- data/lib/mongo.rb +2 -0
- data/lib/mongo/address.rb +4 -0
- data/lib/mongo/address/validator.rb +99 -0
- data/lib/mongo/auth.rb +7 -2
- data/lib/mongo/auth/user.rb +1 -7
- data/lib/mongo/background_thread.rb +135 -0
- data/lib/mongo/bulk_write/transformable.rb +3 -3
- data/lib/mongo/client.rb +74 -16
- data/lib/mongo/cluster.rb +193 -41
- data/lib/mongo/cluster/periodic_executor.rb +31 -43
- data/lib/mongo/cluster/sdam_flow.rb +26 -3
- data/lib/mongo/cluster/srv_monitor.rb +127 -0
- data/lib/mongo/collection/view/readable.rb +3 -5
- data/lib/mongo/collection/view/writable.rb +3 -3
- data/lib/mongo/cursor/builder/get_more_command.rb +1 -4
- data/lib/mongo/cursor/builder/kill_cursors_command.rb +5 -23
- data/lib/mongo/cursor/builder/op_get_more.rb +2 -2
- data/lib/mongo/cursor/builder/op_kill_cursors.rb +5 -24
- data/lib/mongo/error.rb +1 -0
- data/lib/mongo/error/auth_error.rb +1 -1
- data/lib/mongo/error/connection_check_out_timeout.rb +7 -8
- data/lib/mongo/error/invalid_address.rb +24 -0
- data/lib/mongo/error/notable.rb +2 -2
- data/lib/mongo/error/operation_failure.rb +3 -3
- data/lib/mongo/error/pool_closed_error.rb +11 -4
- data/lib/mongo/event.rb +1 -1
- data/lib/mongo/grid/file.rb +0 -5
- data/lib/mongo/grid/file/chunk.rb +0 -2
- data/lib/mongo/grid/fs_bucket.rb +13 -15
- data/lib/mongo/grid/stream/write.rb +3 -9
- data/lib/mongo/loggable.rb +5 -1
- data/lib/mongo/monitoring.rb +1 -0
- data/lib/mongo/monitoring/event/cmap/connection_check_out_failed.rb +7 -0
- data/lib/mongo/monitoring/event/cmap/connection_checked_in.rb +11 -3
- data/lib/mongo/monitoring/event/cmap/connection_checked_out.rb +11 -3
- data/lib/mongo/monitoring/event/cmap/pool_closed.rb +11 -3
- data/lib/mongo/monitoring/event/cmap/pool_created.rb +12 -3
- data/lib/mongo/monitoring/unified_sdam_log_subscriber.rb +62 -0
- data/lib/mongo/operation/shared/executable.rb +5 -10
- data/lib/mongo/operation/shared/sessions_supported.rb +1 -5
- data/lib/mongo/protocol/get_more.rb +1 -2
- data/lib/mongo/protocol/kill_cursors.rb +13 -6
- data/lib/mongo/protocol/serializers.rb +4 -20
- data/lib/mongo/retryable.rb +9 -34
- data/lib/mongo/semaphore.rb +1 -1
- data/lib/mongo/server.rb +113 -42
- data/lib/mongo/server/connection.rb +12 -5
- data/lib/mongo/server/connection_pool.rb +250 -40
- data/lib/mongo/server/connection_pool/populator.rb +58 -0
- data/lib/mongo/server/description.rb +9 -2
- data/lib/mongo/server/monitor.rb +68 -93
- data/lib/mongo/server/monitor/connection.rb +2 -0
- data/lib/mongo/server_selector/selectable.rb +13 -5
- data/lib/mongo/session.rb +0 -13
- data/lib/mongo/srv.rb +17 -0
- data/lib/mongo/srv/monitor.rb +96 -0
- data/lib/mongo/srv/resolver.rb +130 -0
- data/lib/mongo/srv/result.rb +126 -0
- data/lib/mongo/srv/warning_result.rb +35 -0
- data/lib/mongo/uri.rb +45 -55
- data/lib/mongo/uri/srv_protocol.rb +89 -42
- data/lib/mongo/version.rb +1 -1
- data/mongo.gemspec +3 -4
- data/spec/README.md +6 -1
- data/spec/enterprise_auth/kerberos_spec.rb +7 -6
- data/spec/integration/change_stream_examples_spec.rb +0 -4
- data/spec/integration/client_construction_spec.rb +14 -2
- data/spec/integration/connect_single_rs_name_spec.rb +2 -2
- data/spec/integration/connection_pool_populator_spec.rb +296 -0
- data/spec/integration/connection_spec.rb +31 -22
- data/spec/integration/cursor_reaping_spec.rb +1 -2
- data/spec/integration/docs_examples_spec.rb +0 -4
- data/spec/integration/heartbeat_events_spec.rb +17 -15
- data/spec/integration/reconnect_spec.rb +144 -1
- data/spec/integration/retryable_writes_errors_spec.rb +0 -4
- data/spec/integration/retryable_writes_spec.rb +36 -36
- data/spec/integration/sdam_error_handling_spec.rb +31 -25
- data/spec/integration/sdam_events_spec.rb +2 -6
- data/spec/integration/server_monitor_spec.rb +28 -0
- data/spec/integration/server_selector_spec.rb +7 -5
- data/spec/integration/srv_monitoring_spec.rb +360 -0
- data/spec/integration/step_down_spec.rb +4 -6
- data/spec/lite_spec_helper.rb +22 -0
- data/spec/mongo/address/validator_spec.rb +51 -0
- data/spec/mongo/auth/cr_spec.rb +1 -29
- data/spec/mongo/auth/ldap_spec.rb +1 -29
- data/spec/mongo/auth/scram/conversation_spec.rb +0 -2
- data/spec/mongo/auth/scram/negotiation_spec.rb +1 -1
- data/spec/mongo/auth/scram_spec.rb +1 -29
- data/spec/mongo/auth/user/view_spec.rb +1 -36
- data/spec/mongo/auth/user_spec.rb +0 -12
- data/spec/mongo/auth/x509_spec.rb +1 -29
- data/spec/mongo/bulk_write_spec.rb +2 -2
- data/spec/mongo/client_construction_spec.rb +56 -15
- data/spec/mongo/client_spec.rb +31 -27
- data/spec/mongo/cluster/periodic_executor_spec.rb +16 -0
- data/spec/mongo/cluster/srv_monitor_spec.rb +214 -0
- data/spec/mongo/cluster/topology/replica_set_spec.rb +16 -11
- data/spec/mongo/cluster/topology/sharded_spec.rb +12 -9
- data/spec/mongo/cluster/topology/single_spec.rb +20 -11
- data/spec/mongo/cluster_spec.rb +45 -29
- data/spec/mongo/collection/view/map_reduce_spec.rb +14 -9
- data/spec/mongo/collection/view/readable_spec.rb +0 -16
- data/spec/mongo/collection_spec.rb +0 -44
- data/spec/mongo/cursor/builder/get_more_command_spec.rb +2 -4
- data/spec/mongo/cursor/builder/op_get_more_spec.rb +2 -4
- data/spec/mongo/cursor_spec.rb +27 -7
- data/spec/mongo/monitoring/event/cmap/connection_checked_in_spec.rb +10 -3
- data/spec/mongo/monitoring/event/cmap/connection_checked_out_spec.rb +10 -3
- data/spec/mongo/monitoring/event/cmap/pool_closed_spec.rb +10 -3
- data/spec/mongo/monitoring/event/cmap/pool_created_spec.rb +10 -3
- data/spec/mongo/operation/delete/op_msg_spec.rb +17 -8
- data/spec/mongo/operation/insert/op_msg_spec.rb +50 -35
- data/spec/mongo/operation/update/op_msg_spec.rb +14 -7
- data/spec/mongo/retryable_spec.rb +52 -31
- data/spec/mongo/server/app_metadata_spec.rb +0 -8
- data/spec/mongo/server/connection_auth_spec.rb +5 -2
- data/spec/mongo/server/connection_pool/populator_spec.rb +101 -0
- data/spec/mongo/server/connection_pool_spec.rb +256 -107
- data/spec/mongo/server/connection_spec.rb +22 -33
- data/spec/mongo/server/description_spec.rb +42 -4
- data/spec/mongo/server/monitor/connection_spec.rb +22 -11
- data/spec/mongo/server/monitor_spec.rb +66 -107
- data/spec/mongo/server_spec.rb +82 -60
- data/spec/mongo/session/session_pool_spec.rb +1 -5
- data/spec/mongo/session_spec.rb +0 -4
- data/spec/mongo/socket/ssl_spec.rb +2 -2
- data/spec/mongo/srv/monitor_spec.rb +211 -0
- data/spec/mongo/srv/result_spec.rb +54 -0
- data/spec/mongo/uri/srv_protocol_spec.rb +30 -15
- data/spec/mongo/uri_spec.rb +125 -4
- data/spec/spec_helper.rb +6 -0
- data/spec/spec_tests/auth_spec.rb +39 -0
- data/spec/spec_tests/cmap_spec.rb +55 -8
- data/spec/spec_tests/connection_string_spec.rb +6 -31
- data/spec/spec_tests/data/auth/connection-string.yml +297 -0
- data/spec/spec_tests/data/cmap/pool-checkout-error-closed.yml +4 -1
- data/spec/spec_tests/data/cmap/pool-create-with-options.yml +1 -0
- data/spec/spec_tests/data/command_monitoring/insertMany.yml +1 -1
- data/spec/spec_tests/data/connection_string/invalid-uris.yml +20 -0
- data/spec/spec_tests/data/connection_string/valid-auth.yml +16 -0
- data/spec/spec_tests/data/connection_string/valid-warnings.yml +26 -30
- data/spec/spec_tests/data/transactions/abort.yml +3 -3
- data/spec/spec_tests/data/transactions/error-labels.yml +3 -3
- data/spec/spec_tests/data/transactions_api/callback-retry.yml +3 -3
- data/spec/spec_tests/data/uri_options/auth-options.yml +1 -1
- data/spec/spec_tests/max_staleness_spec.rb +7 -2
- data/spec/spec_tests/retryable_reads_spec.rb +0 -31
- data/spec/spec_tests/sdam_monitoring_spec.rb +12 -12
- data/spec/spec_tests/sdam_spec.rb +4 -7
- data/spec/spec_tests/server_selection_spec.rb +6 -2
- data/spec/spec_tests/transactions_spec.rb +0 -2
- data/spec/spec_tests/uri_options_spec.rb +4 -2
- data/spec/stress/connection_pool_stress_spec.rb +203 -0
- data/spec/stress/connection_pool_timing_spec.rb +181 -0
- data/spec/support/auth.rb +113 -0
- data/spec/support/background_thread_registry.rb +63 -0
- data/spec/support/client_registry.rb +11 -2
- data/spec/support/cluster_config.rb +65 -46
- data/spec/support/cluster_tools.rb +2 -2
- data/spec/support/cmap.rb +13 -14
- data/spec/support/cmap/verifier.rb +4 -5
- data/spec/support/command_monitoring.rb +0 -5
- data/spec/support/common_shortcuts.rb +101 -1
- data/spec/support/constraints.rb +25 -0
- data/spec/support/dns.rb +13 -0
- data/spec/support/event_subscriber.rb +0 -7
- data/spec/support/json_ext_formatter.rb +5 -1
- data/spec/support/lite_constraints.rb +22 -6
- data/spec/support/local_resource_registry.rb +34 -0
- data/spec/support/sdam_monitoring.rb +115 -0
- data/spec/support/spec_config.rb +20 -6
- data/spec/support/spec_setup.rb +2 -2
- data/spec/support/transactions.rb +1 -1
- data/spec/support/transactions/test.rb +1 -1
- data/spec/support/utils.rb +1 -16
- metadata +685 -659
- metadata.gz.sig +0 -0
- data/lib/mongo/event/description_changed.rb +0 -52
- data/spec/integration/bson_symbol_spec.rb +0 -34
- data/spec/integration/crud_spec.rb +0 -45
- data/spec/integration/get_more_spec.rb +0 -32
- data/spec/integration/grid_fs_bucket_spec.rb +0 -48
- data/spec/integration/retryable_errors_spec.rb +0 -265
- data/spec/integration/size_limit_spec.rb~12e1e9c4f... RUBY-2242 Fix zlib compression (#2021) +0 -98
- data/spec/mongo/cursor/builder/op_kill_cursors_spec.rb +0 -56
- data/spec/runners/sdam/verifier.rb +0 -88
@@ -33,6 +33,8 @@ module Mongo
|
|
33
33
|
# @since 2.5.0
|
34
34
|
class SRVProtocol < URI
|
35
35
|
|
36
|
+
attr_reader :srv_records
|
37
|
+
|
36
38
|
# Gets the options hash that needs to be passed to a Mongo::Client on instantiation, so we
|
37
39
|
# don't have to merge the txt record options, credentials, and database in at that point -
|
38
40
|
# we only have a single point here.
|
@@ -49,49 +51,93 @@ module Mongo
|
|
49
51
|
@user ? opts.merge(credentials) : opts
|
50
52
|
end
|
51
53
|
|
52
|
-
|
54
|
+
# @return [ Srv::Result ] SRV lookup result.
|
55
|
+
#
|
56
|
+
# @api private
|
57
|
+
attr_reader :srv_result
|
58
|
+
|
59
|
+
# The hostname that is specified in the URI and used to look up
|
60
|
+
# SRV records.
|
61
|
+
#
|
62
|
+
# This attribute needs to be defined because SRVProtocol changes
|
63
|
+
# #servers to be the result of the lookup rather than the hostname
|
64
|
+
# specified in the URI.
|
65
|
+
#
|
66
|
+
# @return [ String ] The hostname used in SRV lookup.
|
67
|
+
#
|
68
|
+
# @api private
|
69
|
+
attr_reader :query_hostname
|
53
70
|
|
54
|
-
|
71
|
+
private
|
55
72
|
|
73
|
+
# @return [ String ] DOT_PARTITION The '.' character used to delineate the parts of a
|
74
|
+
# hostname.
|
75
|
+
#
|
76
|
+
# @deprecated
|
56
77
|
DOT_PARTITION = '.'.freeze
|
57
78
|
|
79
|
+
# @return [ Array<String> ] VALID_TXT_OPTIONS The valid options for a TXT record to specify.
|
58
80
|
VALID_TXT_OPTIONS = ['replicaset', 'authsource'].freeze
|
59
81
|
|
82
|
+
# @return [ String ] INVALID_HOST Error message format string indicating that the hostname in
|
83
|
+
# in the URI does not fit the expected form.
|
60
84
|
INVALID_HOST = "One and only one host is required in a connection string with the " +
|
61
85
|
"'#{MONGODB_SRV_SCHEME}' protocol.".freeze
|
62
86
|
|
87
|
+
# @return [ String ] INVALID_PORT Error message format string indicating that a port was
|
88
|
+
# included with an SRV hostname.
|
63
89
|
INVALID_PORT = "It is not allowed to specify a port in a connection string with the " +
|
64
90
|
"'#{MONGODB_SRV_SCHEME}' protocol.".freeze
|
65
91
|
|
92
|
+
# @return [ String ] INVALID_DOMAIN Error message format string indicating that the domain name
|
93
|
+
# of the hostname does not fit the expected form.
|
66
94
|
# @deprecated
|
67
95
|
INVALID_DOMAIN = "The domain name must consist of at least two parts: the domain name, " +
|
68
96
|
"and a TLD.".freeze
|
69
97
|
|
98
|
+
# @return [ String ] NO_SRV_RECORDS Error message format string indicating that no SRV records
|
99
|
+
# were found.
|
70
100
|
NO_SRV_RECORDS = "The DNS query returned no SRV records at hostname (%s)".freeze
|
71
101
|
|
72
|
-
|
73
|
-
|
74
|
-
|
102
|
+
# @return [ String ] INVALID_TXT_RECORD_OPTION Error message format string indicating that an
|
103
|
+
# unexpected TXT record option was found.
|
75
104
|
INVALID_TXT_RECORD_OPTION = "TXT records can only specify the options " +
|
76
105
|
"[#{VALID_TXT_OPTIONS.join(', ')}].".freeze
|
77
106
|
|
78
|
-
|
79
|
-
"that of the hostname (%s)".freeze
|
80
|
-
|
107
|
+
# @return [ String ] FORMAT The expected SRV URI format.
|
81
108
|
FORMAT = 'mongodb+srv://[username:password@]host[/[database][?options]]'.freeze
|
82
109
|
|
110
|
+
# Gets the MongoDB SRV URI scheme.
|
111
|
+
#
|
112
|
+
# @return [ String ] The MongoDB SRV URI scheme.
|
83
113
|
def scheme
|
84
114
|
MONGODB_SRV_SCHEME
|
85
115
|
end
|
86
116
|
|
117
|
+
# Raises an InvalidURI error.
|
118
|
+
#
|
119
|
+
# @param [ String ] details A detailed error message.
|
120
|
+
#
|
121
|
+
# @raise [ Mongo::Error::InvalidURI ]
|
87
122
|
def raise_invalid_error!(details)
|
88
123
|
raise Error::InvalidURI.new(@string, details, FORMAT)
|
89
124
|
end
|
90
125
|
|
126
|
+
# Gets the SRV resolver.
|
127
|
+
#
|
128
|
+
# @return [ Mongo::Srv::Resolver ]
|
91
129
|
def resolver
|
92
|
-
@resolver ||=
|
130
|
+
@resolver ||= Srv::Resolver.new(
|
131
|
+
raise_on_invalid: true,
|
132
|
+
resolv_options: options[:resolv_options],
|
133
|
+
)
|
93
134
|
end
|
94
135
|
|
136
|
+
# Parses the credentials from the URI and performs DNS queries to obtain
|
137
|
+
# the hosts and TXT options.
|
138
|
+
#
|
139
|
+
# @param [ String ] remaining The portion of the URI pertaining to the
|
140
|
+
# authentication credentials and the hosts.
|
95
141
|
def parse!(remaining)
|
96
142
|
super
|
97
143
|
|
@@ -99,14 +145,21 @@ module Mongo
|
|
99
145
|
raise_invalid_error!(INVALID_HOST)
|
100
146
|
end
|
101
147
|
hostname = @servers.first
|
102
|
-
|
148
|
+
validate_srv_hostname(hostname)
|
149
|
+
@query_hostname = hostname
|
103
150
|
|
104
|
-
|
105
|
-
|
151
|
+
@srv_result = resolver.get_records(hostname)
|
152
|
+
if srv_result.empty?
|
153
|
+
raise Error::NoSRVRecords.new(NO_SRV_RECORDS % hostname)
|
154
|
+
end
|
155
|
+
@txt_options = get_txt_options(hostname) || {}
|
156
|
+
records = srv_result.address_strs
|
106
157
|
records.each do |record|
|
107
|
-
|
158
|
+
validate_address_str!(record)
|
108
159
|
end
|
109
160
|
@servers = records
|
161
|
+
rescue Error::InvalidAddress => e
|
162
|
+
raise_invalid_error!(e.message)
|
110
163
|
end
|
111
164
|
|
112
165
|
# Validates the hostname used in an SRV URI.
|
@@ -118,7 +171,7 @@ module Mongo
|
|
118
171
|
# components (foo.bar.tld).
|
119
172
|
#
|
120
173
|
# Raises Error::InvalidURI if validation fails.
|
121
|
-
def
|
174
|
+
def validate_srv_hostname(hostname)
|
122
175
|
raise_invalid_error!(INVALID_PORT) if hostname.include?(HOST_PORT_DELIM)
|
123
176
|
|
124
177
|
if hostname.start_with?('.')
|
@@ -136,39 +189,33 @@ module Mongo
|
|
136
189
|
end
|
137
190
|
end
|
138
191
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
def validate_record!(record_host, hostname)
|
152
|
-
domainname = hostname.split(DOT_PARTITION)[1..-1]
|
153
|
-
host_parts = record_host.split(DOT_PARTITION)
|
154
|
-
unless (host_parts.size > domainname.size) && (domainname == host_parts[-domainname.length..-1])
|
155
|
-
raise Error::MismatchedDomain.new(MISMATCHED_DOMAINNAME % [record_host, domainname])
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
|
-
def get_txt_opts(host)
|
160
|
-
records = resolver.getresources(host, Resolv::DNS::Resource::IN::TXT)
|
161
|
-
unless records.empty?
|
162
|
-
if records.size > 1
|
163
|
-
raise Error::InvalidTXTRecord.new(MORE_THAN_ONE_TXT_RECORD_FOUND % host)
|
164
|
-
end
|
165
|
-
options_string = records[0].strings.join
|
192
|
+
# Obtains the TXT options of a host.
|
193
|
+
#
|
194
|
+
# @param [ String ] hostname The hostname whose records should be obtained.
|
195
|
+
#
|
196
|
+
# @return [ Hash ] The TXT record options (an empyt hash if no TXT
|
197
|
+
# records are found).
|
198
|
+
#
|
199
|
+
# @raise [ Mongo::Error::InvalidTXTRecord ] If more than one TXT record is found.
|
200
|
+
def get_txt_options(hostname)
|
201
|
+
options_string = resolver.get_txt_options_string(hostname)
|
202
|
+
if options_string
|
166
203
|
parse_txt_options!(options_string)
|
204
|
+
else
|
205
|
+
{}
|
167
206
|
end
|
168
207
|
end
|
169
208
|
|
209
|
+
# Parses the TXT record options into a hash and adds the options to set of all URI options
|
210
|
+
# parsed.
|
211
|
+
#
|
212
|
+
# @param [ String ] string The concatenated TXT options.
|
213
|
+
#
|
214
|
+
# @return [ Hash ] The parsed TXT options.
|
215
|
+
#
|
216
|
+
# @raise [ Mongo::Error::InvalidTXTRecord ] If the TXT record does not fit the expected form
|
217
|
+
# or the option specified is not a valid TXT option.
|
170
218
|
def parse_txt_options!(string)
|
171
|
-
return {} unless string
|
172
219
|
string.split(INDIV_URI_OPTS_DELIM).reduce({}) do |txt_options, opt|
|
173
220
|
raise Error::InvalidTXTRecord.new(INVALID_OPTS_VALUE_DELIM) unless opt.index(URI_OPTS_VALUE_DELIM)
|
174
221
|
key, value = opt.split(URI_OPTS_VALUE_DELIM)
|
data/lib/mongo/version.rb
CHANGED
data/mongo.gemspec
CHANGED
@@ -4,10 +4,7 @@ require 'mongo/version'
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |s|
|
6
6
|
s.name = 'mongo'
|
7
|
-
|
8
|
-
# Without it rubygems tries to modify version which fails because
|
9
|
-
# Mongo::VERSION is frozen.
|
10
|
-
s.version = Mongo::VERSION.dup
|
7
|
+
s.version = Mongo::VERSION
|
11
8
|
s.platform = Gem::Platform::RUBY
|
12
9
|
|
13
10
|
s.authors = ['Tyler Brock', 'Emily Stolfo', 'Durran Jordan']
|
@@ -32,5 +29,7 @@ Gem::Specification.new do |s|
|
|
32
29
|
s.require_paths = ['lib']
|
33
30
|
s.bindir = 'bin'
|
34
31
|
|
32
|
+
s.required_ruby_version = ">= 2.3"
|
33
|
+
|
35
34
|
s.add_dependency 'bson', '>=4.4.2', '<5.0.0'
|
36
35
|
end
|
data/spec/README.md
CHANGED
@@ -78,12 +78,17 @@ configuration is needed:
|
|
78
78
|
|
79
79
|
A sharded cluster can be configured with mlaunch:
|
80
80
|
|
81
|
-
mlaunch init --replicaset --name ruby-driver-rs --sharded 1 \
|
81
|
+
mlaunch init --replicaset --name ruby-driver-rs --sharded 1 --mongos 2 \
|
82
82
|
--dir /tmp/mdb-sc --setParameter enableTestCommands=1
|
83
83
|
|
84
84
|
As with the replica set, the test suite will automatically detect sharded
|
85
85
|
cluster topology.
|
86
86
|
|
87
|
+
Note that some tests require a sharded cluster with exactly one shard and
|
88
|
+
other tests require a sharded cluster with more than one shard. Tests requiring
|
89
|
+
a single shard can be run against a deployment with multiple shards by
|
90
|
+
specifying only one mongos address in MONGODB_URI.
|
91
|
+
|
87
92
|
## TLS With Verification
|
88
93
|
|
89
94
|
The test suite includes a set of TLS certificates for configuring a server
|
@@ -1,6 +1,13 @@
|
|
1
1
|
require 'mongo'
|
2
|
+
require 'support/lite_constraints'
|
3
|
+
|
4
|
+
RSpec.configure do |config|
|
5
|
+
config.extend(LiteConstraints)
|
6
|
+
end
|
2
7
|
|
3
8
|
describe 'kerberos authentication' do
|
9
|
+
require_mongo_kerberos
|
10
|
+
|
4
11
|
let(:user) do
|
5
12
|
"#{ENV['SASL_USER']}%40#{ENV['SASL_HOST'].upcase}"
|
6
13
|
end
|
@@ -25,13 +32,7 @@ describe 'kerberos authentication' do
|
|
25
32
|
Mongo::Client.new(uri)
|
26
33
|
end
|
27
34
|
|
28
|
-
before do
|
29
|
-
skip 'ENTERPRISE_AUTH_TESTS env var not specified' unless ENV['ENTERPRISE_AUTH_TESTS']
|
30
|
-
end
|
31
|
-
|
32
35
|
let(:doc) do
|
33
|
-
require 'mongo_kerberos'
|
34
|
-
|
35
36
|
client.database[:test].find.first
|
36
37
|
end
|
37
38
|
|
@@ -31,6 +31,18 @@ describe 'Client construction' do
|
|
31
31
|
expect(client.cluster.topology).to be_a(Mongo::Cluster::Topology::Single)
|
32
32
|
expect(client.options[:connect]).to eq :direct
|
33
33
|
end
|
34
|
+
|
35
|
+
it 'creates connection pool and keeps it populated' do
|
36
|
+
client = ClientRegistry.instance.new_local_client([SpecConfig.instance.addresses.first],
|
37
|
+
base_options.merge(min_pool_size: 1))
|
38
|
+
# allow connection pool to populate
|
39
|
+
sleep 0.1
|
40
|
+
|
41
|
+
server = client.cluster.next_primary
|
42
|
+
expect(server.pool.size).to eq(1)
|
43
|
+
client['client_construction'].insert_one(test: 1)
|
44
|
+
expect(server.pool.size).to eq(1)
|
45
|
+
end
|
34
46
|
end
|
35
47
|
|
36
48
|
context 'in replica set topology' do
|
@@ -61,7 +73,7 @@ describe 'Client construction' do
|
|
61
73
|
end
|
62
74
|
|
63
75
|
it 'connects directly' do
|
64
|
-
primary_address = ClusterConfig.instance.
|
76
|
+
primary_address = ClusterConfig.instance.primary_address_str
|
65
77
|
client = ClientRegistry.instance.new_local_client([primary_address],
|
66
78
|
base_options.merge(connect: :direct))
|
67
79
|
client['client_construction'].insert_one(test: 1)
|
@@ -84,7 +96,7 @@ describe 'Client construction' do
|
|
84
96
|
end
|
85
97
|
|
86
98
|
it 'connects directly' do
|
87
|
-
primary_address = ClusterConfig.instance.
|
99
|
+
primary_address = ClusterConfig.instance.primary_address_str
|
88
100
|
client = ClientRegistry.instance.new_local_client([SpecConfig.instance.addresses.first],
|
89
101
|
base_options.merge(connect: :direct))
|
90
102
|
client['client_construction'].insert_one(test: 1)
|
@@ -3,11 +3,11 @@ require 'spec_helper'
|
|
3
3
|
describe 'Direct connection with RS name' do
|
4
4
|
before(:all) do
|
5
5
|
# preload
|
6
|
-
ClientRegistry.instance.close_all_clients
|
7
6
|
ClusterConfig.instance.replica_set_name
|
8
|
-
ClientRegistry.instance.close_all_clients
|
9
7
|
end
|
10
8
|
|
9
|
+
clean_slate_for_all
|
10
|
+
|
11
11
|
shared_examples_for 'passes RS name to topology' do
|
12
12
|
it 'passes RS name to topology' do
|
13
13
|
expect(client.cluster.topology.replica_set_name).to eq(replica_set_name)
|
@@ -0,0 +1,296 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Connection pool populator integration' do
|
4
|
+
let(:options) { {} }
|
5
|
+
|
6
|
+
let(:server_options) do
|
7
|
+
SpecConfig.instance.test_options.merge(options).merge(SpecConfig.instance.auth_options)
|
8
|
+
end
|
9
|
+
|
10
|
+
let(:address) do
|
11
|
+
Mongo::Address.new(SpecConfig.instance.addresses.first)
|
12
|
+
end
|
13
|
+
|
14
|
+
let(:monitoring) do
|
15
|
+
Mongo::Monitoring.new(monitoring: false)
|
16
|
+
end
|
17
|
+
|
18
|
+
let(:listeners) do
|
19
|
+
Mongo::Event::Listeners.new
|
20
|
+
end
|
21
|
+
|
22
|
+
declare_topology_double
|
23
|
+
|
24
|
+
let(:cluster) do
|
25
|
+
double('cluster').tap do |cl|
|
26
|
+
allow(cl).to receive(:topology).and_return(topology)
|
27
|
+
allow(cl).to receive(:app_metadata).and_return(app_metadata)
|
28
|
+
allow(cl).to receive(:options).and_return({})
|
29
|
+
allow(cl).to receive(:update_cluster_time)
|
30
|
+
allow(cl).to receive(:cluster_time).and_return(nil)
|
31
|
+
allow(cl).to receive(:run_sdam_flow)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
let(:server) do
|
36
|
+
register_server(
|
37
|
+
Mongo::Server.new(address, cluster, monitoring, listeners,
|
38
|
+
{monitoring_io: false}.update(server_options)
|
39
|
+
).tap do |server|
|
40
|
+
allow(server).to receive(:description).and_return(ClusterConfig.instance.primary_description)
|
41
|
+
end
|
42
|
+
)
|
43
|
+
end
|
44
|
+
|
45
|
+
let(:pool) do
|
46
|
+
server.pool
|
47
|
+
end
|
48
|
+
|
49
|
+
describe '#initialize' do
|
50
|
+
context 'when a min size is provided' do
|
51
|
+
|
52
|
+
let(:options) do
|
53
|
+
{ min_pool_size: 2, max_pool_size: 5 }
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'creates the pool with min pool size connections' do
|
57
|
+
pool
|
58
|
+
sleep 2
|
59
|
+
|
60
|
+
expect(pool.size).to eq(2)
|
61
|
+
expect(pool.available_count).to eq(2)
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'does not use the same objects in the pool' do
|
65
|
+
expect(pool.check_out).to_not equal(pool.check_out)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context 'when min size is zero' do
|
70
|
+
|
71
|
+
it 'does not start the background thread' do
|
72
|
+
pool
|
73
|
+
sleep 2
|
74
|
+
|
75
|
+
expect(pool.size).to eq(0)
|
76
|
+
expect(pool.instance_variable_get('@populator').running?).to be false
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe '#clear' do
|
82
|
+
context 'when a min size is provided' do
|
83
|
+
let(:options) do
|
84
|
+
{ min_pool_size: 1 }
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'repopulates the pool periodically only up to min size' do
|
88
|
+
pool
|
89
|
+
|
90
|
+
sleep 2
|
91
|
+
expect(pool.size).to eq(1)
|
92
|
+
expect(pool.available_count).to eq(1)
|
93
|
+
first_connection = pool.check_out
|
94
|
+
pool.check_in(first_connection)
|
95
|
+
|
96
|
+
pool.clear
|
97
|
+
|
98
|
+
sleep 2
|
99
|
+
expect(pool.size).to eq(1)
|
100
|
+
expect(pool.available_count).to eq(1)
|
101
|
+
second_connection = pool.check_out
|
102
|
+
pool.check_in(second_connection)
|
103
|
+
expect(second_connection).to_not eq(first_connection)
|
104
|
+
|
105
|
+
# When populate is re-run, the pool size should not change
|
106
|
+
pool.populate
|
107
|
+
expect(pool.size).to eq(1)
|
108
|
+
expect(pool.available_count).to eq(1)
|
109
|
+
third_connection = pool.check_out
|
110
|
+
expect(third_connection).to eq(second_connection)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe '#check_in' do
|
116
|
+
context 'when a min size is provided' do
|
117
|
+
let(:options) do
|
118
|
+
{ min_pool_size: 1 }
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'repopulates the pool after check_in of a closed connection' do
|
122
|
+
pool
|
123
|
+
|
124
|
+
sleep 2
|
125
|
+
expect(pool.size).to eq(1)
|
126
|
+
first_connection = pool.check_out
|
127
|
+
first_connection.disconnect!
|
128
|
+
expect(pool.size).to eq(1)
|
129
|
+
|
130
|
+
pool.check_in(first_connection)
|
131
|
+
|
132
|
+
sleep 2
|
133
|
+
expect(pool.size).to eq(1)
|
134
|
+
expect(pool.available_count).to eq(1)
|
135
|
+
second_connection = pool.check_out
|
136
|
+
expect(second_connection).to_not eq(first_connection)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
describe '#check_out' do
|
142
|
+
context 'when min size and idle time are provided' do
|
143
|
+
|
144
|
+
let(:options) do
|
145
|
+
{ max_pool_size: 2, min_pool_size: 2, max_idle_time: 0.5 }
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'repopulates the pool after check_out empties idle connections' do
|
149
|
+
pool
|
150
|
+
|
151
|
+
first_connection = pool.check_out
|
152
|
+
second_connection = pool.check_out
|
153
|
+
|
154
|
+
first_connection.record_checkin!
|
155
|
+
second_connection.record_checkin!
|
156
|
+
|
157
|
+
pool.check_in(first_connection)
|
158
|
+
pool.check_in(second_connection)
|
159
|
+
|
160
|
+
expect(pool.size).to eq(2)
|
161
|
+
|
162
|
+
# let both connections become idle
|
163
|
+
sleep 0.5
|
164
|
+
|
165
|
+
# check_out should discard first two connections, trigger in-flow
|
166
|
+
# creation of a single connection, then wake up populate thread
|
167
|
+
third_connection = pool.check_out
|
168
|
+
expect(third_connection).to_not eq(first_connection)
|
169
|
+
expect(third_connection).to_not eq(second_connection)
|
170
|
+
|
171
|
+
# populate thread should create a new connection for the pool
|
172
|
+
sleep 2
|
173
|
+
expect(pool.size).to eq(2)
|
174
|
+
fourth_connection = pool.check_out
|
175
|
+
expect(fourth_connection).to_not eq(first_connection)
|
176
|
+
expect(fourth_connection).to_not eq(second_connection)
|
177
|
+
expect(fourth_connection).to_not eq(third_connection)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
describe '#close' do
|
183
|
+
context 'when min size is provided' do
|
184
|
+
|
185
|
+
let(:options) do
|
186
|
+
{ min_pool_size: 2, max_pool_size: 5 }
|
187
|
+
end
|
188
|
+
|
189
|
+
it 'terminates and does not repopulate the pool after pool is closed' do
|
190
|
+
pool
|
191
|
+
|
192
|
+
sleep 2
|
193
|
+
expect(pool.size).to eq(2)
|
194
|
+
|
195
|
+
connection = pool.check_out
|
196
|
+
|
197
|
+
expect(pool.size).to eq(2)
|
198
|
+
pool.close(force: true)
|
199
|
+
|
200
|
+
expect(pool.closed?).to be true
|
201
|
+
expect(pool.instance_variable_get('@available_connections').empty?).to be true
|
202
|
+
expect(pool.instance_variable_get('@checked_out_connections').empty?).to be true
|
203
|
+
|
204
|
+
# populate thread should terminate
|
205
|
+
sleep 2
|
206
|
+
expect(pool.instance_variable_get('@populator').running?).to be false
|
207
|
+
expect(pool.closed?).to be true
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
describe '#close_idle_sockets' do
|
213
|
+
context 'when min size and idle time are provided' do
|
214
|
+
let(:options) do
|
215
|
+
{ min_pool_size: 1, max_idle_time: 0.5 }
|
216
|
+
end
|
217
|
+
|
218
|
+
it 'repopulates pool after sockets are closes' do
|
219
|
+
pool
|
220
|
+
|
221
|
+
sleep 2
|
222
|
+
expect(pool.size).to eq(1)
|
223
|
+
|
224
|
+
connection = pool.check_out
|
225
|
+
connection.record_checkin!
|
226
|
+
pool.check_in(connection)
|
227
|
+
|
228
|
+
# let the connection become idle
|
229
|
+
sleep 0.5
|
230
|
+
|
231
|
+
# close idle_sockets should trigger populate
|
232
|
+
pool.close_idle_sockets
|
233
|
+
|
234
|
+
sleep 2
|
235
|
+
expect(pool.size).to eq(1)
|
236
|
+
expect(pool.check_out).not_to eq(connection)
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
describe '#populate' do
|
242
|
+
let(:options) do
|
243
|
+
{ min_pool_size: 1 }
|
244
|
+
end
|
245
|
+
|
246
|
+
context 'when populate encounters a network error twice' do
|
247
|
+
it 'retries once and does not stop the populator' do
|
248
|
+
expect_any_instance_of(Mongo::Server::ConnectionPool).to \
|
249
|
+
receive(:create_and_add_connection).twice.and_raise(Mongo::Error::SocketError)
|
250
|
+
pool
|
251
|
+
sleep 2
|
252
|
+
expect(pool.populator.running?).to be true
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
context 'when populate encounters a non-network error' do
|
257
|
+
it 'does not retry and does not stop the populator' do
|
258
|
+
expect_any_instance_of(Mongo::Server::ConnectionPool).to \
|
259
|
+
receive(:create_and_add_connection).and_raise(Mongo::Error)
|
260
|
+
pool
|
261
|
+
sleep 2
|
262
|
+
expect(pool.populator.running?).to be true
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
describe 'when forking is enabled' do
|
268
|
+
only_mri
|
269
|
+
|
270
|
+
context 'when min size is provided' do
|
271
|
+
min_server_version '2.8'
|
272
|
+
|
273
|
+
it 'populates the parent and child pools' do
|
274
|
+
client = ClientRegistry.instance.new_local_client([SpecConfig.instance.addresses.first],
|
275
|
+
server_options.merge(min_pool_size: 2, max_pool_size: 5))
|
276
|
+
# let pool populate
|
277
|
+
sleep 2
|
278
|
+
server = client.cluster.next_primary
|
279
|
+
pool = server.pool
|
280
|
+
expect(pool.size).to eq(2)
|
281
|
+
|
282
|
+
fork do
|
283
|
+
# follow forking guidance
|
284
|
+
client.close
|
285
|
+
client.reconnect
|
286
|
+
# let pool populate
|
287
|
+
sleep 2
|
288
|
+
|
289
|
+
server = client.cluster.next_primary
|
290
|
+
pool = server.pool
|
291
|
+
expect(pool.size).to eq(2)
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
end
|