mongo 2.13.2 → 2.13.3

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 (40) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/lib/mongo/collection.rb +2 -0
  4. data/lib/mongo/database.rb +14 -2
  5. data/lib/mongo/grid/fs_bucket.rb +37 -37
  6. data/lib/mongo/operation/parallel_scan/command.rb +1 -2
  7. data/lib/mongo/operation/shared/read_preference_supported.rb +38 -36
  8. data/lib/mongo/operation/shared/sessions_supported.rb +3 -2
  9. data/lib/mongo/protocol/msg.rb +2 -2
  10. data/lib/mongo/protocol/query.rb +11 -11
  11. data/lib/mongo/server_selector/secondary_preferred.rb +2 -7
  12. data/lib/mongo/version.rb +1 -1
  13. data/spec/integration/sdam_error_handling_spec.rb +1 -1
  14. data/spec/integration/sdam_events_spec.rb +3 -5
  15. data/spec/integration/secondary_reads_spec.rb +102 -0
  16. data/spec/mongo/index/view_spec.rb +4 -2
  17. data/spec/mongo/operation/read_preference_legacy_spec.rb +9 -19
  18. data/spec/mongo/operation/read_preference_op_msg_spec.rb +3 -3
  19. data/spec/mongo/server/app_metadata_shared.rb +33 -7
  20. data/spec/mongo/server_selector/secondary_preferred_spec.rb +6 -6
  21. data/spec/runners/transactions/operation.rb +13 -2
  22. data/spec/shared/bin/get-mongodb-download-url +17 -0
  23. data/spec/shared/lib/mrss/cluster_config.rb +221 -0
  24. data/spec/shared/lib/mrss/constraints.rb +43 -0
  25. data/spec/shared/lib/mrss/docker_runner.rb +265 -0
  26. data/spec/shared/lib/mrss/lite_constraints.rb +16 -0
  27. data/spec/shared/lib/mrss/server_version_registry.rb +115 -0
  28. data/spec/shared/lib/mrss/spec_organizer.rb +3 -0
  29. data/spec/shared/lib/mrss/utils.rb +15 -0
  30. data/spec/shared/share/Dockerfile.erb +231 -0
  31. data/spec/shared/shlib/distro.sh +73 -0
  32. data/spec/shared/shlib/server.sh +290 -0
  33. data/spec/shared/shlib/set_env.sh +128 -0
  34. data/spec/support/client_registry.rb +8 -4
  35. data/spec/support/client_registry_macros.rb +14 -5
  36. data/spec/support/spec_config.rb +12 -0
  37. data/spec/support/spec_setup.rb +48 -38
  38. data.tar.gz.sig +0 -0
  39. metadata +998 -978
  40. metadata.gz.sig +0 -0
@@ -305,7 +305,8 @@ describe Mongo::Index::View do
305
305
  { key: { testing: -1 }, unique: true },
306
306
  { commit_quorum: 'unsupported-value' }
307
307
  )
308
- end.to raise_error(Mongo::Error::OperationFailure, /Commit quorum cannot be satisfied with the current replica set configuration/)
308
+ # 4.4.4 changed the text of the error message
309
+ end.to raise_error(Mongo::Error::OperationFailure, /Commit quorum cannot be satisfied with the current replica set configuration|No write concern mode named 'unsupported-value' found in replica set configuration/)
309
310
  end
310
311
  end
311
312
  end
@@ -964,7 +965,8 @@ describe Mongo::Index::View do
964
965
  it 'raises an exception' do
965
966
  expect do
966
967
  view.create_one({ 'x' => 1 }, commit_quorum: 'unsupported-value')
967
- end.to raise_error(Mongo::Error::OperationFailure, /Commit quorum cannot be satisfied with the current replica set configuration/)
968
+ # 4.4.4 changed the text of the error message
969
+ end.to raise_error(Mongo::Error::OperationFailure, /Commit quorum cannot be satisfied with the current replica set configuration|No write concern mode named 'unsupported-value' found in replica set configuration/)
968
970
  end
969
971
  end
970
972
  end
