mongo 2.13.2 → 2.13.3

Sign up to get free protection for your applications and to get access to all the features.
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