mongoid 7.1.5 → 7.1.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/README.md +1 -1
  5. data/Rakefile +33 -7
  6. data/lib/mongoid/association/referenced/has_one/proxy.rb +6 -1
  7. data/lib/mongoid/attributes.rb +8 -1
  8. data/lib/mongoid/criteria/queryable/selector.rb +0 -4
  9. data/lib/mongoid/document.rb +3 -2
  10. data/lib/mongoid/errors/mongoid_error.rb +1 -1
  11. data/lib/mongoid/interceptable.rb +3 -1
  12. data/lib/mongoid/reloadable.rb +5 -0
  13. data/lib/mongoid/validatable/associated.rb +1 -1
  14. data/lib/mongoid/validatable/presence.rb +3 -3
  15. data/lib/mongoid/validatable/uniqueness.rb +1 -1
  16. data/lib/mongoid/version.rb +1 -1
  17. data/lib/rails/generators/mongoid/config/config_generator.rb +8 -1
  18. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +1 -1
  19. data/spec/app/models/customer.rb +11 -0
  20. data/spec/app/models/customer_address.rb +12 -0
  21. data/spec/app/models/dictionary.rb +6 -0
  22. data/spec/app/models/person.rb +2 -0
  23. data/spec/app/models/series.rb +1 -0
  24. data/spec/app/models/wiki_page.rb +1 -0
  25. data/spec/integration/app_spec.rb +178 -88
  26. data/spec/integration/associations/embeds_many_spec.rb +24 -0
  27. data/spec/integration/associations/embeds_one_spec.rb +24 -0
  28. data/spec/integration/associations/has_many_spec.rb +42 -0
  29. data/spec/integration/associations/has_one_spec.rb +42 -0
  30. data/spec/integration/callbacks_models.rb +49 -0
  31. data/spec/integration/callbacks_spec.rb +216 -0
  32. data/spec/integration/document_spec.rb +21 -0
  33. data/spec/lite_spec_helper.rb +6 -6
  34. data/spec/mongoid/association/embedded/embedded_in/proxy_spec.rb +50 -0
  35. data/spec/mongoid/atomic/paths_spec.rb +41 -0
  36. data/spec/mongoid/attributes_spec.rb +241 -0
  37. data/spec/mongoid/contextual/atomic_spec.rb +17 -4
  38. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +36 -0
  39. data/spec/mongoid/document_query_spec.rb +51 -0
  40. data/spec/mongoid/errors/mongoid_error_spec.rb +20 -8
  41. data/spec/mongoid/factory_spec.rb +2 -2
  42. data/spec/mongoid/persistable/savable_spec.rb +4 -4
  43. data/spec/mongoid/persistable/settable_spec.rb +30 -0
  44. data/spec/mongoid/persistable_spec.rb +2 -2
  45. data/spec/shared/LICENSE +20 -0
  46. data/spec/shared/bin/get-mongodb-download-url +17 -0
  47. data/spec/shared/bin/s3-copy +45 -0
  48. data/spec/shared/bin/s3-upload +69 -0
  49. data/spec/shared/lib/mrss/child_process_helper.rb +80 -0
  50. data/spec/shared/lib/mrss/cluster_config.rb +226 -0
  51. data/spec/shared/lib/mrss/constraints.rb +368 -0
  52. data/spec/shared/lib/mrss/docker_runner.rb +271 -0
  53. data/spec/shared/lib/mrss/lite_constraints.rb +191 -0
  54. data/spec/shared/lib/mrss/server_version_registry.rb +115 -0
  55. data/spec/shared/lib/mrss/spec_organizer.rb +179 -0
  56. data/spec/shared/lib/mrss/utils.rb +15 -0
  57. data/spec/shared/share/Dockerfile.erb +322 -0
  58. data/spec/shared/share/haproxy-1.conf +16 -0
  59. data/spec/shared/share/haproxy-2.conf +17 -0
  60. data/spec/shared/shlib/distro.sh +73 -0
  61. data/spec/shared/shlib/server.sh +317 -0
  62. data/spec/shared/shlib/set_env.sh +131 -0
  63. data/spec/spec_helper.rb +3 -1
  64. data/spec/support/constraints.rb +0 -226
  65. data/spec/support/spec_config.rb +8 -0
  66. metadata +538 -493
  67. metadata.gz.sig +0 -0
  68. data/spec/support/child_process_helper.rb +0 -76
  69. data/spec/support/lite_constraints.rb +0 -22
