mongo 2.4.3 → 2.5.0.beta

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 (235) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +3 -2
  3. data.tar.gz.sig +0 -0
  4. data/lib/mongo.rb +3 -2
  5. data/lib/mongo/auth/cr.rb +6 -4
  6. data/lib/mongo/auth/cr/conversation.rb +33 -17
  7. data/lib/mongo/auth/ldap.rb +4 -2
  8. data/lib/mongo/auth/ldap/conversation.rb +19 -9
  9. data/lib/mongo/auth/scram.rb +7 -4
  10. data/lib/mongo/auth/scram/conversation.rb +62 -24
  11. data/lib/mongo/auth/user.rb +10 -0
  12. data/lib/mongo/auth/user/view.rb +44 -22
  13. data/lib/mongo/auth/x509.rb +4 -2
  14. data/lib/mongo/auth/x509/conversation.rb +19 -9
  15. data/lib/mongo/bulk_write.rb +33 -27
  16. data/lib/mongo/bulk_write/combineable.rb +5 -0
  17. data/lib/mongo/bulk_write/transformable.rb +2 -0
  18. data/lib/mongo/bulk_write/validatable.rb +4 -0
  19. data/lib/mongo/client.rb +123 -12
  20. data/lib/mongo/cluster.rb +52 -11
  21. data/lib/mongo/cluster/app_metadata.rb +8 -2
  22. data/lib/mongo/cluster/cursor_reaper.rb +0 -1
  23. data/lib/mongo/cluster/topology.rb +1 -1
  24. data/lib/mongo/collection.rb +114 -27
  25. data/lib/mongo/collection/view.rb +8 -2
  26. data/lib/mongo/collection/view/aggregation.rb +11 -7
  27. data/lib/mongo/collection/view/builder/aggregation.rb +5 -1
  28. data/lib/mongo/collection/view/builder/find_command.rb +5 -3
  29. data/lib/mongo/collection/view/builder/map_reduce.rb +11 -3
  30. data/lib/mongo/collection/view/builder/op_query.rb +1 -1
  31. data/lib/mongo/collection/view/change_stream.rb +160 -0
  32. data/lib/mongo/collection/view/change_stream/retryable.rb +57 -0
  33. data/lib/mongo/collection/view/iterable.rb +11 -10
  34. data/lib/mongo/collection/view/map_reduce.rb +22 -18
  35. data/lib/mongo/collection/view/readable.rb +51 -37
  36. data/lib/mongo/collection/view/writable.rb +72 -40
  37. data/lib/mongo/cursor.rb +25 -4
  38. data/lib/mongo/cursor/builder/get_more_command.rb +4 -2
  39. data/lib/mongo/database.rb +22 -11
  40. data/lib/mongo/database/view.rb +16 -12
  41. data/lib/mongo/error.rb +5 -0
  42. data/lib/mongo/error/invalid_session.rb +36 -0
  43. data/lib/mongo/error/missing_resume_token.rb +39 -0
  44. data/lib/mongo/error/operation_failure.rb +17 -0
  45. data/lib/mongo/error/parser.rb +3 -2
  46. data/lib/mongo/error/unknown_payload_type.rb +41 -0
  47. data/lib/mongo/error/unsupported_array_filters.rb +51 -0
  48. data/lib/mongo/error/unsupported_message_type.rb +23 -0
  49. data/lib/mongo/grid/fs_bucket.rb +5 -4
  50. data/lib/mongo/grid/stream/read.rb +3 -2
  51. data/lib/mongo/grid/stream/write.rb +2 -2
  52. data/lib/mongo/index/view.rb +35 -25
  53. data/lib/mongo/monitoring/event/secure.rb +14 -0
  54. data/lib/mongo/operation.rb +16 -0
  55. data/lib/mongo/operation/commands.rb +1 -0
  56. data/lib/mongo/operation/commands/aggregate.rb +9 -5
  57. data/lib/mongo/operation/commands/aggregate/result.rb +1 -1
  58. data/lib/mongo/operation/commands/collections_info.rb +6 -6
  59. data/lib/mongo/operation/commands/command.rb +2 -1
  60. data/lib/mongo/operation/commands/create.rb +6 -2
  61. data/lib/mongo/operation/commands/drop.rb +6 -2
  62. data/lib/mongo/operation/commands/drop_database.rb +6 -2
  63. data/lib/mongo/operation/commands/explain.rb +27 -0
  64. data/lib/mongo/operation/commands/explain/result.rb +52 -0
  65. data/lib/mongo/operation/commands/indexes.rb +1 -1
  66. data/lib/mongo/operation/commands/list_collections.rb +1 -1
  67. data/lib/mongo/operation/commands/list_collections/result.rb +1 -1
  68. data/lib/mongo/operation/commands/list_indexes.rb +1 -1
  69. data/lib/mongo/operation/commands/list_indexes/result.rb +1 -1
  70. data/lib/mongo/operation/commands/map_reduce.rb +8 -4
  71. data/lib/mongo/operation/commands/map_reduce/result.rb +13 -1
  72. data/lib/mongo/operation/commands/user_query.rb +1 -1
  73. data/lib/mongo/operation/commands/users_info.rb +6 -2
  74. data/lib/mongo/operation/executable.rb +4 -1
  75. data/lib/mongo/operation/read_preference.rb +10 -5
  76. data/lib/mongo/operation/result.rb +26 -2
  77. data/lib/mongo/operation/specifiable.rb +13 -1
  78. data/lib/mongo/operation/uses_command_op_msg.rb +47 -0
  79. data/lib/mongo/operation/write/bulk/bulkable.rb +4 -1
  80. data/lib/mongo/operation/write/bulk/insert/result.rb +4 -4
  81. data/lib/mongo/operation/write/command/create_index.rb +6 -1
  82. data/lib/mongo/operation/write/command/delete.rb +28 -4
  83. data/lib/mongo/operation/write/command/drop_index.rb +6 -1
  84. data/lib/mongo/operation/write/command/insert.rb +22 -18
  85. data/lib/mongo/operation/write/command/update.rb +24 -9
  86. data/lib/mongo/operation/write/command/writable.rb +14 -1
  87. data/lib/mongo/operation/write/insert.rb +4 -1
  88. data/lib/mongo/operation/write/insert/result.rb +2 -2
  89. data/lib/mongo/operation/write/update.rb +7 -1
  90. data/lib/mongo/operation/write/write_command_enabled.rb +20 -3
  91. data/lib/mongo/protocol.rb +3 -0
  92. data/lib/mongo/protocol/bit_vector.rb +2 -2
  93. data/lib/mongo/protocol/compressed.rb +135 -0
  94. data/lib/mongo/protocol/delete.rb +8 -6
  95. data/lib/mongo/protocol/get_more.rb +8 -6
  96. data/lib/mongo/protocol/insert.rb +8 -6
  97. data/lib/mongo/protocol/kill_cursors.rb +8 -6
  98. data/lib/mongo/protocol/message.rb +31 -3
  99. data/lib/mongo/protocol/msg.rb +172 -0
  100. data/lib/mongo/protocol/query.rb +26 -6
  101. data/lib/mongo/protocol/registry.rb +76 -0
  102. data/lib/mongo/protocol/reply.rb +10 -5
  103. data/lib/mongo/protocol/serializers.rb +224 -0
  104. data/lib/mongo/protocol/update.rb +8 -6
  105. data/lib/mongo/retryable.rb +4 -2
  106. data/lib/mongo/server.rb +6 -3
  107. data/lib/mongo/server/connectable.rb +1 -1
  108. data/lib/mongo/server/connection.rb +30 -8
  109. data/lib/mongo/server/description.rb +25 -1
  110. data/lib/mongo/server/description/features.rb +4 -1
  111. data/lib/mongo/server/monitor.rb +5 -0
  112. data/lib/mongo/server/monitor/connection.rb +50 -2
  113. data/lib/mongo/server_selector/nearest.rb +10 -4
  114. data/lib/mongo/server_selector/primary.rb +20 -0
  115. data/lib/mongo/server_selector/primary_preferred.rb +10 -4
  116. data/lib/mongo/server_selector/secondary.rb +10 -4
  117. data/lib/mongo/server_selector/secondary_preferred.rb +24 -4
  118. data/lib/mongo/session.rb +180 -0
  119. data/lib/mongo/session/server_session.rb +73 -0
  120. data/lib/mongo/session/session_pool.rb +161 -0
  121. data/lib/mongo/uri.rb +11 -0
  122. data/lib/mongo/version.rb +1 -1
  123. data/mongo.gemspec +2 -1
  124. data/spec/mongo/auth/cr_spec.rb +12 -0
  125. data/spec/mongo/auth/ldap_spec.rb +2 -0
  126. data/spec/mongo/auth/scram/conversation_spec.rb +6 -6
  127. data/spec/mongo/auth/scram_spec.rb +25 -1
  128. data/spec/mongo/auth/user/view_spec.rb +268 -76
  129. data/spec/mongo/auth/x509_spec.rb +2 -0
  130. data/spec/mongo/bulk_write_spec.rb +435 -5
  131. data/spec/mongo/client_spec.rb +356 -39
  132. data/spec/mongo/cluster/app_metadata_spec.rb +2 -2
  133. data/spec/mongo/cluster_spec.rb +176 -0
  134. data/spec/mongo/collection/view/aggregation_spec.rb +33 -12
  135. data/spec/mongo/collection/view/builder/find_command_spec.rb +46 -6
  136. data/spec/mongo/collection/view/change_stream_spec.rb +814 -0
  137. data/spec/mongo/collection/view/map_reduce_spec.rb +94 -17
  138. data/spec/mongo/collection/view/readable_spec.rb +3 -12
  139. data/spec/mongo/collection_spec.rb +1048 -42
  140. data/spec/mongo/cursor/builder/get_more_command_spec.rb +19 -0
  141. data/spec/mongo/cursor_spec.rb +2 -2
  142. data/spec/mongo/database_spec.rb +50 -1
  143. data/spec/mongo/grid/fs_bucket_spec.rb +225 -137
  144. data/spec/mongo/grid/stream/read_spec.rb +2 -2
  145. data/spec/mongo/index/view_spec.rb +146 -8
  146. data/spec/mongo/monitoring/event/secure_spec.rb +42 -0
  147. data/spec/mongo/operation/read/query_spec.rb +2 -1
  148. data/spec/mongo/operation/specifiable_spec.rb +2 -2
  149. data/spec/mongo/operation/write/command/delete_spec.rb +96 -13
  150. data/spec/mongo/operation/write/command/insert_spec.rb +111 -12
  151. data/spec/mongo/operation/write/command/update_spec.rb +93 -10
  152. data/spec/mongo/operation/write/delete_spec.rb +1 -1
  153. data/spec/mongo/operation/write/insert_spec.rb +1 -1
  154. data/spec/mongo/operation/write/update_spec.rb +1 -1
  155. data/spec/mongo/protocol/compressed_spec.rb +66 -0
  156. data/spec/mongo/protocol/delete_spec.rb +14 -0
  157. data/spec/mongo/protocol/get_more_spec.rb +14 -0
  158. data/spec/mongo/protocol/insert_spec.rb +14 -0
  159. data/spec/mongo/protocol/kill_cursors_spec.rb +14 -0
  160. data/spec/mongo/protocol/msg_spec.rb +499 -0
  161. data/spec/mongo/protocol/query_spec.rb +45 -0
  162. data/spec/mongo/protocol/registry_spec.rb +31 -0
  163. data/spec/mongo/protocol/reply_spec.rb +14 -0
  164. data/spec/mongo/protocol/update_spec.rb +14 -0
  165. data/spec/mongo/retryable_spec.rb +6 -2
  166. data/spec/mongo/sdam_spec.rb +4 -0
  167. data/spec/mongo/server/connection_spec.rb +4 -2
  168. data/spec/mongo/server/description_spec.rb +28 -1
  169. data/spec/mongo/session/server_session_spec.rb +16 -0
  170. data/spec/mongo/session/session_pool_spec.rb +194 -0
  171. data/spec/mongo/uri_spec.rb +31 -2
  172. data/spec/spec_helper.rb +104 -0
  173. data/spec/support/authorization.rb +6 -1
  174. data/spec/support/crud.rb +3 -1
  175. data/spec/support/crud/write.rb +6 -1
  176. data/spec/support/crud_tests/write/findOneAndUpdate-arrayFilters.yml +69 -0
  177. data/spec/support/crud_tests/write/updateMany-arrayFilters.yml +63 -0
  178. data/spec/support/crud_tests/write/updateOne-arrayFilters.yml +109 -0
  179. data/spec/support/sdam/rs/discover_arbiters.yml +1 -1
  180. data/spec/support/sdam/rs/discover_passives.yml +2 -2
  181. data/spec/support/sdam/rs/discover_primary.yml +1 -1
  182. data/spec/support/sdam/rs/discover_secondary.yml +1 -1
  183. data/spec/support/sdam/rs/discovery.yml +4 -4
  184. data/spec/support/sdam/rs/equal_electionids.yml +1 -0
  185. data/spec/support/sdam/rs/ghost_discovered.yml +1 -1
  186. data/spec/support/sdam/rs/hosts_differ_from_seeds.yml +1 -1
  187. data/spec/support/sdam/rs/ls_timeout.yml +88 -0
  188. data/spec/support/sdam/rs/member_reconfig.yml +2 -2
  189. data/spec/support/sdam/rs/member_standalone.yml +2 -2
  190. data/spec/support/sdam/rs/new_primary.yml +2 -2
  191. data/spec/support/sdam/rs/new_primary_new_electionid.yml +3 -0
  192. data/spec/support/sdam/rs/new_primary_new_setversion.yml +3 -0
  193. data/spec/support/sdam/rs/new_primary_wrong_set_name.yml +2 -2
  194. data/spec/support/sdam/rs/non_rs_member.yml +1 -1
  195. data/spec/support/sdam/rs/normalize_case.yml +1 -1
  196. data/spec/support/sdam/rs/null_election_id.yml +4 -0
  197. data/spec/support/sdam/rs/primary_becomes_standalone.yml +2 -2
  198. data/spec/support/sdam/rs/primary_changes_set_name.yml +2 -2
  199. data/spec/support/sdam/rs/primary_disconnect.yml +2 -2
  200. data/spec/support/sdam/rs/primary_disconnect_electionid.yml +5 -0
  201. data/spec/support/sdam/rs/primary_disconnect_setversion.yml +5 -0
  202. data/spec/support/sdam/rs/primary_hint_from_secondary_with_mismatched_me.yml +58 -0
  203. data/spec/support/sdam/rs/primary_reports_new_member.yml +4 -4
  204. data/spec/support/sdam/rs/primary_to_no_primary_mismatched_me.yml +2 -2
  205. data/spec/support/sdam/rs/primary_wrong_set_name.yml +1 -1
  206. data/spec/support/sdam/rs/response_from_removed.yml +2 -2
  207. data/spec/support/sdam/rs/rsother_discovered.yml +1 -1
  208. data/spec/support/sdam/rs/sec_not_auth.yml +1 -1
  209. data/spec/support/sdam/rs/secondary_wrong_set_name.yml +1 -1
  210. data/spec/support/sdam/rs/secondary_wrong_set_name_with_primary.yml +2 -2
  211. data/spec/support/sdam/rs/setversion_without_electionid.yml +2 -0
  212. data/spec/support/sdam/rs/stepdown_change_set_name.yml +2 -2
  213. data/spec/support/sdam/rs/unexpected_mongos.yml +1 -1
  214. data/spec/support/sdam/rs/use_setversion_without_electionid.yml +3 -0
  215. data/spec/support/sdam/rs/wrong_set_name.yml +1 -1
  216. data/spec/support/sdam/sharded/ls_timeout_mongos.yml +97 -0
  217. data/spec/support/sdam/sharded/mongos_disconnect.yml +3 -3
  218. data/spec/support/sdam/sharded/multiple_mongoses.yml +1 -1
  219. data/spec/support/sdam/sharded/non_mongos_removed.yml +1 -1
  220. data/spec/support/sdam/sharded/normalize_uri_case.yml +1 -1
  221. data/spec/support/sdam/single/direct_connection_external_ip.yml +1 -1
  222. data/spec/support/sdam/single/direct_connection_mongos.yml +1 -1
  223. data/spec/support/sdam/single/direct_connection_rsarbiter.yml +1 -1
  224. data/spec/support/sdam/single/direct_connection_rsprimary.yml +1 -1
  225. data/spec/support/sdam/single/direct_connection_rssecondary.yml +1 -1
  226. data/spec/support/sdam/single/direct_connection_slave.yml +1 -1
  227. data/spec/support/sdam/single/direct_connection_standalone.yml +1 -1
  228. data/spec/support/sdam/single/ls_timeout_standalone.yml +35 -0
  229. data/spec/support/sdam/single/not_ok_response.yml +1 -1
  230. data/spec/support/sdam/single/standalone_removed.yml +1 -1
  231. data/spec/support/sdam/single/unavailable_seed.yml +1 -1
  232. data/spec/support/server_discovery_and_monitoring.rb +4 -0
  233. data/spec/support/shared/session.rb +236 -0
  234. metadata +53 -15
  235. metadata.gz.sig +0 -0
