mongo 2.2.7 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (266) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/LICENSE +1 -1
  5. data/README.md +1 -1
  6. data/Rakefile +1 -1
  7. data/lib/mongo.rb +1 -1
  8. data/lib/mongo/address.rb +1 -1
  9. data/lib/mongo/address/ipv4.rb +1 -1
  10. data/lib/mongo/address/ipv6.rb +1 -1
  11. data/lib/mongo/address/unix.rb +1 -1
  12. data/lib/mongo/auth.rb +1 -1
  13. data/lib/mongo/auth/cr.rb +1 -1
  14. data/lib/mongo/auth/ldap.rb +1 -1
  15. data/lib/mongo/auth/roles.rb +1 -1
  16. data/lib/mongo/auth/user.rb +1 -1
  17. data/lib/mongo/auth/user/view.rb +5 -5
  18. data/lib/mongo/auth/x509.rb +1 -1
  19. data/lib/mongo/bson.rb +1 -1
  20. data/lib/mongo/bulk_write.rb +4 -4
  21. data/lib/mongo/bulk_write/combineable.rb +1 -1
  22. data/lib/mongo/bulk_write/ordered_combiner.rb +1 -1
  23. data/lib/mongo/bulk_write/result.rb +1 -1
  24. data/lib/mongo/bulk_write/result_combiner.rb +1 -1
  25. data/lib/mongo/bulk_write/transformable.rb +1 -1
  26. data/lib/mongo/bulk_write/unordered_combiner.rb +1 -1
  27. data/lib/mongo/bulk_write/validatable.rb +1 -1
  28. data/lib/mongo/client.rb +2 -2
  29. data/lib/mongo/cluster.rb +15 -3
  30. data/lib/mongo/cluster/cursor_reaper.rb +174 -0
  31. data/lib/mongo/cluster/topology.rb +1 -1
  32. data/lib/mongo/cluster/topology/replica_set.rb +1 -1
  33. data/lib/mongo/cluster/topology/sharded.rb +1 -1
  34. data/lib/mongo/cluster/topology/single.rb +1 -1
  35. data/lib/mongo/cluster/topology/unknown.rb +1 -1
  36. data/lib/mongo/collection.rb +5 -4
  37. data/lib/mongo/collection/view.rb +4 -4
  38. data/lib/mongo/collection/view/aggregation.rb +2 -2
  39. data/lib/mongo/collection/view/builder.rb +1 -1
  40. data/lib/mongo/collection/view/builder/aggregation.rb +1 -1
  41. data/lib/mongo/collection/view/builder/find_command.rb +1 -1
  42. data/lib/mongo/collection/view/builder/flags.rb +1 -1
  43. data/lib/mongo/collection/view/builder/map_reduce.rb +1 -1
  44. data/lib/mongo/collection/view/builder/modifiers.rb +1 -1
  45. data/lib/mongo/collection/view/builder/op_query.rb +1 -1
  46. data/lib/mongo/collection/view/explainable.rb +1 -1
  47. data/lib/mongo/collection/view/immutable.rb +1 -1
  48. data/lib/mongo/collection/view/iterable.rb +2 -2
  49. data/lib/mongo/collection/view/map_reduce.rb +3 -3
  50. data/lib/mongo/collection/view/readable.rb +23 -6
  51. data/lib/mongo/collection/view/writable.rb +3 -3
  52. data/lib/mongo/cursor.rb +50 -7
  53. data/lib/mongo/cursor/builder.rb +1 -1
  54. data/lib/mongo/cursor/builder/get_more_command.rb +1 -1
  55. data/lib/mongo/cursor/builder/kill_cursors_command.rb +29 -1
  56. data/lib/mongo/cursor/builder/op_get_more.rb +1 -1
  57. data/lib/mongo/cursor/builder/op_kill_cursors.rb +29 -1
  58. data/lib/mongo/database.rb +4 -4
  59. data/lib/mongo/database/view.rb +2 -2
  60. data/lib/mongo/dbref.rb +4 -3
  61. data/lib/mongo/error.rb +1 -1
  62. data/lib/mongo/error/bulk_write_error.rb +1 -1
  63. data/lib/mongo/error/closed_stream.rb +1 -1
  64. data/lib/mongo/error/extra_file_chunk.rb +1 -1
  65. data/lib/mongo/error/file_not_found.rb +1 -1
  66. data/lib/mongo/error/invalid_bulk_operation.rb +1 -1
  67. data/lib/mongo/error/invalid_bulk_operation_type.rb +1 -1
  68. data/lib/mongo/error/invalid_collection_name.rb +1 -1
  69. data/lib/mongo/error/invalid_database_name.rb +1 -1
  70. data/lib/mongo/error/invalid_document.rb +1 -1
  71. data/lib/mongo/error/invalid_file.rb +1 -1
  72. data/lib/mongo/error/invalid_file_revision.rb +1 -1
  73. data/lib/mongo/error/invalid_nonce.rb +1 -1
  74. data/lib/mongo/error/invalid_replacement_document.rb +1 -1
  75. data/lib/mongo/error/invalid_server_preference.rb +1 -1
  76. data/lib/mongo/error/invalid_signature.rb +1 -1
  77. data/lib/mongo/error/invalid_update_document.rb +1 -1
  78. data/lib/mongo/error/invalid_uri.rb +1 -1
  79. data/lib/mongo/error/invalid_write_concern.rb +1 -1
  80. data/lib/mongo/error/max_bson_size.rb +1 -1
  81. data/lib/mongo/error/max_message_size.rb +1 -1
  82. data/lib/mongo/error/missing_file_chunk.rb +1 -1
  83. data/lib/mongo/error/multi_index_drop.rb +1 -1
  84. data/lib/mongo/error/need_primary_server.rb +1 -1
  85. data/lib/mongo/error/no_server_available.rb +4 -2
  86. data/lib/mongo/error/operation_failure.rb +1 -1
  87. data/lib/mongo/error/parser.rb +1 -1
  88. data/lib/mongo/error/socket_error.rb +1 -1
  89. data/lib/mongo/error/socket_timeout_error.rb +1 -1
  90. data/lib/mongo/error/unchangeable_collection_option.rb +1 -1
  91. data/lib/mongo/error/unexpected_chunk_length.rb +1 -1
  92. data/lib/mongo/error/unexpected_response.rb +1 -1
  93. data/lib/mongo/error/unsupported_features.rb +1 -1
  94. data/lib/mongo/event.rb +1 -1
  95. data/lib/mongo/event/description_changed.rb +1 -1
  96. data/lib/mongo/event/publisher.rb +1 -1
  97. data/lib/mongo/event/subscriber.rb +1 -1
  98. data/lib/mongo/grid.rb +1 -1
  99. data/lib/mongo/grid/file.rb +6 -2
  100. data/lib/mongo/grid/file/chunk.rb +6 -4
  101. data/lib/mongo/grid/file/info.rb +7 -3
  102. data/lib/mongo/grid/fs_bucket.rb +12 -6
  103. data/lib/mongo/grid/stream.rb +1 -1
  104. data/lib/mongo/grid/stream/read.rb +2 -4
  105. data/lib/mongo/grid/stream/write.rb +4 -3
  106. data/lib/mongo/index.rb +1 -1
  107. data/lib/mongo/index/view.rb +5 -4
  108. data/lib/mongo/loggable.rb +1 -1
  109. data/lib/mongo/logger.rb +1 -1
  110. data/lib/mongo/monitoring.rb +1 -1
  111. data/lib/mongo/operation.rb +1 -1
  112. data/lib/mongo/operation/commands.rb +1 -1
  113. data/lib/mongo/operation/commands/aggregate.rb +7 -7
  114. data/lib/mongo/operation/commands/aggregate/result.rb +1 -1
  115. data/lib/mongo/operation/commands/collections_info.rb +10 -9
  116. data/lib/mongo/operation/commands/collections_info/result.rb +1 -1
  117. data/lib/mongo/operation/commands/command.rb +1 -1
  118. data/lib/mongo/operation/commands/indexes.rb +12 -11
  119. data/lib/mongo/operation/commands/list_collections.rb +1 -1
  120. data/lib/mongo/operation/commands/list_collections/result.rb +1 -1
  121. data/lib/mongo/operation/commands/list_indexes.rb +1 -1
  122. data/lib/mongo/operation/commands/list_indexes/result.rb +1 -1
  123. data/lib/mongo/operation/commands/map_reduce.rb +1 -1
  124. data/lib/mongo/operation/commands/map_reduce/result.rb +1 -1
  125. data/lib/mongo/operation/commands/user_query.rb +11 -10
  126. data/lib/mongo/operation/commands/users_info.rb +2 -2
  127. data/lib/mongo/operation/commands/users_info/result.rb +1 -1
  128. data/lib/mongo/operation/executable.rb +8 -7
  129. data/lib/mongo/operation/kill_cursors.rb +2 -2
  130. data/lib/mongo/operation/limited.rb +1 -1
  131. data/lib/mongo/operation/read.rb +1 -1
  132. data/lib/mongo/operation/read/get_more.rb +2 -2
  133. data/lib/mongo/operation/read/query.rb +1 -1
  134. data/lib/mongo/operation/read/query/result.rb +1 -1
  135. data/lib/mongo/operation/read_preference.rb +10 -10
  136. data/lib/mongo/operation/result.rb +1 -1
  137. data/lib/mongo/operation/specifiable.rb +2 -2
  138. data/lib/mongo/operation/write.rb +1 -1
  139. data/lib/mongo/operation/write/bulk.rb +1 -1
  140. data/lib/mongo/operation/write/bulk/bulkable.rb +9 -9
  141. data/lib/mongo/operation/write/bulk/delete.rb +3 -3
  142. data/lib/mongo/operation/write/bulk/delete/result.rb +1 -1
  143. data/lib/mongo/operation/write/bulk/insert.rb +5 -5
  144. data/lib/mongo/operation/write/bulk/insert/result.rb +1 -1
  145. data/lib/mongo/operation/write/bulk/legacy_mergable.rb +1 -1
  146. data/lib/mongo/operation/write/bulk/mergable.rb +1 -1
  147. data/lib/mongo/operation/write/bulk/update.rb +3 -3
  148. data/lib/mongo/operation/write/bulk/update/result.rb +1 -1
  149. data/lib/mongo/operation/write/command.rb +1 -1
  150. data/lib/mongo/operation/write/command/create_index.rb +1 -1
  151. data/lib/mongo/operation/write/command/create_user.rb +1 -1
  152. data/lib/mongo/operation/write/command/delete.rb +1 -1
  153. data/lib/mongo/operation/write/command/drop_index.rb +1 -1
  154. data/lib/mongo/operation/write/command/insert.rb +11 -1
  155. data/lib/mongo/operation/write/command/remove_user.rb +1 -1
  156. data/lib/mongo/operation/write/command/update.rb +1 -1
  157. data/lib/mongo/operation/write/command/update_user.rb +1 -1
  158. data/lib/mongo/operation/write/command/writable.rb +7 -6
  159. data/lib/mongo/operation/write/create_index.rb +1 -1
  160. data/lib/mongo/operation/write/create_user.rb +1 -1
  161. data/lib/mongo/operation/write/delete.rb +1 -1
  162. data/lib/mongo/operation/write/delete/result.rb +1 -1
  163. data/lib/mongo/operation/write/drop_index.rb +5 -5
  164. data/lib/mongo/operation/write/gle.rb +3 -3
  165. data/lib/mongo/operation/write/idable.rb +1 -1
  166. data/lib/mongo/operation/write/insert.rb +5 -5
  167. data/lib/mongo/operation/write/insert/result.rb +1 -1
  168. data/lib/mongo/operation/write/remove_user.rb +1 -1
  169. data/lib/mongo/operation/write/update.rb +1 -1
  170. data/lib/mongo/operation/write/update/result.rb +1 -1
  171. data/lib/mongo/operation/write/update_user.rb +1 -1
  172. data/lib/mongo/operation/write/write_command_enabled.rb +10 -9
  173. data/lib/mongo/protocol/bit_vector.rb +2 -2
  174. data/lib/mongo/protocol/delete.rb +1 -1
  175. data/lib/mongo/protocol/get_more.rb +1 -1
  176. data/lib/mongo/protocol/insert.rb +5 -1
  177. data/lib/mongo/protocol/kill_cursors.rb +1 -1
  178. data/lib/mongo/protocol/message.rb +9 -5
  179. data/lib/mongo/protocol/query.rb +1 -1
  180. data/lib/mongo/protocol/reply.rb +1 -1
  181. data/lib/mongo/protocol/serializers.rb +8 -8
  182. data/lib/mongo/protocol/update.rb +1 -1
  183. data/lib/mongo/server.rb +40 -3
  184. data/lib/mongo/server/connectable.rb +1 -1
  185. data/lib/mongo/server/connection.rb +4 -2
  186. data/lib/mongo/server/connection_pool.rb +1 -1
  187. data/lib/mongo/server/connection_pool/queue.rb +1 -1
  188. data/lib/mongo/server/context.rb +3 -1
  189. data/lib/mongo/server/description.rb +1 -1
  190. data/lib/mongo/server/description/inspector/description_changed.rb +1 -1
  191. data/lib/mongo/server/monitor.rb +1 -1
  192. data/lib/mongo/server_selector.rb +2 -1
  193. data/lib/mongo/server_selector/nearest.rb +1 -1
  194. data/lib/mongo/server_selector/primary.rb +1 -1
  195. data/lib/mongo/server_selector/primary_preferred.rb +1 -1
  196. data/lib/mongo/server_selector/secondary.rb +1 -1
  197. data/lib/mongo/server_selector/secondary_preferred.rb +1 -1
  198. data/lib/mongo/server_selector/selectable.rb +12 -7
  199. data/lib/mongo/socket.rb +1 -1
  200. data/lib/mongo/socket/ssl.rb +1 -1
  201. data/lib/mongo/socket/tcp.rb +1 -1
  202. data/lib/mongo/socket/unix.rb +1 -1
  203. data/lib/mongo/uri.rb +1 -1
  204. data/lib/mongo/version.rb +2 -2
  205. data/lib/mongo/write_concern/acknowledged.rb +1 -1
  206. data/lib/mongo/write_concern/normalizable.rb +1 -1
  207. data/lib/mongo/write_concern/unacknowledged.rb +1 -1
  208. data/mongo.gemspec +1 -1
  209. data/spec/mongo/client_spec.rb +2 -2
  210. data/spec/mongo/cluster/cursor_reaper_spec.rb +216 -0
  211. data/spec/mongo/cluster_spec.rb +36 -5
  212. data/spec/mongo/collection/view/aggregation_spec.rb +2 -2
  213. data/spec/mongo/collection/view/map_reduce_spec.rb +2 -2
  214. data/spec/mongo/collection/view/readable_spec.rb +203 -5
  215. data/spec/mongo/collection/view_spec.rb +10 -0
  216. data/spec/mongo/collection_spec.rb +64 -18
  217. data/spec/mongo/cursor_spec.rb +89 -0
  218. data/spec/mongo/database_spec.rb +79 -13
  219. data/spec/mongo/grid/fs_bucket_spec.rb +119 -1
  220. data/spec/mongo/grid/stream/write_spec.rb +63 -12
  221. data/spec/mongo/index/view_spec.rb +19 -0
  222. data/spec/mongo/operation/commands/aggregate_spec.rb +10 -7
  223. data/spec/mongo/operation/commands/collections_info_spec.rb +1 -1
  224. data/spec/mongo/operation/commands/command_spec.rb +3 -3
  225. data/spec/mongo/operation/commands/indexes_spec.rb +1 -1
  226. data/spec/mongo/operation/commands/map_reduce_spec.rb +2 -2
  227. data/spec/mongo/operation/kill_cursors_spec.rb +10 -19
  228. data/spec/mongo/operation/read/get_more_spec.rb +13 -25
  229. data/spec/mongo/operation/read/query_spec.rb +26 -30
  230. data/spec/mongo/operation/read_preference_spec.rb +11 -11
  231. data/spec/mongo/operation/specifiable_spec.rb +31 -0
  232. data/spec/mongo/operation/write/bulk/delete_spec.rb +16 -18
  233. data/spec/mongo/operation/write/bulk/insert_spec.rb +17 -18
  234. data/spec/mongo/operation/write/bulk/update_spec.rb +20 -25
  235. data/spec/mongo/operation/write/command/delete_spec.rb +26 -32
  236. data/spec/mongo/operation/write/command/insert_spec.rb +24 -31
  237. data/spec/mongo/operation/write/command/update_spec.rb +24 -32
  238. data/spec/mongo/operation/write/create_index_spec.rb +4 -4
  239. data/spec/mongo/operation/write/create_user_spec.rb +3 -3
  240. data/spec/mongo/operation/write/delete_spec.rb +51 -22
  241. data/spec/mongo/operation/write/drop_index_spec.rb +2 -2
  242. data/spec/mongo/operation/write/insert_spec.rb +42 -11
  243. data/spec/mongo/operation/write/remove_user_spec.rb +4 -4
  244. data/spec/mongo/operation/write/update_spec.rb +34 -6
  245. data/spec/mongo/operation/write/update_user_spec.rb +1 -1
  246. data/spec/mongo/server/connection_spec.rb +22 -14
  247. data/spec/mongo/server_selection_spec.rb +2 -2
  248. data/spec/mongo/server_selector/nearest_spec.rb +4 -4
  249. data/spec/mongo/server_selector/primary_preferred_spec.rb +4 -4
  250. data/spec/mongo/server_selector/primary_spec.rb +2 -2
  251. data/spec/mongo/server_selector/secondary_preferred_spec.rb +4 -4
  252. data/spec/mongo/server_selector/secondary_spec.rb +3 -3
  253. data/spec/mongo/server_selector_spec.rb +82 -3
  254. data/spec/mongo/server_spec.rb +0 -20
  255. data/spec/support/command_monitoring.rb +1 -1
  256. data/spec/support/connection_string.rb +1 -1
  257. data/spec/support/crud.rb +1 -1
  258. data/spec/support/crud/read.rb +1 -1
  259. data/spec/support/crud/write.rb +1 -1
  260. data/spec/support/gridfs.rb +1 -1
  261. data/spec/support/shared/server_selector.rb +3 -3
  262. metadata +7 -10
  263. metadata.gz.sig +0 -0
  264. data/lib/csasl/csasl.bundle +0 -0
  265. data/spec/mongo/operation/write/response_spec.rb +0 -85
  266. data/spec/support/shared/operation.rb +0 -100
