mongo 2.4.0.rc0 → 2.4.0.rc1

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 (93) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +1 -2
  4. data/lib/mongo/bulk_write/validatable.rb +3 -1
  5. data/lib/mongo/client.rb +30 -3
  6. data/lib/mongo/cluster/app_metadata.rb +7 -2
  7. data/lib/mongo/collection.rb +3 -1
  8. data/lib/mongo/collection/view.rb +3 -1
  9. data/lib/mongo/collection/view/aggregation.rb +3 -1
  10. data/lib/mongo/collection/view/builder/find_command.rb +20 -5
  11. data/lib/mongo/collection/view/map_reduce.rb +3 -1
  12. data/lib/mongo/collection/view/writable.rb +12 -2
  13. data/lib/mongo/cursor/builder/get_more_command.rb +3 -2
  14. data/lib/mongo/error/closed_stream.rb +1 -1
  15. data/lib/mongo/error/invalid_server_preference.rb +1 -1
  16. data/lib/mongo/index/view.rb +3 -1
  17. data/lib/mongo/operation/write/bulk/mergable.rb +1 -1
  18. data/lib/mongo/operation/write/create_index.rb +1 -1
  19. data/lib/mongo/operation/write/delete.rb +1 -1
  20. data/lib/mongo/operation/write/update.rb +1 -1
  21. data/lib/mongo/protocol/delete.rb +4 -1
  22. data/lib/mongo/protocol/get_more.rb +4 -1
  23. data/lib/mongo/protocol/insert.rb +7 -3
  24. data/lib/mongo/protocol/kill_cursors.rb +4 -1
  25. data/lib/mongo/protocol/message.rb +5 -1
  26. data/lib/mongo/protocol/query.rb +11 -4
  27. data/lib/mongo/protocol/update.rb +4 -1
  28. data/lib/mongo/server/connectable.rb +8 -2
  29. data/lib/mongo/server/connection_pool.rb +3 -1
  30. data/lib/mongo/server/monitor.rb +1 -0
  31. data/lib/mongo/socket.rb +16 -8
  32. data/lib/mongo/socket/ssl.rb +24 -9
  33. data/lib/mongo/uri.rb +6 -6
  34. data/lib/mongo/version.rb +1 -1
  35. data/mongo.gemspec +1 -1
  36. data/spec/mongo/bulk_write_spec.rb +117 -0
  37. data/spec/mongo/collection/view/aggregation_spec.rb +26 -0
  38. data/spec/mongo/collection/view/builder/find_command_spec.rb +244 -2
  39. data/spec/mongo/collection/view/map_reduce_spec.rb +13 -0
  40. data/spec/mongo/collection/view/readable_spec.rb +26 -0
  41. data/spec/mongo/collection/view/writable_spec.rb +104 -0
  42. data/spec/mongo/collection/view_spec.rb +13 -0
  43. data/spec/mongo/collection_spec.rb +226 -7
  44. data/spec/mongo/crud_spec.rb +5 -5
  45. data/spec/mongo/index/view_spec.rb +53 -0
  46. data/spec/mongo/server/connection_spec.rb +45 -26
  47. data/spec/mongo/socket/ssl_spec.rb +358 -22
  48. data/spec/spec_helper.rb +4 -0
  49. data/spec/support/authorization.rb +3 -3
  50. data/spec/support/certificates/client_cert.pem +21 -0
  51. data/spec/support/certificates/client_key.pem +28 -0
  52. data/spec/support/certificates/client_key_encrypted.pem +30 -0
  53. data/spec/support/crud.rb +67 -22
  54. data/spec/support/crud/read.rb +18 -36
  55. data/spec/support/crud/write.rb +0 -44
  56. data/spec/support/crud_tests/read/aggregate-collation.yml +17 -0
  57. data/spec/support/crud_tests/read/aggregate-out.yml +28 -0
  58. data/spec/support/crud_tests/read/aggregate.yml +1 -35
  59. data/spec/support/crud_tests/read/count-collation.yml +15 -0
  60. data/spec/support/crud_tests/read/count.yml +3 -15
  61. data/spec/support/crud_tests/read/distinct-collation.yml +17 -0
  62. data/spec/support/crud_tests/read/distinct.yml +1 -14
  63. data/spec/support/crud_tests/read/find-collation.yml +15 -0
  64. data/spec/support/crud_tests/read/find.yml +1 -12
  65. data/spec/support/crud_tests/write/deleteMany-collation.yml +22 -0
  66. data/spec/support/crud_tests/write/deleteMany.yml +1 -23
  67. data/spec/support/crud_tests/write/deleteOne-collation.yml +22 -0
  68. data/spec/support/crud_tests/write/deleteOne.yml +1 -21
  69. data/spec/support/crud_tests/write/findOneAndDelete-collation.yml +23 -0
  70. data/spec/support/crud_tests/write/findOneAndDelete.yml +2 -28
  71. data/spec/support/crud_tests/write/findOneAndReplace-collation.yml +24 -0
  72. data/spec/support/crud_tests/write/findOneAndReplace-upsert.yml +47 -0
  73. data/spec/support/crud_tests/write/findOneAndReplace.yml +13 -53
  74. data/spec/support/crud_tests/write/findOneAndUpdate-collation.yml +27 -0
  75. data/spec/support/crud_tests/write/findOneAndUpdate.yml +8 -51
  76. data/spec/support/crud_tests/write/insertMany.yml +1 -2
  77. data/spec/support/crud_tests/write/insertOne.yml +1 -2
  78. data/spec/support/crud_tests/write/replaceOne-collation.yml +23 -0
  79. data/spec/support/crud_tests/write/replaceOne-upsert.yml +48 -0
  80. data/spec/support/crud_tests/write/replaceOne.yml +11 -45
  81. data/spec/support/crud_tests/write/updateMany-collation.yml +27 -0
  82. data/spec/support/crud_tests/write/updateMany.yml +10 -42
  83. data/spec/support/crud_tests/write/updateOne-collation.yml +24 -0
  84. data/spec/support/crud_tests/write/updateOne.yml +7 -33
  85. data/spec/support/sdam/rs/new_primary_new_setversion.yml +1 -1
  86. data/spec/support/sdam/rs/null_election_id.yml +1 -0
  87. data/spec/support/sdam/rs/primary_disconnect_electionid.yml +2 -3
  88. data/spec/support/sdam/rs/primary_disconnect_setversion.yml +1 -2
  89. data/spec/support/sdam/single/direct_connection_rsarbiter.yml +1 -1
  90. data/spec/support/sdam/single/direct_connection_rsprimary.yml +1 -1
  91. data/spec/support/sdam/single/direct_connection_rssecondary.yml +1 -1
  92. metadata +40 -4
  93. metadata.gz.sig +0 -0