@@ -218,6 +218,119 @@ describe Mongo::Client do
218
218
 
219
219
  context 'when providing options' do
220
220
 
221
+ context 'when compressors are provided' do
222
+
223
+ let(:client) do
224
+ described_class.new([default_address.seed], authorized_client.options.merge(options))
225
+ end
226
+
227
+ after do
228
+ client.close
229
+ end
230
+
231
+ context 'when the compressor is supported' do
232
+
233
+ let(:options) do
234
+ { compressors: ['zlib'] }
235
+ end
236
+
237
+ it 'sets the compressor' do
238
+ expect(client.options['compressors']).to eq(options[:compressors])
239
+ end
240
+
241
+ it 'sends the compressor in the compression key of the handshake document' do
242
+ expect(client.cluster.app_metadata.send(:document)[:compression]).to eq(options[:compressors])
243
+ end
244
+
245
+ it 'uses compression for messages', if: testing_compression? do
246
+ expect(Mongo::Protocol::Compressed).to receive(:new).and_call_original
247
+ client[TEST_COLL].find({}, limit: 1).first
248
+ end
249
+
250
+ it 'does not use compression for authentication messages' do
251
+ expect(Mongo::Protocol::Compressed).not_to receive(:new)
252
+ client.cluster.next_primary.send(:with_connection) do |conn|
253
+ conn.send(:authenticate!)
254
+ end
255
+ end
256
+ end
257
+
258
+ context 'when the compressor is not supported by the driver' do
259
+
260
+ let(:options) do
261
+ { compressors: ['snoopy'] }
262
+ end
263
+
264
+ it 'does not set the compressor and warns' do
265
+ expect(Mongo::Logger.logger).to receive(:warn)
266
+ expect(client.options['compressors']).to be_nil
267
+ end
268
+
269
+ it 'sets the compression key of the handshake document to an empty array' do
270
+ expect(client.cluster.app_metadata.send(:document)[:compression]).to eq([])
271
+ end
272
+
273
+ context 'when one supported compressor and one unsupported compressor are provided', if: compression_enabled? do
274
+
275
+ let(:options) do
276
+ { compressors: ['zlib', 'snoopy'] }
277
+ end
278
+
279
+ it 'does not set the unsupported compressor and warns' do
280
+ expect(Mongo::Logger.logger).to receive(:warn).at_least(:once)
281
+ expect(client.options['compressors']).to eq(['zlib'])
282
+ end
283
+
284
+ it 'sets the compression key of the handshake document to the list of supported compressors' do
285
+ expect(client.cluster.app_metadata.send(:document)[:compression]).to eq(['zlib'])
286
+ end
287
+ end
288
+ end
289
+
290
+ context 'when the compressor is not supported by the server', unless: collation_enabled? do
291
+
292
+ let(:options) do
293
+ { compressors: ['zlib'] }
294
+ end
295
+
296
+ it 'does not set the compressor and warns' do
297
+ expect(Mongo::Logger.logger).to receive(:warn).at_least(:once)
298
+ expect(client.cluster.next_primary.monitor.compressor).to be_nil
299
+ end
300
+ end
301
+ end
302
+
303
+ context 'when compressors are not provided', unless: compression_enabled? do
304
+
305
+ let(:client) do
306
+ authorized_client
307
+ end
308
+
309
+ it 'does not set the compressor' do
310
+ expect(client.options['compressors']).to be_nil
311
+ end
312
+
313
+ it 'sets the compression key of the handshake document to an empty array' do
314
+ expect(client.cluster.app_metadata.send(:document)[:compression]).to eq([])
315
+ end
316
+
317
+ it 'does not use compression for messages' do
318
+ client[TEST_COLL].find({}, limit: 1).first
319
+ expect(Mongo::Protocol::Compressed).not_to receive(:new)
320
+ end
321
+ end
322
+
323
+ context 'when a zlib_compression_level option is provided', if: testing_compression? do
324
+
325
+ let(:client) do
326
+ described_class.new([default_address.seed], TEST_OPTIONS.merge(zlib_compression_level: 1))
327
+ end
328
+
329
+ it 'sets the option on the client' do
330
+ expect(client.options[:zlib_compression_level]).to eq(1)
331
+ end
332
+ end
333
+
221
334
  context 'when ssl options are provided' do