@@ -370,7 +370,7 @@ describe Mongo::Collection::View::Aggregation do
370
370
  end
371
371
 
372
372
 
373
- context 'when the context is not a valid server for writing' do
373
+ context 'when the server is not a valid for writing' do
374
374
 
375
375
  it 'reroutes the operation to a primary' do
376
376
  allow(aggregation).to receive(:valid_server?).and_return(false)
@@ -379,7 +379,7 @@ describe Mongo::Collection::View::Aggregation do
379
379
  end
380
380
  end
381
381
 
382
- context 'when the context is a valid server for writing' do
382
+ context 'when the server is a valid for writing' do
383
383
 
384
384
  it 'does not reroute the operation to a primary' do
385
385
  expect(Mongo::Logger.logger).not_to receive(:warn?)
@@ -328,7 +328,7 @@ describe Mongo::Collection::View::MapReduce do
328
328
  expect(map_reduce.send(:secondary_ok?)).to be false
329
329
  end
330
330
 
331
- context 'when the context is not a valid server for writing' do
331
+ context 'when the server is not a valid for writing' do
332
332
 
333
333
  it 'reroutes the operation to a primary' do
334
334
  allow(map_reduce).to receive(:valid_server?).and_return(false)
@@ -337,7 +337,7 @@ describe Mongo::Collection::View::MapReduce do
337
337
  end