@@ -10,14 +10,26 @@ describe Mongoid::Errors::MongoidError do
10
10
  let(:options) { {} }
11
11
 
12
12
  before do
13
- {"message_title" => "message", "summary_title" => "summary", "resolution_title" => "resolution"}.each do |key, name|
14
- expect(::I18n).to receive(:translate).with("mongoid.errors.messages.#{key}", {}).and_return(name)
15
- end
16
-
17
- ["message", "summary", "resolution"].each do |name|
18
- expect(::I18n).to receive(:translate).
19
- with("mongoid.errors.messages.#{key}.#{name}", {}).
20
- and_return(name)
13
+ if RUBY_VERSION.start_with?('3.', '2.7')
14
+ {"message_title" => "message", "summary_title" => "summary", "resolution_title" => "resolution"}.each do |key, name|
15
+ expect(::I18n).to receive(:translate).with("mongoid.errors.messages.#{key}", **{}).and_return(name)
16
+ end
17
+
18
+ ["message", "summary", "resolution"].each do |name|
19
+ expect(::I18n).to receive(:translate).
20
+ with("mongoid.errors.messages.#{key}.#{name}", **{}).
21
+ and_return(name)
22
+ end
23
+ else
24
+ {"message_title" => "message", "summary_title" => "summary", "resolution_title" => "resolution"}.each do |key, name|
25
+ expect(::I18n).to receive(:translate).with("mongoid.errors.messages.#{key}", {}).and_return(name)
26
+ end
27
+
28
+ ["message", "summary", "resolution"].each do |name|
29
+ expect(::I18n).to receive(:translate).
30
+ with("mongoid.errors.messages.#{key}.#{name}", {}).
31
+ and_return(name)
32
+ end
21
33
  end
22
34
 
23
35
  error.compose_message(key, options)
@@ -109,11 +109,11 @@ describe Mongoid::Factory do
109
109
  context "when the attributes are nil" do
110
110
 
111
111
  let(:document) do
112
- described_class.from_db(Address, nil)
112
+ described_class.from_db(Animal, nil)
113
113
  end
114
114
 
115
115
  it "generates based on the provided class" do
116
- expect(document).to be_a(Address)
116
+ expect(document).to be_a(Animal)
117
117
  end
118
118
 
119
119
  it "sets the attributes to empty" do
@@ -169,8 +169,8 @@ describe Mongoid::Persistable::Savable do
169
169
  Person.create(title: "Blah")
170
170
  end
171
171
 
172
- let!(:address) do
173
- person.addresses.build(street: "Bond St")
172
+ let!(:symptom) do
173
+ person.symptoms.build(name: "Headache")
174
174
  end
175
175
 
176
176
  let!(:name) do
@@ -193,7 +193,7 @@ describe Mongoid::Persistable::Savable do
193
193
  "name.first_name" => "Ryan"
194
194
  },
195
195
  "$push"=> {
196
- "addresses" => { '$each' => [ { "_id" => address.id, "street" => "Bond St" } ] }
196
+ "symptoms" => { '$each' => [ { "_id" => symptom.id, "name" => "Headache" } ] }
197
197
  }
198
198
  })
199
199
  end
@@ -205,7 +205,7 @@ describe Mongoid::Persistable::Savable do
205
205
  end
206
206
 
207
207
  it "saves embedded many relations" do
208
- expect(person.addresses.first.street).to eq("Bond St")
208
+ expect(person.symptoms.first.name).to eq("Headache")
209
209
  end
210
210
 
211
211
  it "saves embedded one relations" do
@@ -512,4 +512,34 @@ describe Mongoid::Persistable::Settable do
512
512
  end
513
513
  end