222
335
 
223
336
  let(:options) do
@@ -444,6 +557,25 @@ describe Mongo::Client do
444
557
  end
445
558
  end
446
559
 
560
+ context 'when max_pool_size and min_pool_size are both nil' do
561
+
562
+ let(:client) do
563
+ described_class.new(['127.0.0.1:27017'], options)
564
+ end
565
+
566
+ let(:options) do
567
+ {
568
+ :min_pool_size => nil,
569
+ :max_pool_size => nil
570
+ }
571
+ end
572
+
573
+ it 'does not set either option' do
574
+ expect(client.options[:max_pool_size]).to be_nil
575
+ expect(client.options[:min_pool_size]).to be_nil
576
+ end
577
+ end
578
+
447
579
  context 'when platform details are specified' do
448
580
 
449
581
  let(:app_metadata) do
@@ -690,6 +822,122 @@ describe Mongo::Client do
690
822
  end
691
823
  end
692
824
 
825
+ describe '#server_selector' do
826
+
827
+ context 'when there is a read preference set' do
828
+
829
+ let(:client) do
830
+ described_class.new(['127.0.0.1:27017'],
831
+ :database => TEST_DB,
832
+ :read => mode,
833
+ :server_selection_timeout => 2)
834
+ end
835
+
836
+ let(:server_selector) do
837
+ client.server_selector
838
+ end
839
+
840
+ context 'when mode is primary' do
841
+
842
+ let(:mode) do
843
+ { :mode => :primary }
844
+ end
845
+
846
+ it 'returns a primary server selector' do
847
+ expect(server_selector).to be_a(Mongo::ServerSelector::Primary)
848
+ end
849
+
850
+ it 'passes the options to the cluster' do
851
+ expect(client.cluster.options[:server_selection_timeout]).to eq(2)
852
+ end
853
+ end
854
+
855
+ context 'when mode is primary_preferred' do
856
+
857
+ let(:mode) do
858
+ { :mode => :primary_preferred }
859
+ end
860
+
861
+ it 'returns a primary preferred server selector' do
862
+ expect(server_selector).to be_a(Mongo::ServerSelector::PrimaryPreferred)
863
+ end
864
+ end
865
+
866
+ context 'when mode is secondary' do
867
+
868
+ let(:mode) do
869
+ { :mode => :secondary }
870
+ end
871
+
872
+ it 'uses a Secondary server selector' do
873
+ expect(server_selector).to be_a(Mongo::ServerSelector::Secondary)
874
+ end
875
+ end
876
+
877
+ context 'when mode is secondary preferred' do
878
+
879
+ let(:mode) do
880
+ { :mode => :secondary_preferred }
881
+ end
882
+
883
+ it 'uses a Secondary server selector' do
884
+ expect(server_selector).to be_a(Mongo::ServerSelector::SecondaryPreferred)
885
+ end
886
+ end
887
+
888
+ context 'when mode is nearest' do
889
+
890
+ let(:mode) do
891
+ { :mode => :nearest }
892
+ end
893
+
894
+ it 'uses a Secondary server selector' do
895
+ expect(server_selector).to be_a(Mongo::ServerSelector::Nearest)
896
+ end
897
+ end
898
+
899
+ context 'when no mode provided' do
900
+
901
+ let(:client) do
902
+ described_class.new(['127.0.0.1:27017'],
903
+ :database => TEST_DB,
904
+ :server_selection_timeout => 2)
905
+ end
906
+
907
+ it 'returns a primary server selector' do
908
+ expect(server_selector).to be_a(Mongo::ServerSelector::Primary)
909
+ end
910
+ end
911
+
912
+ context 'when the read preference is printed' do
913
+
914
+ let(:client) do
915
+ described_class.new([ default_address.to_s ], options)
916
+ end
917
+
918
+ let(:options) do
919
+ { user: 'Emily', password: 'sensitive_data', server_selection_timeout: 0.1 }
920
+ end
921
+
922
+ before do
923
+ allow(client.database.cluster).to receive(:single?).and_return(false)
924
+ end
925
+
926
+ let(:error) do
927
+ begin
928
+ client.database.command(ping: 1)
929
+ rescue => e
930
+ e
931
+ end
932
+ end
933
+
934
+ it 'redacts sensitive client options' do
935
+ expect(error.message).not_to match(options[:password])
936
+ end
937
+ end
938
+ end
939
+ end
940
+
693
941
  describe '#read_preference' do