@@ -59,6 +59,7 @@ module Mongo
59
59
  @update = update
60
60
  @flags = options[:flags] || []
61
61
  @upconverter = Upconverter.new(collection, selector, update, flags)
62
+ super
62
63
  end
63
64
 
64
65
  # Return the event payload for monitoring.
@@ -78,10 +79,12 @@ module Mongo
78
79
  }
79
80
  end
80
81
 
81
- private
82
+ protected
82
83
 
83
84
  attr_reader :upconverter
84
85
 
86
+ private
87
+
85
88
  # The operation code required to specify an Update message.
86
89
  # @return [Fixnum] the operation code.
87
90
  def op_code
@@ -28,6 +28,10 @@ module Mongo
28
28
  # The default time in seconds to timeout an operation executed on a socket.
29
29
  #
30
30
  # @since 2.0.0
31
+ #
32
+ # @deprecated Timeouts on Ruby sockets aren't effective so this default option is
33
+ # no longer used.
34
+ # Will be removed in driver version 3.0.
31
35
  TIMEOUT = 5.freeze
32
36
 
33
37
  # @return [ Mongo::Address ] address The address to connect to.
@@ -73,13 +77,15 @@ module Mongo
73
77
  #
74
78
  # @since 2.0.0
75
79
  def timeout
