mongo 2.2.7 → 2.3.0

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 (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