mongo 2.4.3 → 2.5.0.beta

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -296,4 +296,49 @@ describe Mongo::Protocol::Query do
296
296
  end
297
297
  end
298
298
  end
299
+
300
+ describe '#registry' do
301
+
302
+ context 'when the class is loaded' do
303
+
304
+ it 'registers the op code in the Protocol Registry' do
305
+ expect(Mongo::Protocol::Registry.get(described_class::OP_CODE)).to be(described_class)
306
+ end
307
+
308
+ it 'creates an #op_code instance method' do
309
+ expect(message.op_code).to eq(described_class::OP_CODE)
310
+ end
311
+ end
312
+ end
313
+
314
+ describe '#compress' do
315
+
316
+ context 'when the selector represents a command that can be compressed' do
317
+
318
+ let(:selector) do
319
+ { ping: 1 }
320
+ end
321
+
322
+ it 'returns a compressed message' do
323
+ expect(message.compress!('zlib')).to be_a(Mongo::Protocol::Compressed)
324
+ end
325
+ end
326
+
327
+ context 'when the selector represents a command for which compression is not allowed' do
328
+
329
+ Mongo::Monitoring::Event::Secure::REDACTED_COMMANDS.each do |command|
330
+
331
+ let(:selector) do
332
+ { command => 1 }
333
+ end
334
+
335
+ context "when the command is #{command}" do
336
+
337
+ it 'does not allow compression for the command' do
338
+ expect(message.compress!('zlib')).to be(message)
339
+ end
340
+ end
341
+ end
342
+ end
343
+ end
299
344
  end
@@ -0,0 +1,31 @@
1
+ require "spec_helper"
2
+
3
+ describe Mongo::Protocol::Registry do
4
+
5
+ describe ".get" do
6
+
7
+ context "when the type has a correspoding class" do
8
+
9
+ before do
10
+ described_class.register(Mongo::Protocol::Query::OP_CODE, Mongo::Protocol::Query)
11
+ end
12
+
13
+ let(:klass) do
14
+ described_class.get(Mongo::Protocol::Query::OP_CODE, "message")
15
+ end
16
+
17
+ it "returns the class" do
18
+ expect(klass).to eq(Mongo::Protocol::Query)
19
+ end
20
+ end
21
+
22
+ context "when the type has no corresponding class" do
23
+
24
+ it "raises an error" do
25
+ expect {
26
+ described_class.get(-100)
27
+ }.to raise_error(Mongo::Error::UnsupportedMessageType)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -178,4 +178,18 @@ describe Mongo::Protocol::Reply do
178
178
  end
179
179
  end
180
180
  end
181
+
182
+ describe '#registry' do
183
+
184
+ context 'when the class is loaded' do
185
+
186
+ it 'registers the op code in the Protocol Registry' do
187
+ expect(Mongo::Protocol::Registry.get(described_class::OP_CODE)).to be(described_class)
188
+ end
189
+
190
+ it 'creates an #op_code instance method' do
191
+ expect(reply.op_code).to eq(described_class::OP_CODE)
192
+ end
193
+ end
194
+ end
181
195
  end
@@ -183,4 +183,18 @@ describe Mongo::Protocol::Update do
183
183
  end
184
184
  end
185
185
  end
186
+
187
+ describe '#registry' do
188
+
189
+ context 'when the class is loaded' do
190
+
191
+ it 'registers the op code in the Protocol Registry' do
192
+ expect(Mongo::Protocol::Registry.get(described_class::OP_CODE)).to be(described_class)
193
+ end
194
+
195
+ it 'creates an #op_code instance method' do
196
+ expect(message.op_code).to eq(described_class::OP_CODE)
197
+ end
198
+ end
199
+ end
186
200
  end
@@ -29,7 +29,7 @@ describe Mongo::Retryable do
29
29
  end
30
30
 
31
31
  def write
32
- write_with_retry do
32
+ write_with_retry(nil, Proc.new { cluster.next_primary }) do
33
33
  operation.execute
34
34
  end
35
35
  end
@@ -41,7 +41,11 @@ describe Mongo::Retryable do
41
41
  end
42
42
 
43
43
  let(:cluster) do
44
- double('cluster')
44
+ double('cluster', next_primary: server_selector)
45
+ end
46
+
47
+ let(:server_selector) do
48
+ double('server_selector', select_server: double('server'))
45
49
  end