@@ -46,10 +46,10 @@ describe Mongo::Operation::ReadPreferenceSupported do
46
46
  end
47
47
  end
48
48
 
49
- describe '#add_slave_ok_flag_maybe' do
49
+ describe '#add_slave_ok_flag?' do
50
50
 
51
51
  let(:actual) do
52
- operation.send(:add_slave_ok_flag_maybe, operation.send(:options), connection)
52
+ operation.send(:add_slave_ok_flag?, connection)
53
53
  end
54
54
 
55
55
  shared_examples_for 'sets the slave_ok flag as expected' do
@@ -60,9 +60,7 @@ describe Mongo::Operation::ReadPreferenceSupported do
60
60
 
61
61
  shared_examples_for 'never sets slave_ok' do
62
62
 
63
- let(:expected) do
64
- { }
65
- end
63
+ let(:expected) { false }
66
64
 
67
65
  context 'when no read preference is specified' do
68
66
  let(:read_pref) { Mongo::ServerSelector.get }
@@ -85,9 +83,7 @@ describe Mongo::Operation::ReadPreferenceSupported do
85
83
 
86
84
  shared_examples_for 'always sets slave_ok' do
87
85
 
88
- let(:expected) do
89
- { :flags => [ :slave_ok ] }
90
- end
86
+ let(:expected) { true }
91
87
 
92
88
  context 'when no read preference is specified' do
93
89
  let(:read_pref) { Mongo::ServerSelector.get }
@@ -114,9 +110,7 @@ describe Mongo::Operation::ReadPreferenceSupported do
114
110
 
115
111
  let(:read_pref) { Mongo::ServerSelector.get }
116
112
 
117
- let(:expected) do
118
- { }
119
- end
113
+ let(:expected) { false }
120
114
 
121
115
  it_behaves_like 'sets the slave_ok flag as expected'
122
116
  end
@@ -127,9 +121,7 @@ describe Mongo::Operation::ReadPreferenceSupported do
127
121
 
128
122
  let(:read_pref) { Mongo::ServerSelector.get(:mode => :secondary) }
129
123
 
130
- let(:expected) do
131
- { :flags => [ :slave_ok ] }
132
- end
124
+ let(:expected) { true }
133
125
 
134
126
  it_behaves_like 'sets the slave_ok flag as expected'
135
127
  end
@@ -138,9 +130,7 @@ describe Mongo::Operation::ReadPreferenceSupported do
138
130
 
139
131
  let(:read_pref) { Mongo::ServerSelector.get(:mode => :primary) }
140
132
 
141
- let(:expected) do
142
- { }
143
- end
133
+ let(:expected) { false }
144
134
 
145
135
  it_behaves_like 'sets the slave_ok flag as expected'
146
136
  end
@@ -206,7 +196,7 @@ describe Mongo::Operation::ReadPreferenceSupported do
206
196
  end
207
197
  end
208
198
 
209
- describe '#update_selector_for_read_pref' do
199
+ describe '#add_read_preference_legacy' do
210
200
 
211
201
  let(:read_pref) do
212
202
  Mongo::ServerSelector.get(:mode => mode)
@@ -215,7 +205,7 @@ describe Mongo::Operation::ReadPreferenceSupported do
215
205
  # Behavior of sending $readPreference is the same regardless of topology.
216
206
  shared_examples_for '$readPreference in the command' do
217
207
  let(:actual) do
218
- operation.send(:update_selector_for_read_pref, operation.send(:selector), connection)
208
+ operation.send(:add_read_preference_legacy, operation.send(:selector), connection)
219
209
  end
220
210
 
221
211
  let(:expected_read_preference) do
@@ -175,13 +175,13 @@ describe Mongo::Operation::SessionsSupported do
175
175
  let(:tag_sets) { nil }
176
176
 
177
177
  context 'without tag_sets specified' do
178
- it_behaves_like 'does not modify selector'
178
+ it_behaves_like 'adds read preference'
179
179
  end
180
180
 
181
181
  context 'with empty tag_sets' do
182
182
  let(:tag_sets) { [] }
183
183
 