514
514
  end
515
+
516
+ context "when the field being set was projected out" do
517
+ let(:full_agent) do
518
+ Agent.create!(title: "Double-Oh Eight")
519
+ end
520
+
521
+ let(:agent) do
522
+ Agent.where(_id: full_agent.id).only(:dob).first
523
+ end
524
+
525
+ context 'field exists in database' do
526
+ it "raises MissingAttributeError" do
527
+ lambda do
528
+ agent.set(title: '008')
529
+ end.should raise_error(ActiveModel::MissingAttributeError)
530
+
531
+ expect(agent.reload.title).to eq 'Double-Oh Eight'
532
+ end
533
+ end
534
+
535
+ context 'field does not exist in database' do
536
+ it "raises MissingAttributeError" do
537
+ lambda do
538
+ agent.set(number: '008')
539
+ end.should raise_error(ActiveModel::MissingAttributeError)
540
+
541
+ expect(agent.reload.read_attribute(:number)).to be nil
542
+ end
543
+ end
544
+ end
515
545
  end
@@ -178,8 +178,8 @@ describe Mongoid::Persistable do
178
178
 
179
179
  before do
180
180
  class Band
181
- def my_updates(*args)
182
- atomically(*args) do |d|
181
+ def my_updates(**args)
182
+ atomically(**args) do |d|
183
183
  d.set(name: "Placebo")
184
184
  d.unset(:origin)