46
50
 
47
51
  let(:retryable) do
@@ -63,6 +63,10 @@ describe 'Server Discovery and Monitoring' do
63
63
  expect(@client.cluster.replica_set_name).to eq(phase.outcome.set_name)
64
64
  end
65
65
 
66
+ it "sets the cluster logical session timeout minutes to #{phase.outcome.logical_session_timeout.inspect}" do
67
+ expect(@client.cluster.logical_session_timeout).to eq(phase.outcome.logical_session_timeout)
68
+ end
69
+
66
70
  it "has the expected servers in the cluster" do
67
71
  expect(cluster_addresses).to eq(phase_addresses)
68
72
  end
@@ -22,6 +22,8 @@ describe Mongo::Server::Connection do
22
22
  double('cluster').tap do |cl|
23
23
  allow(cl).to receive(:topology).and_return(topology)
24
24
  allow(cl).to receive(:app_metadata).and_return(app_metadata)
25
+ allow(cl).to receive(:cluster_time).and_return(nil)
26
+ allow(cl).to receive(:update_cluster_time)
25
27
  end
26
28
  end
27
29
 
@@ -334,11 +336,11 @@ describe Mongo::Server::Connection do
334
336
  it 'closes the socket and does not use it for subsequent requests' do
335
337
  t = Thread.new {
336
338
  # Kill the thread just before the reply is read
337
- allow(Mongo::Protocol::Reply).to receive(:deserialize_header) { t.kill }
339
+ allow(Mongo::Protocol::Message).to receive(:deserialize_header) { t.kill }
338
340
  connection.dispatch([ query_bob ])
339
341
  }
340
342
  t.join
341
- allow(Mongo::Protocol::Reply).to receive(:deserialize_header).and_call_original
343
+ allow(Mongo::Protocol::Message).to receive(:deserialize_header).and_call_original
342
344
  expect(connection.dispatch([ query_alice ]).documents.first['name']).to eq('alice')
343
345
  end
344
346
  end
@@ -24,6 +24,7 @@ describe Mongo::Server::Description do
24
24
  'minWireVersion' => 0,
25
25
  'localTime' => Time.now,
26
26
  'lastWrite' => { 'lastWriteDate' => Time.now },
27
+ 'logicalSessionTimeoutMinutes' => 7,
27
28
  'ok' => 1
28
29
  }
29
30
  end
@@ -832,6 +833,31 @@ describe Mongo::Server::Description do
832
833
  end
833
834
  end
834
835
 
836
+ describe '#logical_session_timeout_minutes' do
837
+
838
+ context 'when a logical session timeout value is in the config' do
839
+
840
+ let(:description) do
841
+ described_class.new(address, replica)
842
+ end
843
+
844
+ it 'returns the logical session timeout value' do
845
+ expect(description.logical_session_timeout).to eq(7)
846
+ end
847
+ end
848
+
849
+ context 'when a logical session timeout value is not in the config' do
850
+
851
+ let(:description) do
852
+ described_class.new(address, { 'ismaster' => true, 'ok' => 1 })
853
+ end
854
+
855
+ it 'returns nil' do
856
+ expect(description.logical_session_timeout).to be(nil)
857
+ end
858
+ end
859
+ end
860
+
835
861
  describe '#==' do
836
862
 
837
863
  let(:description) do
@@ -841,7 +867,8 @@ describe Mongo::Server::Description do
841
867
  let(:other) do
842
868
  described_class.new(address, replica.merge(
843
869
  'localTime' => 1,
844
- 'lastWrite' => { 'lastWriteDate' => 1 }
870
+ 'lastWrite' => { 'lastWriteDate' => 1 },
871
+ 'operationTime' => 1
845
872
  ))
846
873
  end