76
- @timeout ||= options[:socket_timeout] || TIMEOUT
80
+ @timeout ||= options[:socket_timeout]
77
81
  end
78
82
 
79
- private
83
+ protected
80
84
 
81
85
  attr_reader :socket
82
86
 
87
+ private
88
+
83
89
  def ssl_options
84
90
  @ssl_options[:ssl] == true ? @ssl_options : {}
85
91
  end
@@ -109,10 +109,12 @@ module Mongo
109
109
  checkin(connection) if connection
110
110
  end
111
111
 
112
- private
112
+ protected
113
113
 
114
114
  attr_reader :queue
115
115
 
116
+ private
117
+
116
118
  class << self
117
119
 
118
120
  # Get a connection pool for the provided server.
@@ -104,6 +104,7 @@ module Mongo
104
104
  @options = options.freeze
105
105
  @connection = Connection.new(address, options)
106
106
  @last_round_trip_time = nil
107
+ @last_scan = nil
107
108
  @mutex = Mutex.new
108
109
  end
109
110
 
@@ -162,14 +162,28 @@ module Mongo
162
162
  # @since 2.0.5
163
163
  def eof?
164
164
  @socket.eof?
165
- rescue IOError, SystemCallError => e
165
+ rescue IOError, SystemCallError => _
166
166
  true
167
167
  end
168
168
 
169
169
  private
170
170
 
171
171
  def read_from_socket(length)
172
- @socket.read(length) || String.new
172
+ data = String.new
173
+ deadline = (Time.now + timeout) if timeout
174
+ begin
175
+ while (data.length < length)
176
+ data << @socket.read_nonblock(length - data.length)
177
+ end
178
+ rescue IO::WaitReadable
179
+ select_timeout = (deadline - Time.now) if deadline
180
+ unless Kernel::select([@socket], nil, [@socket], select_timeout)
181
+ raise Timeout::Error.new("Took more than #{timeout} seconds to receive data.")
182
+ end
183
+ retry
184
+ end
185
+
186
+ data
173
187
  end
174
188
 
175
189
  def unix_socket?(sock)
@@ -178,12 +192,6 @@ module Mongo
178
192
 
179
193
  def set_socket_options(sock)
180
194
  sock.set_encoding(BSON::BINARY)
181
-
182
- unless unix_socket?(sock) && BSON::Environment.jruby?
183
- encoded_timeout = [ timeout, 0 ].pack(TIMEOUT_PACK)
184
- sock.setsockopt(SOL_SOCKET, SO_RCVTIMEO, encoded_timeout)
185
- sock.setsockopt(SOL_SOCKET, SO_SNDTIMEO, encoded_timeout)
186
- end
187
195
  end
188
196
 
189
197
  def handle_errors
@@ -116,22 +116,32 @@ module Mongo
116
116
 
117
117
  def create_context(options)
118
118
  context = OpenSSL::SSL::SSLContext.new
119
- set_cert(context, options) if options[:ssl_cert]
120
- set_key(context, options) if options[:ssl_key]
119
+ set_cert(context, options)
120
+ set_key(context, options)
121
121
  set_cert_verification(context, options) unless options[:ssl_verify] == false
122
122
  context
123
123
  end
124
124
 
125
125
  def set_cert(context, options)
126
- context.cert = OpenSSL::X509::Certificate.new(File.open(options[:ssl_cert]))
126
+ if options[:ssl_cert]
127
+ context.cert = OpenSSL::X509::Certificate.new(File.open(options[:ssl_cert]))
128
+ elsif options[:ssl_cert_string]
129
+ context.cert = OpenSSL::X509::Certificate.new(options[:ssl_cert_string])
130
+ elsif options[:ssl_cert_object]
131
+ context.cert = options[:ssl_cert_object]
132
+ end
127
133
  end
128
134
 
129
135
  def set_key(context, options)