694
942
 
695
943
  let(:client) do
@@ -710,11 +958,7 @@ describe Mongo::Client do
710
958
  end
711
959
 
712
960
  it 'returns a primary read preference' do
713
- expect(preference).to be_a(Mongo::ServerSelector::Primary)
714
- end
715
-
716
- it 'passes the options to the cluster' do
717
- expect(client.cluster.options[:server_selection_timeout]).to eq(2)
961
+ expect(preference).to eq(BSON::Document.new(mode))
718
962
  end
719
963
  end
720
964
 
@@ -725,7 +969,7 @@ describe Mongo::Client do
725
969
  end
726
970
 
727
971
  it 'returns a primary preferred read preference' do
728
- expect(preference).to be_a(Mongo::ServerSelector::PrimaryPreferred)
972
+ expect(preference).to eq(BSON::Document.new(mode))
729
973
  end
730
974
  end
731
975
 
@@ -736,7 +980,7 @@ describe Mongo::Client do
736
980
  end
737
981
 
738
982
  it 'returns a secondary read preference' do
739
- expect(preference).to be_a(Mongo::ServerSelector::Secondary)
983
+ expect(preference).to eq(BSON::Document.new(mode))
740
984
  end
741
985
  end
742
986
 
@@ -747,7 +991,7 @@ describe Mongo::Client do
747
991
  end