184
- it_behaves_like 'does not modify selector'
184
+ it_behaves_like 'adds read preference'
185
185
  end
186
186
 
187
187
  context 'with tag_sets specified' do
@@ -256,7 +256,7 @@ describe Mongo::Operation::SessionsSupported do
256
256
  let(:hedge) { nil }
257
257
 
258
258
  context 'when tag_sets and hedge are not specified' do
259
- it_behaves_like 'does not modify selector'
259
+ it_behaves_like 'adds read preference'
260
260
  end
261
261
 
262
262
  context 'when tag_sets are specified' do
@@ -8,14 +8,40 @@ shared_examples 'app metadata document' do
8
8
  document[:client][:driver][:version].should == Mongo::VERSION
9
9
  end
10
10
 
11
- it 'includes operating system information' do
12
- document[:client][:os][:type].should == 'linux'
13
- if BSON::Environment.jruby? || RUBY_VERSION >= '3.0'
14
- document[:client][:os][:name].should == 'linux'
15
- else
16
- document[:client][:os][:name].should == 'linux-gnu'
11
+ context 'linux' do
12
+ before(:all) do
13
+ unless SpecConfig.instance.linux?
14
+ skip "Linux required, we have #{RbConfig::CONFIG['host_os']}"
15
+ end
16
+ end
17
+
18
+ it 'includes operating system information' do
19
+ document[:client][:os][:type].should == 'linux'
20
+ if BSON::Environment.jruby? || RUBY_VERSION >= '3.0'
21
+ document[:client][:os][:name].should == 'linux'
22
+ else
23
+ document[:client][:os][:name].should == 'linux-gnu'
24
+ end
25
+ document[:client][:os][:architecture].should == 'x86_64'
26
+ end
27
+ end
28
+
29
+ context 'macos' do
30
+ before(:all) do
31
+ unless SpecConfig.instance.macos?
32
+ skip "MacOS required, we have #{RbConfig::CONFIG['host_os']}"
33
+ end
34
+ end
35
+
36
+ it 'includes operating system information' do
37
+ document[:client][:os][:type].should == 'darwin'
38
+ if BSON::Environment.jruby?
39
+ document[:client][:os][:name].should == 'darwin'
40
+ else
41
+ document[:client][:os][:name].should =~ /darwin\d+/
42
+ end
43
+ document[:client][:os][:architecture].should == 'x86_64'
17
44
  end
18
- document[:client][:os][:architecture].should == 'x86_64'
19
45
  end
20
46
 
21
47
  context 'mri' do
@@ -78,8 +78,8 @@ describe Mongo::ServerSelector::SecondaryPreferred do
78
78
 
79
79
  context 'tag sets not provided' do
80
80
 
81
- it 'returns nil' do
82
- expect(selector.to_mongos).to be_nil
81
+ it 'returns secondaryPreferred' do
82
+ selector.to_mongos.should == {mode: 'secondaryPreferred'}
83
83
  end
84
84
  end
85
85
 
@@ -89,8 +89,8 @@ describe Mongo::ServerSelector::SecondaryPreferred do
89
89
  { :mode => 'secondaryPreferred' }
90
90
  end
91
91
 
92
- it 'returns nil' do
93
- expect(selector.to_mongos).to be_nil
92
+ it 'returns secondaryPreferred' do
93
+ selector.to_mongos.should == {mode: 'secondaryPreferred'}
94
94
  end
95
95
  end
96
96
 
@@ -120,8 +120,8 @@ describe Mongo::ServerSelector::SecondaryPreferred do
120
120
  context 'hedge not provided' do
121
121
  let(:hedge) { nil }
122
122
 
123
- it 'returns nil' do
124
- expect(selector.to_mongos).to be_nil
123
+ it 'returns secondaryPreferred' do
124
+ selector.to_mongos.should == {mode: 'secondaryPreferred'}
125
125
  end
126
126
  end
127
127
 
@@ -191,8 +191,19 @@ module Mongo
191
191
 
192
192
  def assert_event_count(client, context)
193
193
  events = _select_events(context)