130
- if options[:ssl_key_pass_phrase]
131
- context.key = OpenSSL::PKey::RSA.new(File.open(options[:ssl_key]),
132
- options[:ssl_key_pass_phrase])
133
- else
134
- context.key = OpenSSL::PKey::RSA.new(File.open(options[:ssl_key]))
136
+ passphrase = options[:ssl_key_pass_phrase]
137
+ if options[:ssl_key]
138
+ context.key = passphrase ? OpenSSL::PKey.read(File.open(options[:ssl_key]), passphrase) :
139
+ OpenSSL::PKey.read(File.open(options[:ssl_key]))
140
+ elsif options[:ssl_key_string]
141
+ context.key = passphrase ? OpenSSL::PKey.read(options[:ssl_key_string], passphrase) :
142
+ OpenSSL::PKey.read(options[:ssl_key_string])
143
+ elsif options[:ssl_key_object]
144
+ context.key = options[:ssl_key_object]
135
145
  end
136
146
  end
137
147
 
@@ -139,7 +149,12 @@ module Mongo
139
149
  context.verify_mode = OpenSSL::SSL::VERIFY_PEER
140
150
  cert_store = OpenSSL::X509::Store.new
141
151
  if options[:ssl_ca_cert]
142
- cert_store.add_file(options[:ssl_ca_cert])
152
+ cert_store.add_cert(OpenSSL::X509::Certificate.new(File.open(options[:ssl_ca_cert])))
153
+ elsif options[:ssl_ca_cert_string]
154
+ cert_store.add_cert(OpenSSL::X509::Certificate.new(options[:ssl_ca_cert_string]))
155
+ elsif options[:ssl_ca_cert_object]
156
+ raise TypeError("Option :ssl_ca_cert_object should be an array of OpenSSL::X509:Certificate objects") unless options[:ssl_ca_cert_object].is_a? Array
157
+ options[:ssl_ca_cert_object].each {|cert| cert_store.add_cert(cert)}
143
158
  else
144
159
  cert_store.set_default_paths
145
160
  end
@@ -193,7 +193,7 @@ module Mongo
193
193
  def initialize(string, options = {})
194
194
  @string = string
195
195
  @options = options
196
- empty, scheme, remaining = @string.partition(SCHEME)
196
+ _, scheme, remaining = @string.partition(SCHEME)
197
197
  raise_invalid_error!(INVALID_SCHEME) unless scheme == SCHEME
198
198
  setup!(remaining)
199
199
  end
@@ -248,7 +248,7 @@ module Mongo
248
248
  end
249
249
 
250
250
  def extract_db_opts!(string)
251
- db_opts, d, creds_hosts = string.reverse.partition(DATABASE_DELIM)
251
+ db_opts, _, creds_hosts = string.reverse.partition(DATABASE_DELIM)
252
252
  db_opts, creds_hosts = creds_hosts, db_opts if creds_hosts.empty?
253
253
  if db_opts.empty? && creds_hosts.include?(URI_OPTS_DELIM)
254
254
  raise_invalid_error!(INVALID_OPTS_DELIM)
@@ -264,13 +264,13 @@ module Mongo
264
264
  end
265
265
 
266
266
  def split_creds_hosts(string)
267
- hosts, d, creds = string.reverse.partition(AUTH_DELIM)
267
+ hosts, _, creds = string.reverse.partition(AUTH_DELIM)
268
268
  hosts, creds = creds, hosts if hosts.empty?
269
269
  [ hosts, creds ].map { |s| s.reverse }
270
270
  end
271
271
 
272
272
  def parse_db_opts!(string)
273
- auth_db, d, uri_opts = string.partition(URI_OPTS_DELIM)
273
+ auth_db, _, uri_opts = string.partition(URI_OPTS_DELIM)
274
274
  @uri_options = Options::Redacted.new(parse_uri_options!(uri_opts))
275
275
  @database = parse_database!(auth_db)
276
276
  end
@@ -324,7 +324,7 @@ module Mongo
324
324
  validate_port_string!(p)
325
325
  end
326
326
  elsif host.index(HOST_PORT_DELIM)
