mongo 2.13.0.rc1 → 2.13.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/lib/mongo/address.rb +1 -1
  4. data/lib/mongo/auth/aws/request.rb +27 -3
  5. data/lib/mongo/client.rb +48 -2
  6. data/lib/mongo/collection.rb +21 -12
  7. data/lib/mongo/database/view.rb +1 -1
  8. data/lib/mongo/database.rb +14 -2
  9. data/lib/mongo/error/invalid_server_auth_host.rb +22 -0
  10. data/lib/mongo/error/operation_failure.rb +5 -5
  11. data/lib/mongo/error.rb +2 -0
  12. data/lib/mongo/grid/fs_bucket.rb +37 -37
  13. data/lib/mongo/index/view.rb +3 -0
  14. data/lib/mongo/operation/collections_info/command.rb +5 -0
  15. data/lib/mongo/operation/collections_info/result.rb +16 -1
  16. data/lib/mongo/operation/parallel_scan/command.rb +1 -2
  17. data/lib/mongo/operation/shared/read_preference_supported.rb +38 -36
  18. data/lib/mongo/operation/shared/sessions_supported.rb +3 -2
  19. data/lib/mongo/protocol/message.rb +11 -2
  20. data/lib/mongo/protocol/msg.rb +22 -3
  21. data/lib/mongo/protocol/query.rb +47 -11
  22. data/lib/mongo/server/app_metadata.rb +27 -3
  23. data/lib/mongo/server/connection_base.rb +35 -11
  24. data/lib/mongo/server_selector/secondary_preferred.rb +2 -7
  25. data/lib/mongo/version.rb +1 -1
  26. data/spec/integration/bson_symbol_spec.rb +4 -2
  27. data/spec/integration/bulk_write_spec.rb +19 -0
  28. data/spec/integration/client_authentication_options_spec.rb +37 -0
  29. data/spec/integration/client_side_encryption/auto_encryption_bulk_writes_spec.rb +9 -5
  30. data/spec/integration/sdam_error_handling_spec.rb +18 -1
  31. data/spec/integration/sdam_events_spec.rb +8 -7
  32. data/spec/integration/secondary_reads_spec.rb +102 -0
  33. data/spec/integration/size_limit_spec.rb +20 -6
  34. data/spec/lite_spec_helper.rb +1 -1
  35. data/spec/mongo/auth/aws/request_region_spec.rb +42 -0
  36. data/spec/mongo/auth/aws/request_spec.rb +32 -32
  37. data/spec/mongo/client_construction_spec.rb +123 -0
  38. data/spec/mongo/client_encryption_spec.rb +16 -10
  39. data/spec/mongo/crypt/data_key_context_spec.rb +1 -1
  40. data/spec/mongo/database_spec.rb +64 -0
  41. data/spec/mongo/index/view_spec.rb +150 -2
  42. data/spec/mongo/operation/read_preference_legacy_spec.rb +9 -19
  43. data/spec/mongo/operation/read_preference_op_msg_spec.rb +3 -3
  44. data/spec/mongo/server/app_metadata_shared.rb +114 -8
  45. data/spec/mongo/server_selector/secondary_preferred_spec.rb +6 -6
  46. data/spec/runners/transactions/operation.rb +13 -2
  47. data/spec/shared/LICENSE +20 -0
  48. data/spec/shared/bin/get-mongodb-download-url +17 -0
  49. data/spec/shared/lib/mrss/child_process_helper.rb +80 -0
  50. data/spec/shared/lib/mrss/cluster_config.rb +221 -0
  51. data/spec/shared/lib/mrss/constraints.rb +346 -0
  52. data/spec/shared/lib/mrss/docker_runner.rb +265 -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 +152 -0
  56. data/spec/shared/lib/mrss/utils.rb +15 -0
  57. data/spec/shared/share/Dockerfile.erb +231 -0
  58. data/spec/shared/shlib/distro.sh +73 -0
  59. data/spec/shared/shlib/server.sh +290 -0
  60. data/spec/shared/shlib/set_env.sh +128 -0
  61. data/spec/support/client_registry.rb +8 -4
  62. data/spec/support/client_registry_macros.rb +14 -5
  63. data/spec/support/spec_config.rb +12 -0
  64. data/spec/support/spec_setup.rb +48 -38
  65. data.tar.gz.sig +3 -1
  66. metadata +1005 -974
  67. metadata.gz.sig +0 -0
  68. data/spec/integration/size_limit_spec.rb~12e1e9c4f... RUBY-2242 Fix zlib compression (#2021) +0 -98
@@ -256,6 +256,43 @@ describe 'Client authentication options' do
256
256
  expect(client.options[:auth_mech_properties]).to eq({ 'service_name' => 'mongodb' })
257
257
  end
258
258
  end
259
+
260
+ context 'when properties are given but not service name' do
261
+ context 'with URI options' do
262
+ let(:credentials) { "#{user}:#{pwd}@" }
263
+
264
+ context 'with default auth mech properties' do
265
+ let(:options) { '?authMechanism=GSSAPI&authMechanismProperties=service_realm:foo' }
266
+
267
+ it 'sets service name to mongodb' do
268
+ expect(client.options[:auth_mech_properties]).to eq(
269
+ 'service_name' => 'mongodb',
270
+ 'service_realm' => 'foo',
271
+ )
272
+ end
273
+ end
274
+ end
275
+
276
+ context 'with client options' do
277
+ let(:client_opts) do
278
+ {
279
+ auth_mech: :gssapi,
280
+ user: user,
281
+ password: pwd,
282
+ auth_mech_properties: {
283
+ service_realm: 'foo',
284
+ }.freeze,
285
+ }.freeze
286
+ end
287
+
288
+ it 'sets default auth mech properties' do
289
+ expect(client.options[:auth_mech_properties]).to eq(
290
+ 'service_name' => 'mongodb',
291
+ 'service_realm' => 'foo',
292
+ )
293
+ end
294
+ end
295
+ end
259
296
  end
260
297
 
261
298
  context 'with PLAIN auth mechanism' do
@@ -113,7 +113,7 @@ describe 'Bulk writes with auto-encryption enabled' do
113
113
  it 'raises an exception' do
114
114
  expect do
115
115
  bulk_write.execute
116
- end.to raise_error(Mongo::Error::MaxBSONSize, /maximum allowed size: 16777216 bytes/)
116
+ end.to raise_error(Mongo::Error::MaxBSONSize, /The document exceeds maximum allowed BSON object size after serialization/)
117
117
  end
118
118
  end
119
119
  end
@@ -162,15 +162,19 @@ describe 'Bulk writes with auto-encryption enabled' do
162
162
  context 'when one operation is larger than 16MiB' do
163
163
  let(:requests) do
164
164
  [
165
- { update_one: { filter: { _id: 1 }, update: { ssn: 'a' * (Mongo::Server::ConnectionBase::DEFAULT_MAX_BSON_OBJECT_SIZE - 100) } } },
165
+ { update_one: { filter: { _id: 1 }, update: { ssn: 'a' * (Mongo::Server::ConnectionBase::DEFAULT_MAX_BSON_OBJECT_SIZE) } } },
166
166
  { update_one: { filter: { _id: 2 }, update: { ssn: 'a' * size_limit } } },
167
167
  ]
168
168
  end
169
169
 
170
+ before do
171
+ expect(requests.first.to_bson.length).to be > Mongo::Server::ConnectionBase::DEFAULT_MAX_BSON_OBJECT_SIZE
172
+ end
173
+
170
174
  it 'raises an exception' do
171
175
  expect do
172
176
  bulk_write.execute
173
- end.to raise_error(Mongo::Error::MaxBSONSize, /maximum allowed size: 16777216 bytes/)
177
+ end.to raise_error(Mongo::Error::MaxBSONSize, /The document exceeds maximum allowed BSON object size after serialization/)
174
178
  end
175
179
  end
176
180
  end
@@ -255,7 +259,7 @@ describe 'Bulk writes with auto-encryption enabled' do
255
259
  it 'raises an exception' do
256
260
  expect do
257
261
  bulk_write.execute
258
- end.to raise_error(Mongo::Error::MaxBSONSize, /maximum allowed size: 16777216 bytes/)
262
+ end.to raise_error(Mongo::Error::MaxBSONSize, /The document exceeds maximum allowed BSON object size after serialization/)
259
263
  end
260
264
  end
261
265
  end
@@ -346,7 +350,7 @@ describe 'Bulk writes with auto-encryption enabled' do
346
350
  it 'raises an exception' do
347
351
  expect do
348
352
  perform_bulk_write
349
- end.to raise_error(Mongo::Error::MaxBSONSize, /maximum allowed size: 16777216 bytes/)
353
+ end.to raise_error(Mongo::Error::MaxBSONSize, /The document exceeds maximum allowed BSON object size after serialization/)
350
354
  end
351
355
  end
352
356
  end
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe 'SDAM error handling' do
4
- clean_slate_for_all
4
+ clean_slate
5
5
 
6
6
  after do
7
7
  # Close all clients after every test to avoid leaking expectations into
@@ -19,6 +19,7 @@ describe 'SDAM error handling' do
19
19
  new_local_client(SpecConfig.instance.addresses,
20
20
  SpecConfig.instance.all_test_options.merge(
21
21
  socket_timeout: 3, connect_timeout: 3,
22
+ heartbeat_frequency: 100,
22
23
  # Uncomment to print all events to stdout:
23
24
  #sdam_proc: Utils.subscribe_all_sdam_proc(diagnostic_subscriber),
24
25
  **Utils.disable_retries_client_options)
@@ -28,6 +29,14 @@ describe 'SDAM error handling' do
28
29
  let(:server) { client.cluster.next_primary }
29
30
 
30
31
  shared_examples_for 'marks server unknown' do
32
+ before do
33
+ server.monitor.stop!
34
+ end
35
+
36
+ after do
37
+ client.close
38
+ end
39
+
31
40
  it 'marks server unknown' do
32
41
  expect(server).not_to be_unknown
33
42
  RSpec::Mocks.with_temporary_scope do
@@ -38,6 +47,14 @@ describe 'SDAM error handling' do
38
47
  end
39
48
 
40
49
  shared_examples_for 'does not mark server unknown' do
50
+ before do
51
+ server.monitor.stop!
52
+ end
53
+
54
+ after do
55
+ client.close
56
+ end
57
+
41
58
  it 'does not mark server unknown' do
42
59
  expect(server).not_to be_unknown
43
60
  RSpec::Mocks.with_temporary_scope do
@@ -67,9 +67,8 @@ describe 'SDAM events' do
67
67
  started_events.length.should <= 10
68
68
 
69
69
  succeeded_events = subscriber.select_succeeded_events(Mongo::Monitoring::Event::ServerHeartbeatSucceeded)
70
- # Since we gracefully close the client, we expect each heartbeat
71
- # to complete.
72
- started_events.length.should == succeeded_events.length
70
+ started_events.length.should > 1
71
+ (succeeded_events.length..succeeded_events.length+1).should include(started_events.length)
73
72
  end
74
73
  end
75
74
 
@@ -105,10 +104,12 @@ describe 'SDAM events' do
105
104
  (succeeded_awaited = events.select(&:awaited?)).should_not be_empty
106
105
  (succeeded_regular = events.reject(&:awaited?)).should_not be_empty
107
106
 
108
- # Since we gracefully close the client, we expect each heartbeat
109
- # to complete.
110
- started_awaited.length.should == succeeded_awaited.length
111
- started_regular.length.should == succeeded_regular.length
107
+ # There may be in-flight ismasters that don't complete, both
108
+ # regular and awaited.
109
+ started_awaited.length.should > 1
110
+ (succeeded_awaited.length..succeeded_awaited.length+1).should include(started_awaited.length)
111
+ started_regular.length.should > 1
112
+ (succeeded_regular.length..succeeded_regular.length+1).should include(started_regular.length)
112
113
  end
113
114
  end
114
115
  end
@@ -0,0 +1,102 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Secondary reads' do
4
+ before do
5
+ root_authorized_client.use('sr')['secondary_reads'].drop
6
+ root_authorized_client.use('sr')['secondary_reads'].insert_one(test: 1)
7
+ end
8
+
9
+ shared_examples 'performs reads as per read preference' do
10
+
11
+ %i(primary primary_preferred).each do |mode|
12
+
13
+ context mode.inspect do
14
+
15
+ let(:client) do
16
+ root_authorized_client.with(read: {mode: mode}).use('sr')
17
+ end
18
+
19
+ it 'reads from primary' do
20
+ start_stats = get_read_counters
21
+
22
+ 30.times do
23
+ client['secondary_reads'].find.to_a
24
+ end
25
+
26
+ end_stats = get_read_counters
27
+
28
+ end_stats[:secondary].should be_within(10).of(start_stats[:secondary])
29
+ end_stats[:primary].should >= start_stats[:primary] + 30
30
+ end
31
+ end
32
+ end
33
+
34
+ %i(secondary secondary_preferred).each do |mode|
35
+
36
+ context mode.inspect do
37
+ let(:client) do
38
+ root_authorized_client.with(read: {mode: mode}).use('sr')
39
+ end
40
+
41
+ it 'reads from secondaries' do
42
+ start_stats = get_read_counters
43
+
44
+ 30.times do
45
+ client['secondary_reads'].find.to_a
46
+ end
47
+
48
+ end_stats = get_read_counters
49
+
50
+ end_stats[:primary].should be_within(10).of(start_stats[:primary])
51
+ end_stats[:secondary].should >= start_stats[:secondary] + 30
52
+ end
53
+ end
54
+ end
55
+ end
56
+
57
+ context 'replica set' do
58
+ require_topology :replica_set
59
+
60
+ include_examples 'performs reads as per read preference'
61
+ end
62
+
63
+ context 'sharded cluster' do
64
+ require_topology :sharded
65
+
66
+ include_examples 'performs reads as per read preference'
67
+ end
68
+
69
+ def get_read_counters
70
+ client = ClientRegistry.instance.global_client('root_authorized')
71
+ addresses = []
72
+ if client.cluster.sharded?
73
+ doc = client.use('admin').command(listShards: 1).documents.first
74
+ doc['shards'].each do |shard|
75
+ addresses += shard['host'].split('/').last.split(',')
76
+ end
77
+ else
78
+ client.cluster.servers.each do |server|
79
+ next unless server.primary? || server.secondary?
80
+ addresses << server.address.seed
81
+ end
82
+ end
83
+ stats = Hash.new(0)
84
+ addresses.each do |address|
85
+ ClientRegistry.instance.new_local_client(
86
+ [address],
87
+ SpecConfig.instance.all_test_options.merge(connect: :direct),
88
+ ) do |c|
89
+ server = c.cluster.servers.first
90
+ next unless server.primary? || server.secondary?
91
+ stat = c.command(serverStatus: 1).documents.first
92
+ queries = stat['opcounters']['query']
93
+ if server.primary?
94
+ stats[:primary] += queries
95
+ else
96
+ stats[:secondary] += queries
97
+ end
98
+ end
99
+ end
100
+ stats
101
+ end
102
+ end
@@ -62,13 +62,31 @@ describe 'BSON & command size limits' do
62
62
  authorized_collection.insert_one(document)
63
63
  end
64
64
 
65
- it 'fails on the server when a document larger than 16MiB is inserted' do
65
+ it 'fails on the driver when a document larger than 16MiB is inserted' do
66
66
  document = { key: 'a' * (max_document_size - 27), _id: 'foo' }
67
67
  expect(document.to_bson.length).to eq(max_document_size+1)
68
68
 
69
69
  lambda do
70
70
  authorized_collection.insert_one(document)
71
- end.should raise_error(Mongo::Error::OperationFailure, /object to insert too large/)
71
+ end.should raise_error(Mongo::Error::MaxBSONSize, /The document exceeds maximum allowed BSON object size after serialization/)
72
+ end
73
+
74
+ it 'fails on the driver when an update larger than 16MiB is performed' do
75
+ document = { key: 'a' * (max_document_size - 14) }
76
+ expect(document.to_bson.length).to eq(max_document_size+1)
77
+
78
+ lambda do
79
+ authorized_collection.update_one({ _id: 'foo' }, document)
80
+ end.should raise_error(Mongo::Error::MaxBSONSize, /The document exceeds maximum allowed BSON object size after serialization/)
81
+ end
82
+
83
+ it 'fails on the driver when an delete larger than 16MiB is performed' do
84
+ document = { key: 'a' * (max_document_size - 14) }
85
+ expect(document.to_bson.length).to eq(max_document_size+1)
86
+
87
+ lambda do
88
+ authorized_collection.delete_one(document)
89
+ end.should raise_error(Mongo::Error::MaxBSONSize, /The document exceeds maximum allowed BSON object size after serialization/)
72
90
  end
73
91
 
74
92
  it 'fails in the driver when a document larger than 16MiB+16KiB is inserted' do
@@ -81,10 +99,6 @@ describe 'BSON & command size limits' do
81
99
  end
82
100
 
83
101
  it 'allows bulk writes of multiple documents of exactly 16 MiB each' do
84
- if SpecConfig.instance.compressors
85
- pending "RUBY-2234"
86
- end
87
-
88
102
  documents = []
89
103
  1.upto(3) do |index|
90
104
  document = { key: 'a' * (max_document_size - 28), _id: "in#{index}" }
@@ -104,7 +104,7 @@ RSpec.configure do |config|
104
104
  end
105
105
  end
106
106
 
107
- if SpecConfig.instance.ci?
107
+ if SpecConfig.instance.ci? && !%w(1 true yes).include?(ENV['INTERACTIVE']&.downcase)
108
108
  # Allow a max of 30 seconds per test.
109
109
  # Tests should take under 10 seconds ideally but it seems
110
110
  # we have some that run for more than 10 seconds in CI.
@@ -0,0 +1,42 @@
1
+ require 'lite_spec_helper'
2
+
3
+ AWS_REGION_TEST_CASES = {
4
+ 'sts.amazonaws.com' => 'us-east-1',
5
+ 'sts.us-west-2.amazonaws.com' => 'us-west-2',
6
+ 'sts.us-west-2.amazonaws.com.ch' => 'us-west-2',
7
+ 'example.com' => 'com',
8
+ 'localhost' => 'us-east-1',
9
+ 'sts..com' => Mongo::Error::InvalidServerAuthHost,
10
+ '.amazonaws.com' => Mongo::Error::InvalidServerAuthHost,
11
+ 'sts.amazonaws.' => Mongo::Error::InvalidServerAuthHost,
12
+ '' => Mongo::Error::InvalidServerAuthResponse,
13
+ 'x' * 256 => Mongo::Error::InvalidServerAuthHost,
14
+ }
15
+
16
+ describe 'AWS auth region tests' do
17
+
18
+ AWS_REGION_TEST_CASES.each do |host, expected_region|
19
+ context "host '#{host}'" do
20
+ let(:request) do
21
+ Mongo::Auth::Aws::Request.new(access_key_id: 'access_key_id',
22
+ secret_access_key: 'secret_access_key',
23
+ session_token: 'session_token',
24
+ host: host,
25
+ server_nonce: 'server_nonce',
26
+ )
27
+ end
28
+
29
+ if expected_region.is_a?(String)
30
+ it 'derives expected region' do
31
+ request.region.should == expected_region
32
+ end
33
+ else
34
+ it 'fails with an error' do
35
+ lambda do
36
+ request.region
37
+ end.should raise_error(expected_region)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -1,15 +1,15 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Mongo::Auth::Aws::Request do
3
+ describe Mongo::Auth::Aws::Request do
4
4
 
5
- describe "#formatted_time" do
6
- context "when time is provided and frozen" do
5
+ describe "#formatted_time" do
6
+ context "when time is provided and frozen" do
7
7
  let(:original_time) { Time.at(1592399523).freeze }
8
- let(:request) do
9
- described_class.new(access_key_id: 'access_key_id',
10
- secret_access_key: 'secret_access_key',
11
- session_token: 'session_token',
12
- host: 'host',
8
+ let(:request) do
9
+ described_class.new(access_key_id: 'access_key_id',
10
+ secret_access_key: 'secret_access_key',
11
+ session_token: 'session_token',
12
+ host: 'host',
13
13
  server_nonce: 'server_nonce',
14
14
  time: original_time
15
15
  )
@@ -24,12 +24,12 @@ describe Mongo::Auth::Aws::Request do
24
24
  end
25
25
  end
26
26
 
27
- context "when time is not provided" do
28
- let(:request) do
29
- described_class.new(access_key_id: 'access_key_id',
30
- secret_access_key: 'secret_access_key',
31
- session_token: 'session_token',
32
- host: 'host',
27
+ context "when time is not provided" do
28
+ let(:request) do
29
+ described_class.new(access_key_id: 'access_key_id',
30
+ secret_access_key: 'secret_access_key',
31
+ session_token: 'session_token',
32
+ host: 'host',
33
33
  server_nonce: 'server_nonce'
34
34
  )
35
35
  end
@@ -40,37 +40,37 @@ describe Mongo::Auth::Aws::Request do
40
40
  end
41
41
  end
42
42
 
43
- describe "#signature" do
44
- context "when time is provided and frozen" do
43
+ describe "#signature" do
44
+ context "when time is provided and frozen" do
45
45
  let(:original_time) { Time.at(1592399523).freeze }
46
- let(:request) do
47
- described_class.new(access_key_id: 'access_key_id',
48
- secret_access_key: 'secret_access_key',
49
- session_token: 'session_token',
50
- host: 'host',
46
+ let(:request) do
47
+ described_class.new(access_key_id: 'access_key_id',
48
+ secret_access_key: 'secret_access_key',
49
+ session_token: 'session_token',
50
+ host: 'host',
51
51
  server_nonce: 'server_nonce',
52
52
  time: original_time
53
53
  )
54
54
  end
55
-
56
- it 'doesn\'t raise error on signature' do
55
+
56
+ it 'doesn\'t raise error on signature' do
57
57
  expect { request.signature }.to_not raise_error
58
58
  end
59
59
  end
60
60
 
61
- context "when time is not provided" do
62
- let(:request) do
63
- described_class.new(access_key_id: 'access_key_id',
64
- secret_access_key: 'secret_access_key',
65
- session_token: 'session_token',
66
- host: 'host',
61
+ context "when time is not provided" do
62
+ let(:request) do
63
+ described_class.new(access_key_id: 'access_key_id',
64
+ secret_access_key: 'secret_access_key',
65
+ session_token: 'session_token',
66
+ host: 'host',
67
67
  server_nonce: 'server_nonce'
68
68
  )
69
69
  end
70
-
71
- it 'doesn\'t raise error on signature' do
70
+
71
+ it 'doesn\'t raise error on signature' do
72
72
  expect { request.signature }.to_not raise_error
73
73
  end
74
- end
74
+ end
75
75
  end
76
76
  end