mongo 2.13.0.rc1 → 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 (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