327
- h, d, p = host.partition(HOST_PORT_DELIM)
327
+ h, _, p = host.partition(HOST_PORT_DELIM)
328
328
  raise_invalid_error!(INVALID_HOST) unless h.size > 0
329
329
  validate_port_string!(p)
330
330
  elsif host =~ UNIX_SOCKET
@@ -339,7 +339,7 @@ module Mongo
339
339
  end
340
340
 
341
341
  def decode(value)
342
- ::URI.decode(value)
342
+ ::URI::DEFAULT_PARSER.unescape(value)
343
343
  end
344
344
 
345
345
  # Hash for storing map of URI option parameters to conversion strategies
@@ -17,5 +17,5 @@ module Mongo
17
17
  # The current version of the driver.
18
18
  #
19
19
  # @since 2.0.0
20
- VERSION = '2.4.0.rc0'.freeze
20
+ VERSION = '2.4.0.rc1'.freeze
21
21
  end
@@ -30,5 +30,5 @@ Gem::Specification.new do |s|
30
30
  s.has_rdoc = 'yard'
31
31
  s.bindir = 'bin'
32
32
 
33
- s.add_dependency 'bson', '~> 4.2.0.rc0'
33
+ s.add_dependency 'bson', '~> 4.2.0.rc1'
34
34
  end
@@ -243,6 +243,19 @@ describe Mongo::BulkWrite do
243
243
  bulk_write.execute
244
244
  }.to raise_exception(Mongo::Error::UnsupportedCollation)
245
245
  end
246
+
247
+ context 'when a String key is used' do
248
+
249
+ let(:requests) do
250
+ [{ delete_one: { filter: { name: 'BANG' }, 'collation' => collation } }]
251
+ end
252
+
253
+ it 'raises an exception' do
254
+ expect {
255
+ bulk_write.execute
256
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
257
+ end
258
+ end
246
259
  end
247
260
  end
248
261
 
@@ -371,6 +384,20 @@ describe Mongo::BulkWrite do
371
384
  bulk_write.execute
372
385
  }.to raise_exception(Mongo::Error::UnsupportedCollation)
373
386
  end
387
+
388
+ context 'when a String key is used' do
389
+
390
+ let(:requests) do
391
+ [{ delete_one: { filter: { name: 'BANG' }, 'collation' => collation }},
392
+ { delete_one: { filter: { name: 'DOINK' }, 'collation' => collation }}]
393
+ end
394
+
395
+ it 'raises an exception' do
396
+ expect {
397
+ bulk_write.execute
398
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
399
+ end
400
+ end
374
401
  end
375
402
  end
376
403
 
@@ -473,6 +500,19 @@ describe Mongo::BulkWrite do
473
500
  bulk_write.execute
474
501
  }.to raise_exception(Mongo::Error::UnsupportedCollation)
475
502
  end
503
+
504
+ context 'when a String key is used' do
505
+
506
+ let(:requests) do
507
+ [{ delete_many: { filter: { name: 'BANG' }, 'collation' => collation }}]
508
+ end
509
+
510
+ it 'raises an exception' do
511
+ expect {
512
+ bulk_write.execute
513
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
514
+ end
515
+ end
476
516
  end
477
517
  end
478
518
 
@@ -582,6 +622,20 @@ describe Mongo::BulkWrite do
582
622
  bulk_write.execute
583
623
  }.to raise_exception(Mongo::Error::UnsupportedCollation)
584
624
  end
625
+
626
+ context 'when a String key is used' do
627
+
628
+ let(:requests) do
629
+ [{ delete_many: { filter: { name: 'BANG' }, 'collation' => collation }},
630
+ { delete_many: { filter: { name: 'DOINK' }, 'collation' => collation }}]
631
+ end
632
+
633
+ it 'raises an exception' do
634
+ expect {
635
+ bulk_write.execute
636
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
637
+ end
638
+ end
585
639
  end
586
640
  end
587
641
 
@@ -698,6 +752,21 @@ describe Mongo::BulkWrite do
698
752
  bulk_write.execute
699
753
  }.to raise_exception(Mongo::Error::UnsupportedCollation)
700
754
  end