338
338
  end
339
339
 
340
- context 'when the context is a valid server for writing' do
340
+ context 'when the server is a valid for writing' do
341
341
 
342
342
  it 'does not reroute the operation to a primary' do
343
343
  expect(Mongo::Logger.logger).not_to receive(:warn?)
@@ -309,6 +309,93 @@ describe Mongo::Collection::View::Readable do
309
309
  expect(view.count(read: { mode: :secondary })).to eq(10)
310
310
  end
311
311
 
312
+ context 'when the collection has a read preference set' do
313
+
314
+ after do
315
+ client.close
316
+ end
317
+
318
+ let(:client) do
319
+ # Set a timeout in case the collection read_preference does get used.
320
+ # Otherwise, the test will hang for 30 seconds.
321
+ authorized_client.with(server_selection_timeout: 1)
322
+ end
323
+
324
+ let(:read_preference) do
325
+ { :mode => :secondary, :tag_sets => [{ 'non' => 'existent' }] }
326
+ end
327
+
328
+ let(:collection) do
329
+ client[authorized_collection.name, read: read_preference]
330
+ end
331
+
332
+ let(:view) do
333
+ Mongo::Collection::View.new(collection, selector, options)
334
+ end
335
+
336
+ context 'when a read preference argument is provided' do
337
+
338
+ let(:result) do
339
+ view.count(read: { mode: :primary })
340
+ end
341
+
342
+ it 'uses the read preference passed to the method' do
343
+ expect(result).to eq(10)
344
+ end
345
+ end
346
+
347
+ context 'when no read preference argument is provided', unless: sharded? do
348
+
349
+ before do
350
+ allow(view.collection.client.cluster).to receive(:single?).and_return(false)
351
+ end
352
+
353
+ let(:result) do
354
+ view.count
355
+ end
356
+
357
+ it 'uses the read preference of the collection' do
358
+ expect {
359
+ result
360
+ }.to raise_exception(Mongo::Error::NoServerAvailable)
361
+ end
362
+ end
363
+
364
+ context 'when the collection does not have a read preference set', unless: sharded? do
365
+
366
+ after do
367
+ client.close
368
+ end
369
+
370
+ let(:client) do
371
+ authorized_client.with(server_selection_timeout: 1)
372
+ end
373
+
374
+ before do
375
+ allow(view.collection.client.cluster).to receive(:single?).and_return(false)
376
+ end
377
+
378
+ let(:collection) do
379
+ client[authorized_collection.name]
380
+ end
381
+
382
+ let(:view) do
383
+ Mongo::Collection::View.new(collection, selector, options)
384
+ end
385
+
386
+ let(:result) do
387
+ read_preference = { :mode => :secondary, :tag_sets => [{ 'non' => 'existent' }] }
388
+ view.count(read: read_preference)
389
+ end
390
+
391
+ it 'uses the read preference passed to the method' do
392
+ expect {
393
+ result
394
+ }.to raise_exception(Mongo::Error::NoServerAvailable)
395
+ end
396
+ end
397
+ end
398
+
312
399
  it 'takes a max_time_ms option', if: write_command_enabled? do
