mongo 2.11.0 → 2.11.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/Rakefile +24 -0
  5. data/lib/mongo/address.rb +53 -37
  6. data/lib/mongo/auth.rb +30 -10
  7. data/lib/mongo/auth/cr.rb +1 -0
  8. data/lib/mongo/auth/cr/conversation.rb +13 -13
  9. data/lib/mongo/auth/ldap.rb +2 -1
  10. data/lib/mongo/auth/ldap/conversation.rb +9 -12
  11. data/lib/mongo/auth/scram.rb +1 -0
  12. data/lib/mongo/auth/scram/conversation.rb +36 -27
  13. data/lib/mongo/auth/user.rb +7 -1
  14. data/lib/mongo/auth/x509.rb +2 -1
  15. data/lib/mongo/auth/x509/conversation.rb +9 -9
  16. data/lib/mongo/bulk_write/transformable.rb +3 -3
  17. data/lib/mongo/client.rb +17 -6
  18. data/lib/mongo/cluster.rb +67 -49
  19. data/lib/mongo/cluster/sdam_flow.rb +87 -3
  20. data/lib/mongo/collection/view/readable.rb +3 -1
  21. data/lib/mongo/collection/view/writable.rb +3 -3
  22. data/lib/mongo/cursor/builder/kill_cursors_command.rb +8 -1
  23. data/lib/mongo/cursor/builder/op_kill_cursors.rb +8 -1
  24. data/lib/mongo/database.rb +1 -1
  25. data/lib/mongo/grid/file.rb +5 -0
  26. data/lib/mongo/grid/file/chunk.rb +2 -0
  27. data/lib/mongo/grid/fs_bucket.rb +15 -13
  28. data/lib/mongo/grid/stream/write.rb +9 -3
  29. data/lib/mongo/protocol/serializers.rb +12 -2
  30. data/lib/mongo/retryable.rb +33 -8
  31. data/lib/mongo/server.rb +13 -6
  32. data/lib/mongo/server/connection.rb +15 -8
  33. data/lib/mongo/server/connection_base.rb +7 -4
  34. data/lib/mongo/server/description.rb +34 -21
  35. data/lib/mongo/server/monitor.rb +1 -1
  36. data/lib/mongo/server/monitor/connection.rb +2 -3
  37. data/lib/mongo/session.rb +10 -10
  38. data/lib/mongo/socket.rb +10 -1
  39. data/lib/mongo/uri.rb +1 -1
  40. data/lib/mongo/version.rb +1 -1
  41. data/mongo.gemspec +1 -1
  42. data/spec/README.md +13 -0
  43. data/spec/integration/auth_spec.rb +27 -8
  44. data/spec/integration/bson_symbol_spec.rb +34 -0
  45. data/spec/integration/client_construction_spec.rb +14 -0
  46. data/spec/integration/client_options_spec.rb +5 -5
  47. data/spec/integration/connection_spec.rb +57 -9
  48. data/spec/integration/crud_spec.rb +45 -0
  49. data/spec/integration/cursor_reaping_spec.rb +2 -1
  50. data/spec/integration/grid_fs_bucket_spec.rb +48 -0
  51. data/spec/integration/retryable_errors_spec.rb +204 -39
  52. data/spec/integration/retryable_writes_spec.rb +36 -36
  53. data/spec/integration/size_limit_spec.rb~12e1e9c4f... RUBY-2242 Fix zlib compression (#2021) +98 -0
  54. data/spec/lite_spec_helper.rb +1 -0
  55. data/spec/mongo/address_spec.rb +19 -13
  56. data/spec/mongo/auth/ldap/conversation_spec.rb +1 -1
  57. data/spec/mongo/auth/scram/conversation_spec.rb +25 -14
  58. data/spec/mongo/auth/user/view_spec.rb +36 -1
  59. data/spec/mongo/auth/user_spec.rb +12 -0
  60. data/spec/mongo/auth/x509/conversation_spec.rb +1 -1
  61. data/spec/mongo/bulk_write_spec.rb +2 -2
  62. data/spec/mongo/client_construction_spec.rb +1 -21
  63. data/spec/mongo/cluster_spec.rb +57 -0
  64. data/spec/mongo/collection/view/map_reduce_spec.rb +1 -1
  65. data/spec/mongo/collection_spec.rb +26 -2
  66. data/spec/mongo/cursor/builder/op_kill_cursors_spec.rb +56 -0
  67. data/spec/mongo/server/connection_spec.rb +76 -8
  68. data/spec/mongo/server/monitor/connection_spec.rb +14 -7
  69. data/spec/mongo/socket/ssl_spec.rb +132 -98
  70. data/spec/mongo/socket/tcp_spec.rb +1 -9
  71. data/spec/mongo/uri_spec.rb +1 -1
  72. data/spec/runners/sdam/verifier.rb +91 -0
  73. data/spec/spec_tests/data/sdam/rs/primary_address_change.yml +29 -0
  74. data/spec/spec_tests/data/sdam/rs/primary_mismatched_me.yml +27 -23
  75. data/spec/spec_tests/data/sdam/rs/primary_to_no_primary_mismatched_me.yml +56 -79
  76. data/spec/spec_tests/data/sdam/sharded/primary_address_change.yml +21 -0
  77. data/spec/spec_tests/data/sdam/sharded/primary_mismatched_me.yml +22 -0
  78. data/spec/spec_tests/data/sdam/single/primary_address_change.yml +24 -0
  79. data/spec/spec_tests/data/sdam/single/primary_mismatched_me.yml +25 -0
  80. data/spec/spec_tests/data/sdam_monitoring/replica_set_with_me_mismatch.yml +159 -0
  81. data/spec/spec_tests/data/sdam_monitoring/{replica_set_other_seed.yml → replica_set_with_primary_change.yml} +97 -101
  82. data/spec/spec_tests/data/sdam_monitoring/replica_set_with_primary_removal.yml +22 -18
  83. data/spec/spec_tests/data/sdam_monitoring/standalone_to_rs_with_me_mismatch.yml +90 -0
  84. data/spec/spec_tests/sdam_monitoring_spec.rb +9 -4
  85. data/spec/support/cluster_config.rb +36 -0
  86. data/spec/support/cluster_tools.rb +5 -3
  87. data/spec/support/command_monitoring.rb +1 -1
  88. data/spec/support/constraints.rb +18 -18
  89. data/spec/support/lite_constraints.rb +8 -0
  90. data/spec/support/sdam_monitoring.rb +0 -115
  91. data/spec/support/server_discovery_and_monitoring.rb +2 -0
  92. data/spec/support/spec_config.rb +1 -1
  93. data/spec/support/utils.rb +11 -1
  94. metadata +687 -659
  95. metadata.gz.sig +3 -2
@@ -2,8 +2,10 @@ require 'spec_helper'
2
2
 
3
3
  describe Mongo::Auth::User::View do
4
4
 
5
+ let(:database) { root_authorized_client.database }
6
+
5
7
  let(:view) do
6
- described_class.new(root_authorized_client.database)
8
+ described_class.new(database)
7
9
  end
8
10
 
9
11
  before do
@@ -51,6 +53,39 @@ describe Mongo::Auth::User::View do
51
53
 
52
54
  describe '#create' do
53
55
 
56
+ context 'when password is not provided' do
57
+
58
+ let(:database) { root_authorized_client.use('$external').database }
59
+
60
+ let(:username) { 'passwordless-user' }
61
+
62
+ let(:response) do
63
+ view.create(
64
+ username,
65
+ # https://stackoverflow.com/questions/55939832/mongodb-external-database-cannot-create-new-user-with-user-defined-role
66
+ roles: [{role: 'read', db: 'admin'}],
67
+ )
68
+ end
69
+
70
+ before do
71
+ begin
72
+ view.remove(username)
73
+ rescue Mongo::Error::OperationFailure
74
+ # can be user not found, ignore
75
+ end
76
+ end
77
+
78
+ it 'creates the user' do
79
+ view.info(username).should == []
80
+
81
+ lambda do
82
+ response
83
+ end.should_not raise_error
84
+
85
+ view.info(username).first['user'].should == username
86
+ end
87
+ end
88
+
54
89
  context 'when a session is not used' do
55
90
 
56
91
  let!(:response) do
@@ -325,4 +325,16 @@ describe Mongo::Auth::User do
325
325
  end
326
326
  end
327
327
  end
328
+
329
+ describe '#spec' do
330
+ context 'when no password and no roles are set' do
331
+ let(:user) do
332
+ described_class.new(user: 'foo')
333
+ end
334
+
335
+ it 'is a hash with empty roles' do
336
+ user.spec.should == {roles: []}
337
+ end
338
+ end
339
+ end
328
340
  end
@@ -16,7 +16,7 @@ describe Mongo::Auth::X509::Conversation do
16
16
  describe '#start' do
17
17
 
18
18
  let(:query) do
19
- conversation.start
19
+ conversation.start(nil)
20
20
  end
21
21
 
22
22
  let(:selector) do
@@ -1924,11 +1924,11 @@ describe Mongo::BulkWrite do
1924
1924
  end
1925
1925
 
1926
1926
  let(:first_txn_number) do
1927
- started_events[-2].command['txnNumber'].value
1927
+ Utils.int64_value(started_events[-2].command['txnNumber'])
1928
1928
  end
1929
1929
 
1930
1930
  let(:second_txn_number) do
1931
- started_events[-1].command['txnNumber'].value
1931
+ Utils.int64_value(started_events[-1].command['txnNumber'])
1932
1932
  end
1933
1933
 
1934
1934
  it 'inserts the documents' do
@@ -94,27 +94,7 @@ describe Mongo::Client do
94
94
  # cluster during SDAM
95
95
  context 'me mismatch on the only initial seed' do
96
96
  let(:address) do
97
- address = SpecConfig.instance.addresses.first
98
- port = address.sub(/^.*:/, '').to_i
99
- address = address.sub(/:.*/, '')
100
- case address
101
- when '127.0.0.1'
102
- 'localhost'
103
- when /^(\d+\.){3}\d+$/
104
- skip 'This test requires a hostname or 127.0.0.1 as address'
105
- else
106
- # We don't know if mongod is listening on ipv4 or ipv6,
107
- # in principle.
108
- # Our tests use ipv4, so hardcode that for now.
109
- # To support both we need to try both addresses
110
- # which will make this test more complicated.
111
- resolved_address = Addrinfo.getaddrinfo(address, port, Socket::PF_INET).first.ip_address
112
- if resolved_address.include?(':')
113
- "[#{resolved_address}]"
114
- else
115
- resolved_address
116
- end + ":#{port}"
117
- end
97
+ ClusterConfig.instance.alternate_address.to_s
118
98
  end
119
99
 
120
100
  let(:logger) do
@@ -20,6 +20,25 @@ describe Mongo::Cluster do
20
20
 
21
21
  let(:cluster) { cluster_without_io }
22
22
 
23
+ describe 'initialize' do
24
+
25
+ context 'when there are duplicate addresses' do
26
+
27
+ let(:addresses) do
28
+ SpecConfig.instance.addresses + SpecConfig.instance.addresses
29
+ end
30
+ let(:cluster_with_dup_addresses) do
31
+ register_cluster(
32
+ described_class.new(addresses, monitoring, SpecConfig.instance.test_options))
33
+ end
34
+
35
+ it 'does not raise an exception' do
36
+ expect { cluster_with_dup_addresses }.not_to raise_error
37
+ end
38
+ end
39
+
40
+ end
41
+
23
42
  describe '#==' do
24
43
 
25
44
  context 'when the other is a cluster' do
@@ -575,6 +594,44 @@ describe Mongo::Cluster do
575
594
  end
576
595
 
577
596
  describe '#sessions_supported?' do
597
+ context 'when client has not contacted any servers' do
598
+
599
+ let(:cluster) do
600
+ described_class.new(SpecConfig.instance.addresses, monitoring,
601
+ SpecConfig.instance.test_options.merge(
602
+ monitoring_io: false, server_selection_timeout: 0.183))
603
+ end
604
+
605
+ it 'is false' do
606
+ expect(cluster.send(:sessions_supported?)).to be false
607
+ end
608
+ end
609
+
610
+ context 'when client has contacted servers and then disconnected' do
611
+ min_server_fcv '3.6'
612
+ require_wired_tiger
613
+ require_topology :sharded, :replica_set
614
+
615
+ let(:cluster) do
616
+ described_class.new(SpecConfig.instance.addresses, monitoring,
617
+ SpecConfig.instance.test_options.merge(
618
+ server_selection_timeout: 0.183)
619
+ ).tap do |cluster|
620
+ register_cluster(cluster)
621
+ end
622
+ end
623
+
624
+ before do
625
+ cluster.next_primary
626
+ cluster.servers_list.map(&:disconnect!)
627
+ cluster.servers_list.map(&:unknown!)
628
+ end
629
+
630
+ it 'is true' do
631
+ expect(cluster.send(:sessions_supported?)).to be true
632
+ end
633
+ end
634
+
578
635
  context 'in server < 3.6' do
579
636
  max_server_version '3.4'
580
637
 
@@ -575,7 +575,7 @@ describe Mongo::Collection::View::MapReduce do
575
575
  expect(map_reduce.send(:secondary_ok?)).to be false
576
576
  end
577
577
 
578
- context 'when the server is not a valid for writing' do
578
+ context 'when the server is not valid for writing' do
579
579
  clean_slate
580
580
 
581
581
  before do
@@ -278,9 +278,9 @@ describe Mongo::Collection do
278
278
  require_topology :replica_set
279
279
 
280
280
  let(:client_options) do
281
- {
281
+ SpecConfig.instance.auth_options.merge(
282
282
  read: { mode: :primary_preferred },
283
- }
283
+ )
284
284
  end
285
285
 
286
286
  let(:subscriber) { EventSubscriber.new }
@@ -945,6 +945,30 @@ describe Mongo::Collection do
945
945
  it_behaves_like 'a failed operation using a session'
946
946
  end
947
947
  end
948
+
949
+ context 'when collation has a strength' do
950
+ min_server_fcv '3.4'
951
+
952
+ let(:band_collection) do
953
+ described_class.new(database, :bands)
954
+ end
955
+
956
+ before do
957
+ band_collection.delete_many
958
+ band_collection.insert_many([{ name: "Depeche Mode" }, { name: "New Order" }])
959
+ end
960
+
961
+ let(:options) do
962
+ { collation: { locale: 'en_US', strength: 2 } }
963
+ end
964
+ let(:band_result) do
965
+ band_collection.find({ name: 'DEPECHE MODE' }, options)
966
+ end
967
+
968
+ it 'finds Capitalize from UPPER CASE' do
969
+ expect(band_result.count_documents).to eq(1)
970
+ end
971
+ end
948
972
  end
949
973
 
950
974
  describe '#drop' do
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mongo::Cursor::Builder::OpKillCursors do
4
+
5
+ let(:reply) do
6
+ Mongo::Protocol::Reply.allocate.tap do |reply|
7
+ allow(reply).to receive(:cursor_id).and_return(8000)
8
+ end
9
+ end
10
+
11
+ let(:result) do
12
+ Mongo::Operation::Result.new(reply)
13
+ end
14
+
15
+ let(:view) do
16
+ Mongo::Collection::View.new(
17
+ authorized_collection,
18
+ {},
19
+ tailable: true,
20
+ max_time_ms: 100
21
+ )
22
+ end
23
+
24
+ let(:cursor) do
25
+ Mongo::Cursor.new(view, result, authorized_primary)
26
+ end
27
+
28
+ let(:builder) do
29
+ described_class.new(cursor)
30
+ end
31
+
32
+ describe '#specification' do
33
+
34
+ let(:specification) do
35
+ builder.specification
36
+ end
37
+
38
+ it 'includes the cursor ids' do
39
+ expect(specification[:cursor_ids]).to eq([BSON::Int64.new(8000)])
40
+ end
41
+
42
+ it 'includes the database name' do
43
+ expect(specification[:db_name]).to eq(SpecConfig.instance.test_db)
44
+ end
45
+
46
+ it 'includes the collection name' do
47
+ expect(specification[:coll_name]).to eq(TEST_COLL)
48
+ end
49
+ end
50
+
51
+ describe '.get_cursors_list' do
52
+ it 'returns integer cursor ids' do
53
+ expect(described_class.get_cursors_list(builder.specification)).to eq([8000])
54
+ end
55
+ end
56
+ end
@@ -137,12 +137,13 @@ describe Mongo::Server::Connection, retry: 3 do
137
137
 
138
138
  it 'logs a warning' do
139
139
  messages = []
140
- # Straightforward expectations are not working here for some reason
141
140
  expect(Mongo::Logger.logger).to receive(:warn) do |msg|
142
141
  messages << msg
143
142
  end
143
+
144
144
  expect(error).not_to be nil
145
- expect(messages).to include(expected_message)
145
+
146
+ messages.any? { |msg| msg.include?(expected_message) }.should be true
146
147
  end
147
148
 
148
149
  end
@@ -419,6 +420,73 @@ describe Mongo::Server::Connection, retry: 3 do
419
420
  end
420
421
  end
421
422
 
423
+ context 'connecting to arbiter' do
424
+ require_topology :replica_set
425
+
426
+ before(:all) do
427
+ unless ENV['HAVE_ARBITER']
428
+ skip 'Test requires an arbiter in the deployment'
429
+ end
430
+ end
431
+
432
+ let(:arbiter_server) do
433
+ authorized_client.cluster.servers_list.each do |server|
434
+ server.scan!
435
+ end
436
+ server = authorized_client.cluster.servers_list.detect do |server|
437
+ server.arbiter?
438
+ end.tap do |server|
439
+ raise 'No arbiter in the deployment' unless server
440
+ end
441
+ end
442
+
443
+ shared_examples_for 'does not authenticate' do
444
+ let(:client) do
445
+ new_local_client([address],
446
+ SpecConfig.instance.test_options.merge(
447
+ :user => 'bogus',
448
+ :password => 'bogus',
449
+ :database => 'bogus'
450
+ ).merge(connect: :direct),
451
+ )
452
+ end
453
+
454
+ let(:connection) do
455
+ described_class.new(
456
+ server,
457
+ )
458
+ end
459
+
460
+ let(:ping) do
461
+ client.database.command(ping: 1)
462
+ end
463
+
464
+ it 'does not authenticate' do
465
+ ClientRegistry.instance.close_all_clients
466
+
467
+ expect_any_instance_of(Mongo::Server::Connection).not_to receive(:authenticate!)
468
+
469
+ expect(ping.documents.first['ok']).to eq(1) rescue nil
470
+ end
471
+ end
472
+
473
+ context 'without me mismatch' do
474
+ let(:address) do
475
+ arbiter_server.address.to_s
476
+ end
477
+
478
+ it_behaves_like 'does not authenticate'
479
+ end
480
+
481
+ context 'with me mismatch' do
482
+ let(:address) do
483
+ "#{ClusterConfig.instance.alternate_address.host}:#{arbiter_server.address.port}"
484
+ end
485
+
486
+ it_behaves_like 'does not authenticate'
487
+ end
488
+ end
489
+
422
490
  end
423
491
 
424
492
  describe '#disconnect!' do
@@ -1012,7 +1080,7 @@ describe Mongo::Server::Connection, retry: 3 do
1012
1080
  end
1013
1081
 
1014
1082
  it 'uses the connect_timeout for the address' do
1015
- expect(connection.address.send(:connect_timeout)).to eq(3)
1083
+ expect(connection.address.options[:connect_timeout]).to eq(3)
1016
1084
  end
1017
1085
 
1018
1086
  it 'uses the socket_timeout as the socket_timeout' do
@@ -1031,7 +1099,7 @@ describe Mongo::Server::Connection, retry: 3 do
1031
1099
  end
1032
1100
 
1033
1101
  it 'uses the connect_timeout for the address' do
1034
- expect(connection.address.send(:connect_timeout)).to eq(3)
1102
+ expect(connection.address.options[:connect_timeout]).to eq(3)
1035
1103
  end
1036
1104
 
1037
1105
  it 'does not use a socket_timeout' do
@@ -1052,8 +1120,8 @@ describe Mongo::Server::Connection, retry: 3 do
1052
1120
  connection.connect!
1053
1121
  end
1054
1122
 
1055
- it 'uses the default connect_timeout for the address' do
1056
- expect(connection.address.send(:connect_timeout)).to eq(10)
1123
+ it 'does not specify connect_timeout for the address' do
1124
+ expect(connection.address.options[:connect_timeout]).to be nil
1057
1125
  end
1058
1126
 
1059
1127
  it 'uses the socket_timeout' do
@@ -1071,8 +1139,8 @@ describe Mongo::Server::Connection, retry: 3 do
1071
1139
  connection.connect!
1072
1140
  end
1073
1141
 
1074
- it 'uses the default connect_timeout for the address' do
1075
- expect(connection.address.send(:connect_timeout)).to eq(10)
1142
+ it 'does not specify connect_timeout for the address' do
1143
+ expect(connection.address.options[:connect_timeout]).to be nil
1076
1144
  end
1077
1145
 
1078
1146
  it 'does not use a socket_timeout' do
@@ -66,7 +66,7 @@ describe Mongo::Server::Monitor::Connection do
66
66
  end
67
67
 
68
68
  it 'uses the connect_timeout for the address' do
69
- expect(connection.address.send(:connect_timeout)).to eq(3)
69
+ expect(connection.address.options[:connect_timeout]).to eq(3)
70
70
  end
71
71
 
72
72
  it 'uses the connect_timeout as the socket_timeout' do
@@ -81,7 +81,7 @@ describe Mongo::Server::Monitor::Connection do
81
81
  end
82
82
 
83
83
  it 'uses the connect_timeout for the address' do
84
- expect(connection.address.send(:connect_timeout)).to eq(3)
84
+ expect(connection.address.options[:connect_timeout]).to eq(3)
85
85
  end
86
86
 
87
87
  it 'uses the connect_timeout as the socket_timeout' do
@@ -98,8 +98,8 @@ describe Mongo::Server::Monitor::Connection do
98
98
  SpecConfig.instance.test_options.merge(connect_timeout: nil, socket_timeout: 5)
99
99
  end
100
100
 
101
- it 'uses the default connect_timeout for the address' do
102
- expect(connection.address.send(:connect_timeout)).to eq(10)
101
+ it 'does not specify connect_timeout for the address' do
102
+ expect(connection.address.options[:connect_timeout]).to be nil
103
103
  end
104
104
 
105
105
  it 'uses the connect_timeout as the socket_timeout' do
@@ -113,8 +113,8 @@ describe Mongo::Server::Monitor::Connection do
113
113
  SpecConfig.instance.test_options.merge(connect_timeout: nil, socket_timeout: nil)
114
114
  end
115
115
 
116
- it 'uses the default connect_timeout for the address' do
117
- expect(connection.address.send(:connect_timeout)).to eq(10)
116
+ it 'does not specify connect_timeout for the address' do
117
+ expect(connection.address.options[:connect_timeout]).to be nil
118
118
  end
119
119
 
120
120
  it 'uses the connect_timeout as the socket_timeout' do
@@ -189,10 +189,17 @@ describe Mongo::Server::Monitor::Connection do
189
189
 
190
190
  it 'logs a warning' do
191
191
  expect_any_instance_of(Mongo::Socket).to receive(:write).and_raise(Mongo::Error::SocketError, 'test error')
192
- expect(Mongo::Logger.logger).to receive(:warn).with(expected_message).and_call_original
192
+
193
+ messages = []
194
+ expect(Mongo::Logger.logger).to receive(:warn) do |msg|
195
+ messages << msg
196
+ end
197
+
193
198
  expect do
194
199
  monitor.connection.connect!
195
200
  end.to raise_error(Mongo::Error::SocketError, 'test error')
201
+
202
+ messages.any? { |msg| msg.include?(expected_message) }.should be true
196
203
  end
197
204
  end
198
205
  end