748
992
 
749
993
  it 'returns a secondary preferred read preference' do
750
- expect(preference).to be_a(Mongo::ServerSelector::SecondaryPreferred)
994
+ expect(preference).to eq(BSON::Document.new(mode))
751
995
  end
752
996
  end
753
997
 
@@ -758,45 +1002,20 @@ describe Mongo::Client do
758
1002
  end
759
1003
 
760
1004
  it 'returns a nearest read preference' do
761
- expect(preference).to be_a(Mongo::ServerSelector::Nearest)
1005
+ expect(preference).to eq(BSON::Document.new(mode))
762
1006
  end
763
1007
  end
764
1008
 
765
1009
  context 'when no mode provided' do
766
1010
 
767
- let(:mode) do
768
- {}
769
- end
770
-
771
- it 'returns a primary read preference' do
772
- expect(preference).to be_a(Mongo::ServerSelector::Primary)
773
- end
774
- end
775
-
776
- context 'when the read preference is printed' do
777
-
778
1011
  let(:client) do
779
- described_class.new([ default_address.to_s ], options)
1012
+ described_class.new(['127.0.0.1:27017'],
1013
+ :database => TEST_DB,
1014
+ :server_selection_timeout => 2)
780
1015
  end
781
1016
 
782
- let(:options) do
783
- { user: 'Emily', password: 'sensitive_data', server_selection_timeout: 0.1 }
784
- end
785
-
786
- before do
787
- allow(client.database.cluster).to receive(:single?).and_return(false)
788
- end
789
-
790
- let(:error) do
791
- begin
792
- client.database.command(ping: 1)
793
- rescue => e
794
- e
795
- end
796
- end
797
-
798
- it 'redacts sensitive client options' do
799
- expect(error.message).not_to match(options[:password])
1017
+ it 'returns nil' do
1018
+ expect(preference).to be_nil
800
1019
  end