194
- unless events.length == arguments['count']
195
- raise "Exppected #{arguments['count']} #{arguments['event']} events, but have #{events.length}"
194
+ if arguments['event'] == 'ServerMarkedUnknownEvent'
195
+ # We publish SDAM events from both regular and push monitors.
196
+ # This means sometimes there are two ServerMarkedUnknownEvent
197
+ # events published for the same server transition.
198
+ # Allow actual event count to be at least the expected event count
199
+ # in case there are multiple transitions in a single test.
200
+ unless events.length >= arguments['count']
201
+ raise "Expected #{arguments['count']} #{arguments['event']} events, but have #{events.length}"
202
+ end
203
+ else
204
+ unless events.length == arguments['count']
205
+ raise "Expected #{arguments['count']} #{arguments['event']} events, but have #{events.length}"
206
+ end
196
207
  end
197
208
  end
198
209
 
@@ -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,221 @@
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 replica_set_name
19
+ determine_cluster_config
20
+ @replica_set_name
21
+ end
22
+
23
+ def server_version
24
+ determine_cluster_config
25
+ @server_version
26
+ end
27
+
28
+ def enterprise?
29
+ determine_cluster_config
30
+ @enterprise
31
+ end
32
+
33
+ def short_server_version
34
+ server_version.split('.')[0..1].join('.')
35
+ end
36
+
37
+ def fcv
38
+ determine_cluster_config
39
+ @fcv
40
+ end
41
+
42
+ # Per https://jira.mongodb.org/browse/SERVER-39052, working with FCV
43
+ # in sharded topologies is annoying. Also, FCV doesn't exist in servers
44
+ # less than 3.4. This method returns FCV on 3.4+ servers when in single
45
+ # or RS topologies, and otherwise returns the major.minor server version.
46
+ def fcv_ish
47
+ if server_version.nil?
48
+ raise "Deployment server version not known - check that connection to deployment succeeded"
49
+ end
50
+
51
+ if server_version >= '3.4' && topology != :sharded
52
+ fcv
53
+ else
54
+ if short_server_version == '4.1'
55
+ '4.2'
56
+ else
57
+ short_server_version
58
+ end
59
+ end
60
+ end
61
+
62
+ # @return [ Mongo::Address ] The address of the primary in the deployment.
63
+ def primary_address
64
+ determine_cluster_config
65
+ @primary_address
66
+ end
67
+
68
+ def primary_address_str
69
+ determine_cluster_config
70
+ @primary_address.seed
71
+ end
72
+
73
+ def primary_address_host
74
+ both = primary_address_str
75
+ both.split(':').first
76
+ end
77
+
78
+ def primary_address_port
79
+ both = primary_address_str
80
+ both.split(':')[1] || 27017
81
+ end
82
+
83
+ def primary_description
84
+ determine_cluster_config
85
+ @primary_description
86
+ end
87
+
88
+ def server_parameters
89
+ determine_cluster_config
90
+ @server_parameters
91
+ end
92
+
93
+ # Try running a command on the admin database to see if the mongod was
94
+ # started with auth.
95
+ def auth_enabled?
96
+ if @auth_enabled.nil?
97
+ @auth_enabled = begin
98
+ basic_client.use(:admin).command(getCmdLineOpts: 1).first["argv"].include?("--auth")
99
+ rescue => e
100
+ e.message =~ /(not authorized)|(unauthorized)|(no users authenticated)|(requires authentication)/
101
+ end
102
+ end
103
+ @auth_enabled
104
+ end
105
+
106
+ def topology
107
+ determine_cluster_config
108
+ @topology
109
+ end
110
+
111
+ def storage_engine
112
+ @storage_engine ||= begin
113
+ # 2.6 does not have wired tiger
114
+ if short_server_version == '2.6'
115
+ :mmapv1
116
+ else
117
+ client = ClientRegistry.instance.global_client('root_authorized')
118
+ if topology == :sharded
119
+ shards = client.use(:admin).command(listShards: 1).first
120
+ if shards['shards'].empty?
121
+ raise 'Shards are empty'
122
+ end
123
+ shard = shards['shards'].first
124
+ address_str = shard['host'].sub(/^.*\//, '').sub(/,.*/, '')
125
+ client = ClusterTools.instance.direct_client(address_str,
126
+ SpecConfig.instance.test_options.merge(SpecConfig.instance.auth_options).merge(connect: :direct))
127
+ end
128
+ rv = client.use(:admin).command(serverStatus: 1).first
129
+ rv = rv['storageEngine']['name']
130
+ rv_map = {
131
+ 'wiredTiger' => :wired_tiger,
132
+ 'mmapv1' => :mmapv1,
133
+ }
134
+ rv_map[rv] || rv
135
+ end
136
+ end
137
+ end
138
+
139
+ # This method returns an alternate address for connecting to the configured
140
+ # deployment. For example, if the replica set is configured with nodes at
141
+ # of localhost:27017 and so on, this method will return 127.0.0.:27017.
142
+ #
143
+ # Note that the "alternate" refers to replica set configuration, not the
144
+ # addresses specified in test suite configuration. If the deployment topology
145
+ # is not a replica set, "alternate" refers to test suite configuration as
146
+ # this is the only configuration available.
147
+ def alternate_address
148
+ @alternate_address ||= begin
149
+ address = primary_address_host
150
+ str = case address
151
+ when '127.0.0.1'
152
+ 'localhost'
153
+ when /^(\d+\.){3}\d+$/
154
+ skip 'This test requires a hostname or 127.0.0.1 as address'
155
+ else
156
+ # We don't know if mongod is listening on ipv4 or ipv6, in principle.
157
+ # Our tests use ipv4, so hardcode that for now.
158
+ # To support both we need to try both addresses which will make this
159
+ # test more complicated.
160
+ #
161
+ # JRuby chokes on primary_address_port as the port (e.g. 27017).
162
+ # Since the port does not actually matter, use a common port like 80.
163
+ resolved_address = Addrinfo.getaddrinfo(address, 80, Socket::PF_INET).first.ip_address
164
+ if resolved_address.include?(':')
165
+ "[#{resolved_address}]"
166
+ else
167
+ resolved_address
168
+ end
169
+ end + ":#{primary_address_port}"
170
+ Mongo::Address.new(str)
171
+ end
172
+ end
173
+
174
+ private
175
+
176
+ def determine_cluster_config
177
+ return if @primary_address
178
+
179
+ # Run all commands to figure out the cluster configuration from the same
180
+ # client. This is somewhat wasteful when running a single test, but reduces
181
+ # test runtime for the suite overall because all commands are sent on the
182
+ # same connection rather than each command connecting to the cluster by
183
+ # itself.
184
+ client = ClientRegistry.instance.global_client('root_authorized')
185
+
186
+ primary = client.cluster.next_primary
187
+ @primary_address = primary.address
188
+ @primary_description = primary.description
189
+ @replica_set_name = client.cluster.topology.replica_set_name
190
+
191
+ @topology ||= begin
192
+ topology = client.cluster.topology.class.name.sub(/.*::/, '')
193
+ topology = topology.gsub(/([A-Z])/) { |match| '_' + match.downcase }.sub(/^_/, '')
194
+ if topology =~ /^replica_set/
195
+ topology = 'replica_set'
196
+ end
197
+ topology.to_sym
198
+ end
199
+
200
+ @single_server = client.cluster.servers_list.length == 1
201
+
202
+ build_info = client.database.command(buildInfo: 1).first
203
+
204
+ @server_version = build_info['version']
205
+ @enterprise = build_info['modules'] && build_info['modules'].include?('enterprise')
206
+
207
+ @server_parameters = client.use(:admin).command(getParameter: '*').first
208
+
209
+ if @topology != :sharded && short_server_version >= '3.4'
210
+ rv = @server_parameters['featureCompatibilityVersion']
211
+ @fcv = rv['version'] || rv
212
+ end
213
+ end
214
+
215
+ def basic_client
216
+ # Do not cache the result here so that if the client gets closed,
217
+ # client registry reconnects it in subsequent tests
218
+ ClientRegistry.instance.global_client('basic')
219
+ end
220
+ end
221
+ end