313
400
  expect {
314
401
  view.count(max_time_ms: 0.1)
@@ -434,7 +521,7 @@ describe Mongo::Collection::View::Readable do
434
521
  end
435
522
  end
436
523
 
437
- context 'when a read preference is specified' do
524
+ context 'when the collection has a read preference set' do
438
525
 
439
526
  let(:documents) do
440
527
  (1..3).map{ |i| { field: "test#{i}" }}
@@ -444,12 +531,93 @@ describe Mongo::Collection::View::Readable do
444
531
  authorized_collection.insert_many(documents)
445
532
  end
446
533
 
447
- let(:distinct) do
448
- view.distinct(:field, read: { mode: :secondary })
534
+ after do
535
+ client.close
449
536
  end
450
537
 
451
- it 'returns the distinct values' do
452
- expect(distinct.sort).to eq([ 'test1', 'test2', 'test3' ])
538
+ let(:client) do
539
+ # Set a timeout in case the collection read_preference does get used.
540
+ # Otherwise, the test will hang for 30 seconds.
541
+ authorized_client.with(server_selection_timeout: 1)
542
+ end
543
+
544
+ let(:read_preference) do
545
+ { :mode => :secondary, :tag_sets => [{ 'non' => 'existent' }] }
546
+ end
547
+
548
+ let(:collection) do
549
+ client[authorized_collection.name, read: read_preference]
550
+ end
551
+
552
+ let(:view) do
553
+ Mongo::Collection::View.new(collection, selector, options)
554
+ end
555
+
556
+ context 'when a read preference argument is provided' do
557
+
558
+ let(:distinct) do
559
+ view.distinct(:field, read: { mode: :primary })
560
+ end
561
+
562
+ it 'uses the read preference passed to the method' do
563
+ expect(distinct.sort).to eq([ 'test1', 'test2', 'test3' ])
564
+ end
565
+ end
566
+
567
+ context 'when no read preference argument is provided', unless: sharded? do
568
+
569
+ before do
570
+ allow(view.collection.client.cluster).to receive(:single?).and_return(false)
571
+ end
572
+
573
+ let(:distinct) do
574
+ view.distinct(:field)
575
+ end
576
+
577
+ it 'uses the read preference of the collection' do
578
+ expect {
579
+ distinct
580
+ }.to raise_exception(Mongo::Error::NoServerAvailable)
581
+ end
582
+ end
583
+
584
+ context 'when the collection does not have a read preference set', unless: sharded? do
585
+
586
+ let(:documents) do
587
+ (1..3).map{ |i| { field: "test#{i}" }}
588
+ end
589
+
590
+ before do
591
+ authorized_collection.insert_many(documents)
592
+ allow(view.collection.client.cluster).to receive(:single?).and_return(false)
593
+ end
594
+
595
+ after do
596
+ client.close
597
+ end
598
+
599
+ let(:client) do
600
+ authorized_client.with(server_selection_timeout: 1)
601
+ end
602
+
603
+ let(:collection) do
604
+ client[authorized_collection.name]
605
+ end
606
+
607
+ let(:view) do
608
+ Mongo::Collection::View.new(collection, selector, options)
609
+ end
610
+
611
+ let(:distinct) do
612
+ read_preference = { :mode => :secondary, :tag_sets => [{ 'non' => 'existent' }] }
613
+ view.distinct(:field, read: read_preference)
614
+ end
615
+
616
+ it 'uses the read preference passed to the method' do
617
+ expect {
618
+ distinct
619
+ }.to raise_exception(Mongo::Error::NoServerAvailable)
620
+ end
453
621
  end
454
622
  end
455
623
 
@@ -793,6 +961,36 @@ describe Mongo::Collection::View::Readable do
793
961
  end
794
962
  end
795
963
 
964
+ describe '#cusor_type' do
965
+
966
+ let(:options) do
967
+ { :cursor_type => :tailable }
968
+ end
969
+
970
+ context 'when cursor_type is specified' do
971
+
972
+ let(:new_cursor_type) do
973
+ :tailable_await
974
+ end
975
+
976
+ it 'sets the cursor_type value' do
977
+ new_view = view.cursor_type(new_cursor_type)
978
+ expect(new_view.cursor_type).to eq(new_cursor_type)
979
+ end
980
+
981
+ it 'returns a new View' do
982
+ expect(view.cursor_type(new_cursor_type)).not_to be(view)
983
+ end
984
+ end
985
+
986
+ context 'when cursor_type is not specified' do
987
+
988
+ it 'returns the cursor_type value' do
989
+ expect(view.cursor_type).to eq(options[:cursor_type])
990
+ end
991
+ end
992
+ end
993
+
796
994
  describe '#skip' do
797
995
 
798
996
  context 'when a skip is specified' do
@@ -246,6 +246,16 @@ describe Mongo::Collection::View do
246
246
  it 'parses standard options' do
247
247
  expect(view.options).to eq(options)
248
248
  end
249
+
250
+ it 'only freezes the view filter, not the user filter' do
251
+ expect(view.filter.frozen?).to be(true)
252
+ expect(filter.frozen?).to be(false)
253
+ end
254
+
255
+ it 'only freezes the view options, not the user options' do
256
+ expect(view.options.frozen?).to be(true)
257
+ expect(options.frozen?).to be(false)
258
+ end
249
259
  end
250
260
 
251
261
  context 'when the filter contains modifiers' do
@@ -135,12 +135,8 @@ describe Mongo::Collection do
135
135
  Mongo::Client.new(ADDRESSES, server_selection_timeout: 2)
136
136
  end
137
137
 
138
- let(:server_selection_timeout) do
139
- new_collection.read_preference.server_selection_timeout
140
- end
141
-
142
- it 'keeps the server_selection_timeout setting from client' do
143
- expect(server_selection_timeout).to eq(client.options[:server_selection_timeout])
138
+ it 'passes the the server_selection_timeout to the cluster' do
139
+ expect(client.cluster.options[:server_selection_timeout]).to eq(client.options[:server_selection_timeout])
144
140
  end
145
141
  end
146
142
 
@@ -152,6 +148,7 @@ describe Mongo::Collection do
152
148
 
153
149
  it 'sets the new read options on the new collection' do
154
150
  expect(new_collection.read_preference).to eq(Mongo::ServerSelector.get(new_options[:read]))
151
+ expect(new_collection.read_preference).not_to eq(client.read_preference)
155
152
  end
156
153
  end
157
154
 
@@ -161,16 +158,12 @@ describe Mongo::Collection do
161
158
  Mongo::Client.new(ADDRESSES, read: { mode: :primary_preferred }, server_selection_timeout: 2)
162
159
  end
163
160
 
164
- let(:server_selection_timeout) do
165
- new_collection.read_preference.server_selection_timeout
166
- end
167
-
168
161
  it 'sets the new read options on the new collection' do
169
162
  expect(new_collection.read_preference).to eq(Mongo::ServerSelector.get(new_options[:read]))
170
163
  end
171
164
 
172
- it 'keeps the server_selection_timeout setting from client' do
173
- expect(server_selection_timeout).to eq(client.options[:server_selection_timeout])
165
+ it 'passes the server_selection_timeout setting to the cluster' do
166
+ expect(client.cluster.options[:server_selection_timeout]).to eq(client.options[:server_selection_timeout])
174
167
  end
175
168
  end
176
169
  end
@@ -228,12 +221,8 @@ describe Mongo::Collection do
228
221
  Mongo::Client.new(ADDRESSES, server_selection_timeout: 2)
229
222
  end
230
223
 
231
- let(:server_selection_timeout) do
232
- new_collection.read_preference.server_selection_timeout
233
- end
234
-
235
- it 'keeps the server_selection_timeout setting from client' do
236
- expect(server_selection_timeout).to eq(client.options[:server_selection_timeout])
224
+ it 'passes the server_selection_timeout setting to the cluster' do
225
+ expect(client.cluster.options[:server_selection_timeout]).to eq(client.options[:server_selection_timeout])
237
226
  end
238
227
  end
239
228
 
@@ -245,6 +234,7 @@ describe Mongo::Collection do
245
234
 
246
235
  it 'sets the new read options on the new collection' do
247
236
  expect(new_collection.read_preference).to eq(Mongo::ServerSelector.get(new_options[:read]))
237
+ expect(new_collection.read_preference).not_to be(client.read_preference)
248
238
  end
249
239
  end
250
240
  end
@@ -719,6 +709,19 @@ describe Mongo::Collection do
719
709
  expect(result.inserted_ids.size).to eq(2)
720
710
  end
721
711
 
712
+ context 'when a document contains invalid keys' do
713
+
714
+ let(:docs) do
715
+ [ { 'first.name' => 'test1' }, { name: 'test2' } ]
716
+ end
717
+
718
+ it 'raises a BSON::String::IllegalKey exception' do
719
+ expect {
720
+ authorized_collection.insert_many(docs)
721
+ }.to raise_exception(BSON::String::IllegalKey)
722
+ end
723
+ end
724
+
722
725
  context 'when the client has a custom id generator' do
723
726
 
724
727
  let(:generator) do
@@ -842,6 +845,19 @@ describe Mongo::Collection do
842
845
  expect(result.inserted_id).to_not be_nil
843
846
  end
844
847
 
848
+ context 'when the document contains invalid keys' do
849
+
850
+ let(:doc) do
851
+ { 'testing.test' => 'value' }
852
+ end
853
+
854
+ it 'raises a BSON::String::IllegalKey exception' do
855
+ expect {
856
+ authorized_collection.insert_one(doc)
857
+ }.to raise_exception(BSON::String::IllegalKey)
858
+ end
859
+ end
860
+
845
861
  context 'when the insert fails' do
846
862
 
847
863
  let(:result) do
@@ -1216,6 +1232,36 @@ describe Mongo::Collection do
1216
1232
  end
1217
1233
  end
1218
1234
  end
1235
+
1236
+ context 'when the collection has a read preference', unless: sharded? do
1237
+
1238
+ before do
1239
+ allow(collection.client.cluster).to receive(:single?).and_return(false)
1240
+ end
1241
+
1242
+ after do
1243
+ client.close
1244
+ end
1245
+
1246
+ let(:client) do
1247
+ authorized_client.with(server_selection_timeout: 0.2)
1248
+ end
1249
+
1250
+ let(:collection) do
1251
+ client[authorized_collection.name,
1252
+ read: { :mode => :secondary, :tag_sets => [{ 'non' => 'existent' }] }]
1253
+ end
1254
+
1255
+ let(:result) do
1256
+ collection.parallel_scan(2)
1257
+ end
1258
+
1259
+ it 'uses that read preference' do
1260
+ expect {
1261
+ result
1262
+ }.to raise_exception(Mongo::Error::NoServerAvailable)
1263
+ end
1264
+ end
1219
1265
  end
1220
1266
 
1221
1267
  describe '#replace_one' do
@@ -232,6 +232,95 @@ describe Mongo::Cursor do
232
232
  end
233
233
  end
234
234
  end
235
+
236
+ context 'when the cursor is not fully iterated and is garbage collected' do
237
+
238
+ let(:documents) do
239
+ (1..3).map{ |i| { field: "test#{i}" }}
240
+ end
241
+
242
+ before do
243
+ authorized_collection.insert_many(documents)
244
+ cursor_reaper.schedule_kill_cursor(cursor.id,
245
+ cursor.send(:kill_cursors_op_spec),
246
+ cursor.instance_variable_get(:@server))
247
+ end
248
+
249
+ after do
250
+ authorized_collection.delete_many
251
+ end
252
+
253
+ let(:view) do
254
+ Mongo::Collection::View.new(
255
+ authorized_collection,
256
+ {},
257
+ :batch_size => 2
258
+ )
259
+ end
260
+
261
+ let!(:cursor) do
262
+ view.to_enum.next
263
+ view.instance_variable_get(:@cursor)
264
+ end
265
+
266
+ let(:cursor_reaper) do
267
+ authorized_client.cluster.instance_variable_get(:@cursor_reaper)
268
+ end
269
+
270
+
271
+ it 'schedules a kill cursors op' do
272
+ sleep(Mongo::Cluster::CursorReaper::FREQUENCY + 0.5)
273
+ expect {
274
+ cursor.to_a
275
+ }.to raise_exception(Mongo::Error::OperationFailure)
276
+ end
277
+
278
+ context 'when the cursor is unregistered before the kill cursors operations are executed' do
279
+
280
+ it 'does not send a kill cursors operation for the unregistered cursor' do
281
+ cursor_reaper.unregister_cursor(cursor.id)
282
+ expect(cursor.to_a.size).to eq(documents.size)
283
+ end
284
+ end
285
+ end
286
+
287
+ context 'when the cursor is fully iterated' do
288
+
289
+ let(:documents) do
290
+ (1..3).map{ |i| { field: "test#{i}" }}
291
+ end
292
+
293
+ before do
294
+ authorized_collection.insert_many(documents)
295
+ end
296
+
297
+ after do
298
+ authorized_collection.delete_many
299
+ end
300
+
301
+ let(:view) do
302
+ authorized_collection.find({}, batch_size: 2)
303
+ end
304
+
305
+ let!(:cursor_id) do
306
+ enum.next
307
+ enum.next
308
+ view.instance_variable_get(:@cursor).id
309
+ end
310
+
311
+ let(:enum) do
312
+ view.to_enum
313
+ end
314
+
315
+ let(:cursor_reaper) do
316
+ authorized_collection.client.cluster.instance_variable_get(:@cursor_reaper)
317
+ end
318
+
319
+ it 'removes the cursor id from the active cursors tracked by the cluster cursor manager' do
320
+ enum.next
321
+ expect(cursor_reaper.instance_variable_get(:@active_cursors)).not_to include(cursor_id)
322
+ end
323
+ end
235
324
  end
236
325
 
237
326
  describe '#inspect' do