847
874
 
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mongo::Session::ServerSession do
4
+
5
+ describe '#initialize' do
6
+
7
+ it 'sets the last use variable to the current time' do
8
+ expect(described_class.new.last_use).to be_within(0.2).of(Time.now)
9
+ end
10
+
11
+ it 'sets a UUID as the session id' do
12
+ expect(described_class.new.session_id).to be_a(BSON::Document)
13
+ expect(described_class.new.session_id[:id]).to be_a(BSON::Binary)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,194 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mongo::Session::SessionPool do
4
+
5
+ describe '.create' do
6
+
7
+ let(:client) do
8
+ authorized_client
9
+ end
10
+
11
+ let!(:pool) do
12
+ described_class.create(client)
13
+ end
14
+
15
+ it 'creates a session pool' do
16
+ expect(pool).to be_a(Mongo::Session::SessionPool)
17
+ end
18
+
19
+ it 'adds the pool as an instance variable on the client' do
20
+ expect(client.instance_variable_get(:@session_pool)).to eq(pool)
21
+ end
22
+ end
23
+
24
+ describe '#initialize' do
25
+
26
+ let(:pool) do
27
+ described_class.new(authorized_client)
28
+ end
29
+
30
+ it 'sets the client' do
31
+ expect(pool.instance_variable_get(:@client)).to be(authorized_client)
32
+ end
33
+ end
34
+
35
+ describe 'checkout', if: sessions_enabled? do
36
+
37
+ let(:pool) do
38
+ described_class.new(authorized_client)
39
+ end
40
+
41
+ context 'when a session is checked out' do
42
+
43
+ let!(:session_a) do
44
+ pool.checkout
45
+ end
46
+
47
+ let!(:session_b) do
48
+ pool.checkout
49
+ end
50
+
51
+ before do
52
+ pool.checkin(session_a)
53
+ pool.checkin(session_b)
54
+ end
55
+
56
+ it 'is returned to the front of the queue' do
57
+ expect(pool.checkout).to be(session_b)
58
+ expect(pool.checkout).to be(session_a)
59
+ end
60
+ end
61
+
62
+ context 'when there are sessions about to expire in the queue' do
63
+
64
+ let(:old_session_a) do
65
+ pool.checkout
66
+ end
67
+
68
+ let(:old_session_b) do
69
+ pool.checkout
70
+ end
71
+
72
+ before do
73
+ pool.checkin(old_session_a)
74
+ pool.checkin(old_session_b)
75
+ allow(old_session_a).to receive(:last_use).and_return(Time.now - 1800)
76
+ allow(old_session_b).to receive(:last_use).and_return(Time.now - 1800)
77
+ end
78
+
79
+ context 'when a session is checked out' do
80
+
81
+ let(:checked_out_session) do
82
+ pool.checkout
83
+ end
84
+
85
+ it 'disposes of the old session and returns a new one' do
86
+ expect(checked_out_session).not_to be(old_session_a)
87
+ expect(checked_out_session).not_to be(old_session_b)
88
+ expect(pool.instance_variable_get(:@queue)).to be_empty
89
+ end
90
+ end
91
+ end
92
+
93
+ context 'when a sessions that is about to expire is checked in' do
94
+
95
+ let(:old_session_a) do
96
+ pool.checkout
97
+ end
98
+
99
+ let(:old_session_b) do
100
+ pool.checkout
101
+ end
102
+
103
+ before do
104
+ allow(old_session_a).to receive(:last_use).and_return(Time.now - 1800)
105
+ allow(old_session_b).to receive(:last_use).and_return(Time.now - 1800)
106
+ pool.checkin(old_session_a)
107
+ pool.checkin(old_session_b)
108
+ end
109
+
110
+ it 'disposes of the old sessions instead of adding them to the pool' do
111
+ expect(pool.checkout).not_to be(old_session_a)
112
+ expect(pool.checkout).not_to be(old_session_b)
113
+ expect(pool.instance_variable_get(:@queue)).to be_empty
114
+ end
115
+ end
116
+ end
117
+
118
+ describe '#end_sessions', if: sessions_enabled? do
119
+
120
+ let(:pool) do
121
+ described_class.create(client)
122
+ end
123
+
124
+ let!(:session_a) do
125
+ pool.checkout
126
+ end
127
+
128
+ let!(:session_b) do
129
+ pool.checkout
130
+ end
131
+
132
+ let(:client) do
133
+ authorized_client.with(heartbeat_frequency: 100).tap do |cl|
134
+ cl.subscribe(Mongo::Monitoring::COMMAND, subscriber)
135
+ end
136
+ end
137
+
138
+ let(:subscriber) do
139
+ EventSubscriber.new
140
+ end
141
+
142
+ before do
143
+ client.database.command(ping: 1)
144
+ pool.checkin(session_a)
145
+ pool.checkin(session_b)
146
+ pool.end_sessions
147
+ end
148
+
149
+ after do
150
+ client.close
151
+ end
152
+
153
+ let(:end_sessions_command) do
154
+ subscriber.started_events.find { |c| c.command_name == :endSessions}
155
+ end
156
+
157
+ it 'sends the endSessions command with all the session ids' do
158
+ expect(end_sessions_command.command[:ids]).to include(BSON::Document.new(session_a.session_id))
159
+ expect(end_sessions_command.command[:ids]).to include(BSON::Document.new(session_b.session_id))
160
+ end
161
+
162
+ context 'when talking to a mongos', if: sessions_enabled? && sharded? do
163
+
164
+ it 'sends the endSessions command with all the session ids' do
165
+ expect(end_sessions_command.command[:ids]).to include(BSON::Document.new(session_a.session_id))
166
+ expect(end_sessions_command.command[:ids]).to include(BSON::Document.new(session_b.session_id))
167
+ expect(end_sessions_command.command[:$clusterTime]).to eq(client.cluster.cluster_time)
168
+ end
169
+ end
170
+
171
+ context 'when the number of ids is larger than 10_000' do
172
+
173
+ before do
174
+ queue = []
175
+ 10_001.times do |i|
176
+ queue << double('session', session_id: i)
177
+ end
178
+ pool.instance_variable_set(:@queue, queue)
179
+ expect(Mongo::Operation::Commands::Command).to receive(:new).at_least(:twice)
180
+ end
181
+
182
+ let(:end_sessions_commands) do
183
+ subscriber.started_events.select { |c| c.command_name == :endSessions}
184
+ end
185
+
186
+ it 'sends the command more than once' do
187
+ pool.end_sessions
188
+ # expect(end_sessions_commands.size).to eq(2)
189
+ # expect(end_sessions_commands[0].command[:ids]).to eq([*0...10_000])
190
+ # expect(end_sessions_commands[1].command[:ids]).to eq([10_000])
191
+ end
192
+ end
193
+ end
194
+ end
@@ -566,7 +566,7 @@ describe Mongo::URI do
566
566
 