755
+
756
+ context 'when a String key is used' do
757
+
758
+ let(:requests) do
759
+ [{ replace_one: { filter: { name: 'BANG' },
760
+ replacement: { other: 'pong' },
761
+ 'collation' => collation }}]
762
+ end
763
+
764
+ it 'raises an exception' do
765
+ expect {
766
+ bulk_write.execute
767
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
768
+ end
769
+ end
701
770
  end
702
771
  end
703
772
 
@@ -936,6 +1005,21 @@ describe Mongo::BulkWrite do
936
1005
  bulk_write.execute
937
1006
  }.to raise_exception(Mongo::Error::UnsupportedCollation)
938
1007
  end
1008
+
1009
+ context 'when a String key is used' do
1010
+
1011
+ let(:requests) do
1012
+ [{ update_one: { filter: { name: 'BANG' },
1013
+ update: { "$set" => { name: 'pong' }},
1014
+ 'collation' => collation }}]
1015
+ end
1016
+
1017
+ it 'raises an exception' do
1018
+ expect {
1019
+ bulk_write.execute
1020
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
1021
+ end
1022
+ end
939
1023
  end
940
1024
  end
941
1025
 
@@ -1027,6 +1111,24 @@ describe Mongo::BulkWrite do
1027
1111
  bulk_write.execute
1028
1112
  }.to raise_exception(Mongo::Error::UnsupportedCollation)
1029
1113
  end
1114
+
1115
+ context 'when a String key is used' do
1116
+
1117
+ let(:requests) do
1118
+ [{ update_one: { filter: { name: 'BANG' },
1119
+ update: { "$set" => { name: 'pong' }},
1120
+ 'collation' => collation }},
1121
+ { update_one: { filter: { name: 'DOINK' },
1122
+ update: { "$set" => { name: 'pong' }},
1123
+ 'collation' => collation }}]
1124
+ end
1125
+
1126
+ it 'raises an exception' do
1127
+ expect {
1128
+ bulk_write.execute
1129
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
1130
+ end
1131
+ end
1030
1132
  end
1031
1133
  end
1032
1134
 
@@ -1314,6 +1416,21 @@ describe Mongo::BulkWrite do
1314
1416
  bulk_write.execute
1315
1417
  }.to raise_exception(Mongo::Error::UnsupportedCollation)
1316
1418
  end
1419
+
1420
+ context 'when a String key is used' do
1421
+
1422
+ let(:requests) do
1423
+ [{ update_many: { filter: { name: 'BANG' },
1424
+ update: { "$set" => { name: 'pong' }},
1425
+ 'collation' => collation }}]
1426
+ end
1427
+
1428
+ it 'raises an exception' do
1429
+ expect {
1430
+ bulk_write.execute
1431
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
1432
+ end
1433
+ end
1317
1434
  end
1318
1435
  end
1319
1436
 
@@ -235,6 +235,19 @@ describe Mongo::Collection::View::Aggregation do
235
235
  result
236
236
  }.to raise_exception(Mongo::Error::UnsupportedCollation)
237
237
  end
238
+
239
+ context 'when a String key is used' do
240
+
241
+ let(:options) do
242
+ { 'collation' => { locale: 'en_US', strength: 2 } }
243
+ end
244
+
245
+ it 'raises an exception' do
246
+ expect {
247
+ result
248
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
249
+ end
250
+ end
238
251
  end
239
252
  end
240
253
  end
@@ -419,6 +432,19 @@ describe Mongo::Collection::View::Aggregation do
419
432
  result
420
433
  }.to raise_exception(Mongo::Error::UnsupportedCollation)
421
434
  end
435
+
436
+ context 'when a String key is used' do
437
+
438
+ let(:options) do
439
+ { 'collation' => { locale: 'en_US', strength: 2 } }
440
+ end
441
+
442
+ it 'raises an exception' do
443
+ expect {
444
+ result
445
+ }.to raise_exception(Mongo::Error::UnsupportedCollation)
446
+ end
447
+ end
422
448
  end
423
449
  end
424
450