185
185
  end
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2020 MongoDB, Inc.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ desired_version, arch = ARGV
4
+ if arch.nil?
5
+ STDERR.puts "Usage: get-mongodb-download-url desired-version arch"
6
+ exit 1
7
+ end
8
+
9
+ $: << File.join(File.dirname(__FILE__), '../lib')
10
+ require 'mrss/server_version_registry'
11
+
12
+ begin
13
+ puts Mrss::ServerVersionRegistry.new(desired_version, arch).download_url
14
+ rescue Mrss::ServerVersionRegistry::Error => exc
15
+ STDERR.puts "Error: #{exc}"
16
+ exit 2
17
+ end
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+ require 'aws-sdk-s3'
5
+
6
+ options = {}
7
+ OptionParser.new do |opts|
8
+ opts.banner = "Usage: s3-copy options"
9
+
10
+ opts.on("-r", "--region=REGION", "AWS region to use (default us-east-1)") do |v|
11
+ options[:region] = v
12
+ end
13
+
14
+ opts.on("-p", "--param=KEY=VALUE", "Specify parameter for new files") do |v|
15
+ options[:params] ||= {}
16
+ k, v = v.split('=', 2)
17
+ options[:params][k.to_sym] = v
18
+ end
19
+
20
+ opts.on("-f", "--from=BUCKET:PATH", "Bucket name and key (or path) to copy from") do |v|
21
+ options[:from] = v
22
+ end
23
+
24
+ opts.on("-t", "--to=BUCKET:PATH", "Bucket name and key (or path) to write to (may be specified more than once)") do |v|
25
+ options[:to] ||= []
26
+ options[:to] << v
27
+ end
28
+ end.parse!
29
+
30
+ ENV['AWS_REGION'] ||= options[:region] || 'us-east-1'
31
+
32
+ bucket, key = options.fetch(:from).split(':', 2)
33
+
34
+ s3 = Aws::S3::Client.new
35
+
36
+ options.fetch(:to).each do |dest|
37
+ STDERR.puts "Copying to #{dest}"
38
+ dbucket, dkey = dest.split(':', 2)
39
+ s3.copy_object(
40
+ bucket: dbucket,
41
+ key: dkey,
42
+ copy_source: "/#{bucket}/#{key}",
43
+ **options[:params] || {},
44
+ )
45
+ end
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+ require 'aws-sdk-s3'
5
+
6
+ options = {}
7
+ OptionParser.new do |opts|
8
+ opts.banner = "Usage: s3-upload options"
9
+
10
+ opts.on("-r", "--region=REGION", "AWS region to use (default us-east-1)") do |v|
11
+ options[:region] = v
12
+ end
13
+
14
+ opts.on("-p", "--param=KEY=VALUE", "Specify parameter for S3 upload") do |v|
15
+ options[:params] ||= {}
16
+ k, v = v.split('=', 2)
17
+ options[:params][k.to_sym] = v
18
+ end
19
+
20
+ opts.on("-f", "--file=PATH", "Path to the file to upload, - to upload standard input") do |v|
21
+ options[:file] = v
22
+ end
23
+
24
+ opts.on("-w", "--write=BUCKET:PATH", "Bucket name and key (or path) to upload to") do |v|
25
+ options[:write] = v
26
+ end
27
+
28
+ opts.on("-c", "--copy=BUCKET:PATH", "Bucket name and key (or path) to copy to (may be specified more than once)") do |v|
29
+ options[:copy] ||= []
30
+ options[:copy] << v
31
+ end
32
+ end.parse!
33
+
34
+ ENV['AWS_REGION'] ||= options[:region] || 'us-east-1'
35
+
36
+ def upload(f, options)
37
+ s3 = Aws::S3::Client.new
38
+ write = options.fetch(:write)
39
+ STDERR.puts "Writing #{write}"
40
+ bucket, key = write.split(':', 2)
41
+ s3.put_object(
42
+ body: f.read,
43
+ bucket: bucket,
44
+ key: key,
45
+ **options[:params] || {},
46
+ )
47
+ if copy = options[:copy]
48
+ copy.each do |dest|
49
+ STDERR.puts "Copying to #{dest}"
50
+ dbucket, dkey = dest.split(':', 2)
51
+ s3.copy_object(
52
+ bucket: dbucket,
53
+ key: dkey,
54
+ copy_source: "/#{bucket}/#{key}",
55
+ **options[:params] || {},
56
+ )
57
+ end
58
+ end
59
+ end
60
+
61
+ if options[:file] == '-'
62
+ upload(STDIN, options)
63
+ elsif options[:file]
64
+ File.open(options[:file]) do |f|
65
+ upload(f, options)
66
+ end
67
+ else
68
+ upload(STDIN, options)
69
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+ # encoding: utf-8
3
+
4
+ autoload :ChildProcess, 'childprocess'
5
+ autoload :Tempfile, 'tempfile'
6
+
7
+ module Mrss
8
+ module ChildProcessHelper
9
+ class SpawnError < StandardError; end
10
+
11
+ module_function def call(cmd, env: nil, cwd: nil)
12
+ process = ChildProcess.new(*cmd)
13
+ process.io.inherit!
14
+ if cwd
15
+ process.cwd = cwd
16
+ end
17
+ if env
18
+ env.each do |k, v|
19
+ process.environment[k.to_s] = v
20
+ end
21
+ end
22
+ process.start
23
+ process.wait
24
+ process
25
+ end
26
+
27
+ module_function def check_call(cmd, env: nil, cwd: nil)
28
+ process = call(cmd, env: env, cwd: cwd)
29
+ unless process.exit_code == 0
30
+ raise SpawnError, "Failed to execute: #{cmd}"
31
+ end
32
+ end
33
+
34
+ module_function def get_output(cmd, env: nil, cwd: nil)
35
+ process = ChildProcess.new(*cmd)
36
+ process.io.inherit!
37
+ if cwd
38
+ process.cwd = cwd
39
+ end
40
+ if env
41
+ env.each do |k, v|
42
+ process.environment[k.to_s] = v
43
+ end
44
+ end
45
+
46
+ output = ''
47
+ r, w = IO.pipe
48
+
49
+ begin
50
+ process.io.stdout = w
51
+ process.start
52
+ w.close
53
+
54
+ thread = Thread.new do
55
+ begin
56
+ loop do
57
+ output << r.readpartial(16384)
58
+ end
59
+ rescue EOFError
60
+ end
61
+ end
62
+
63
+ process.wait
64
+ thread.join
65
+ ensure
66
+ r.close
67
+ end
68
+
69
+ [process, output]
70
+ end
71
+
72
+ module_function def check_output(*args)
73
+ process, output = get_output(*args)
74
+ unless process.exit_code == 0
75
+ raise SpawnError,"Failed to execute: #{args}"
76
+ end
77
+ output
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,226 @@
1
+ # frozen_string_literal: true
2
+ # encoding: utf-8
3
+
4
+ # ClusterConfig requires ClientRegistry class provided by the host project.
5
+
6
+ require 'singleton'
7
+
8
+ module Mrss
9
+ class ClusterConfig
10
+ include Singleton
11
+ include RSpec::Core::Pending
12
+
13
+ def single_server?
14
+ determine_cluster_config
15
+ @single_server
16
+ end
17
+
18
+ def sharded_ish?
19
+ determine_cluster_config
20
+ @topology == :sharded || @topology == :load_balanced
21
+ end
22
+
23
+ def replica_set_name
24
+ determine_cluster_config
25
+ @replica_set_name
26
+ end
27
+
28
+ def server_version
29
+ determine_cluster_config
30
+ @server_version
31
+ end
32
+
33
+ def enterprise?
34
+ determine_cluster_config
35
+ @enterprise
36
+ end
37
+
38
+ def short_server_version
39
+ server_version.split('.')[0..1].join('.')
40
+ end
41
+
42
+ def fcv
43
+ determine_cluster_config
44
+ @fcv
45
+ end
46
+
47
+ # Per https://jira.mongodb.org/browse/SERVER-39052, working with FCV
48
+ # in sharded topologies is annoying. Also, FCV doesn't exist in servers
49
+ # less than 3.4. This method returns FCV on 3.4+ servers when in single
50
+ # or RS topologies, and otherwise returns the major.minor server version.
51
+ def fcv_ish
52
+ if server_version.nil?
53
+ raise "Deployment server version not known - check that connection to deployment succeeded"
54
+ end
55
+
56
+ if server_version >= '3.4' && !sharded_ish?
57
+ fcv
58
+ else
59
+ if short_server_version == '4.1'
60
+ '4.2'
61
+ else
62
+ short_server_version
63
+ end
64
+ end
65
+ end
66
+
67
+ # @return [ Mongo::Address ] The address of the primary in the deployment.
68
+ def primary_address
69
+ determine_cluster_config
70
+ @primary_address
71
+ end
72
+
73
+ def primary_address_str
74
+ determine_cluster_config
75
+ @primary_address.seed
76
+ end
77
+
78
+ def primary_address_host
79
+ both = primary_address_str
80
+ both.split(':').first
81
+ end
82
+
83
+ def primary_address_port
84
+ both = primary_address_str
85
+ both.split(':')[1] || 27017
86
+ end
87
+
88
+ def primary_description
89
+ determine_cluster_config
90
+ @primary_description
91
+ end
92
+
93
+ def server_parameters
94
+ determine_cluster_config
95
+ @server_parameters
96
+ end
97
+
98
+ # Try running a command on the admin database to see if the mongod was
99
+ # started with auth.
100
+ def auth_enabled?
101
+ if @auth_enabled.nil?
102
+ @auth_enabled = begin
103
+ basic_client.use(:admin).command(getCmdLineOpts: 1).first["argv"].include?("--auth")
104
+ rescue => e
105
+ e.message =~ /(not authorized)|(unauthorized)|(no users authenticated)|(requires authentication)/
106
+ end
107
+ end
108
+ @auth_enabled
109
+ end
110
+
111
+ def topology
112
+ determine_cluster_config
113
+ @topology
114
+ end
115
+
116
+ def storage_engine
117
+ @storage_engine ||= begin
118
+ # 2.6 does not have wired tiger
119
+ if short_server_version == '2.6'
120
+ :mmapv1
121
+ else
122
+ client = ClientRegistry.instance.global_client('root_authorized')
123
+ if sharded_ish?
124
+ shards = client.use(:admin).command(listShards: 1).first
125
+ if shards['shards'].empty?
126
+ raise 'Shards are empty'
127
+ end
128
+ shard = shards['shards'].first
129
+ address_str = shard['host'].sub(/^.*\//, '').sub(/,.*/, '')
130
+ client = ClusterTools.instance.direct_client(address_str,
131
+ SpecConfig.instance.test_options.merge(SpecConfig.instance.auth_options).merge(connect: :direct))
132
+ end
133
+ rv = client.use(:admin).command(serverStatus: 1).first
134
+ rv = rv['storageEngine']['name']
135
+ rv_map = {
136
+ 'wiredTiger' => :wired_tiger,
137
+ 'mmapv1' => :mmapv1,
138
+ }
139
+ rv_map[rv] || rv
140
+ end
141
+ end
142
+ end
143
+
144
+ # This method returns an alternate address for connecting to the configured
145
+ # deployment. For example, if the replica set is configured with nodes at
146
+ # of localhost:27017 and so on, this method will return 127.0.0.:27017.
147
+ #
148
+ # Note that the "alternate" refers to replica set configuration, not the
149
+ # addresses specified in test suite configuration. If the deployment topology
150
+ # is not a replica set, "alternate" refers to test suite configuration as
151
+ # this is the only configuration available.
152
+ def alternate_address
153
+ @alternate_address ||= begin
154
+ address = primary_address_host
155
+ str = case address
156
+ when '127.0.0.1'
157
+ 'localhost'
158
+ when /^(\d+\.){3}\d+$/
159
+ skip 'This test requires a hostname or 127.0.0.1 as address'
160
+ else
161
+ # We don't know if mongod is listening on ipv4 or ipv6, in principle.
162
+ # Our tests use ipv4, so hardcode that for now.
163
+ # To support both we need to try both addresses which will make this
164
+ # test more complicated.
165
+ #
166
+ # JRuby chokes on primary_address_port as the port (e.g. 27017).
167
+ # Since the port does not actually matter, use a common port like 80.
168
+ resolved_address = Addrinfo.getaddrinfo(address, 80, Socket::PF_INET).first.ip_address
169
+ if resolved_address.include?(':')
170
+ "[#{resolved_address}]"
171
+ else
172
+ resolved_address
173
+ end
174
+ end + ":#{primary_address_port}"
175
+ Mongo::Address.new(str)
176
+ end
177
+ end
178
+
179
+ private
180
+
181
+ def determine_cluster_config
182
+ return if @primary_address
183
+
184
+ # Run all commands to figure out the cluster configuration from the same
185
+ # client. This is somewhat wasteful when running a single test, but reduces
186
+ # test runtime for the suite overall because all commands are sent on the
187
+ # same connection rather than each command connecting to the cluster by
188
+ # itself.
189
+ client = ClientRegistry.instance.global_client('root_authorized')
190
+
191
+ primary = client.cluster.next_primary
192
+ @primary_address = primary.address
193
+ @primary_description = primary.description
194
+ @replica_set_name = client.cluster.topology.replica_set_name
195
+
196
+ @topology ||= begin
197
+ topology = client.cluster.topology.class.name.sub(/.*::/, '')
198
+ topology = topology.gsub(/([A-Z])/) { |match| '_' + match.downcase }.sub(/^_/, '')
199
+ if topology =~ /^replica_set/
200
+ topology = 'replica_set'
201
+ end
202
+ topology.to_sym
203
+ end
204
+
205
+ @single_server = client.cluster.servers_list.length == 1
206
+
207
+ build_info = client.database.command(buildInfo: 1).first
208
+
209
+ @server_version = build_info['version']
210
+ @enterprise = build_info['modules'] && build_info['modules'].include?('enterprise')
211
+
212
+ @server_parameters = client.use(:admin).command(getParameter: '*').first
213
+
214
+ if !sharded_ish? && short_server_version >= '3.4'
215
+ rv = @server_parameters['featureCompatibilityVersion']
216
+ @fcv = rv['version'] || rv
217
+ end
218
+ end
219
+
220
+ def basic_client
221
+ # Do not cache the result here so that if the client gets closed,
222
+ # client registry reconnects it in subsequent tests
223
+ ClientRegistry.instance.global_client('basic')
224
+ end
225
+ end
226
+ end