801
1020
  end
802
1021
  end
@@ -1133,4 +1352,102 @@ describe Mongo::Client do
1133
1352
  expect(authorized_client.collections).to all(be_a(Mongo::Collection))
1134
1353
  end
1135
1354
  end
1355
+
1356
+ describe '#start_session' do
1357
+
1358
+ let(:session) do
1359
+ authorized_client.start_session
1360
+ end
1361
+
1362
+ context 'when sessions are supported', if: sessions_enabled? do
1363
+
1364
+ it 'creates a session' do
1365
+ expect(session).to be_a(Mongo::Session)
1366
+ end
1367
+
1368
+ it 'sets the last use field to the current time' do
1369
+ expect(session.instance_variable_get(:@server_session).last_use).to be_within(0.2).of(Time.now)
1370
+ end
1371
+
1372
+ context 'when options are provided' do
1373
+
1374
+ let(:options) do
1375
+ { causally_consistent: true }
1376
+ end
1377
+
1378
+ let(:session) do
1379
+ authorized_client.start_session(options)
1380
+ end
1381
+
1382
+ it 'sets the options on the session' do
1383
+ expect(session.options).to eq(options)
1384
+ end
1385
+ end
1386
+
1387
+ context 'when options are not provided' do
1388
+
1389
+ it 'does not set options on the session' do
1390
+ expect(session.options).to be_empty
1391
+ end
1392
+ end
1393
+
1394
+ context 'when a session is checked out and checked back in' do
1395
+
1396
+ let!(:session_a) do
1397
+ authorized_client.start_session
1398
+ end
1399
+
1400
+ let!(:session_b) do
1401
+ authorized_client.start_session
1402
+ end
1403
+
1404
+ let!(:session_a_server_session) do
1405
+ session_a.instance_variable_get(:@server_session)
1406
+ end
1407
+
1408
+ let!(:session_b_server_session) do
1409
+ session_b.instance_variable_get(:@server_session)
1410
+ end
1411
+
1412
+ before do
1413
+ session_a.end_session
1414
+ session_b.end_session
1415
+ end
1416
+
1417
+ it 'is returned to the front of the queue' do
1418
+ expect(authorized_client.start_session.instance_variable_get(:@server_session)).to be(session_b_server_session)
1419
+ expect(authorized_client.start_session.instance_variable_get(:@server_session)).to be(session_a_server_session)
1420
+ end
1421
+ end
1422
+
1423
+ context 'when an implicit session is used' do
1424
+
1425
+ before do
1426
+ authorized_client.database.command(ping: 1)
1427
+ end
1428
+
1429
+ let(:pool) do
1430
+ authorized_client.instance_variable_get(:@session_pool)
1431
+ end
1432
+
1433
+ let!(:before_last_use) do
1434
+ pool.instance_variable_get(:@queue)[0].last_use
1435
+ end
1436
+
1437
+ it 'uses the session and updates the last use time' do
1438
+ authorized_client.database.command(ping: 1)
1439
+ expect(before_last_use).to be < (pool.instance_variable_get(:@queue)[0].last_use)
1440
+ end
1441
+ end
1442
+ end
1443
+
1444
+ context 'when sessions are not supported', unless: sessions_enabled? do
1445
+
1446
+ it 'raises an exception' do
1447
+ expect {
1448
+ session
1449
+ }.to raise_exception(Mongo::Error::InvalidSession)
1450
+ end
1451
+ end
1452
+ end
1136
1453
  end