567
567
  it 'raises an exception when read preference is accessed on the client' do
568
568
  expect {
569
- Mongo::Client.new(string).read_preference
569
+ Mongo::Client.new(string).server_selector
570
570
  }.to raise_exception(Mongo::Error::InvalidServerPreference)
571
571
  end
572
572
  end
@@ -578,7 +578,7 @@ describe Mongo::URI do
578
578
  end
579
579
 
580
580
  it 'does not raise an exception until the read preference is used' do
581
- expect(Mongo::Client.new(string).read_preference).to be_a(Mongo::ServerSelector::Secondary)
581
+ expect(Mongo::Client.new(string).read_preference).to eq(BSON::Document.new(mode: :secondary, max_staleness: 89))
582
582
  end
583
583
  end
584
584
  end
@@ -929,5 +929,34 @@ describe Mongo::URI do
929
929
  expect(Mongo::Client.new(string).options[:app_name]).to eq(:reports)
930
930
  end
931
931
  end
932
+
933
+ context 'when a supported compressors option is provided' do
934
+ let(:options) { "compressors=zlib" }
935
+
936
+ it 'sets the compressors as an array on the client' do
937
+ expect(Mongo::Client.new(string).options[:compressors]).to eq(['zlib'])
938
+ end
939
+ end
940
+
941
+ context 'when a non-supported compressors option is provided' do
942
+ let(:options) { "compressors=snoopy" }
943
+
944
+ let(:client) do
945
+ Mongo::Client.new(string)
946
+ end
947
+
948
+ it 'sets no compressors on the client and warns' do
949
+ expect(Mongo::Logger.logger).to receive(:warn)
950
+ expect(client.options[:compressors]).to be_nil
951
+ end
952
+ end
953
+
954
+ context 'when a zlibCompressionLevel option is provided' do
955
+ let(:options) { "zlibCompressionLevel=6" }
956
+
957
+ it 'sets the zlib compression level on the client' do
958
+ expect(Mongo::Client.new(string).options[:zlib_compression_level]).to eq(6)
959
+ end
960
+ end
932
961
  end
933
962
  end