mongo 2.5.0.beta → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (172) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/lib/mongo/address.rb +1 -1
  5. data/lib/mongo/address/unix.rb +1 -1
  6. data/lib/mongo/auth/user.rb +0 -5
  7. data/lib/mongo/auth/user/view.rb +4 -4
  8. data/lib/mongo/bulk_write.rb +60 -32
  9. data/lib/mongo/client.rb +44 -8
  10. data/lib/mongo/cluster.rb +14 -12
  11. data/lib/mongo/cluster/periodic_executor.rb +106 -0
  12. data/lib/mongo/cluster/{cursor_reaper.rb → reapers/cursor_reaper.rb} +5 -37
  13. data/lib/mongo/cluster/reapers/socket_reaper.rb +59 -0
  14. data/lib/mongo/collection.rb +9 -6
  15. data/lib/mongo/collection/view.rb +2 -2
  16. data/lib/mongo/collection/view/builder/aggregation.rb +2 -1
  17. data/lib/mongo/collection/view/builder/find_command.rb +1 -1
  18. data/lib/mongo/collection/view/change_stream.rb +14 -1
  19. data/lib/mongo/collection/view/map_reduce.rb +30 -13
  20. data/lib/mongo/collection/view/readable.rb +5 -5
  21. data/lib/mongo/collection/view/writable.rb +98 -51
  22. data/lib/mongo/error.rb +3 -0
  23. data/lib/mongo/error/invalid_txt_record.rb +27 -0
  24. data/lib/mongo/error/invalid_uri.rb +7 -6
  25. data/lib/mongo/error/mismatched_domain.rb +27 -0
  26. data/lib/mongo/error/no_srv_records.rb +26 -0
  27. data/lib/mongo/error/unsupported_features.rb +0 -18
  28. data/lib/mongo/index/view.rb +2 -2
  29. data/lib/mongo/operation.rb +1 -0
  30. data/lib/mongo/operation/causally_consistent.rb +33 -0
  31. data/lib/mongo/operation/commands.rb +2 -1
  32. data/lib/mongo/operation/commands/aggregate.rb +2 -7
  33. data/lib/mongo/operation/commands/count.rb +27 -0
  34. data/lib/mongo/operation/commands/distinct.rb +27 -0
  35. data/lib/mongo/operation/commands/find.rb +3 -1
  36. data/lib/mongo/operation/commands/map_reduce.rb +1 -0
  37. data/lib/mongo/operation/commands/parallel_scan.rb +1 -0
  38. data/lib/mongo/operation/specifiable.rb +12 -0
  39. data/lib/mongo/operation/uses_command_op_msg.rb +36 -5
  40. data/lib/mongo/operation/write.rb +0 -5
  41. data/lib/mongo/operation/write/bulk/bulkable.rb +4 -8
  42. data/lib/mongo/operation/write/bulk/mergable.rb +2 -0
  43. data/lib/mongo/operation/write/command/create_index.rb +19 -0
  44. data/lib/mongo/operation/write/command/create_user.rb +19 -0
  45. data/lib/mongo/operation/write/command/delete.rb +1 -2
  46. data/lib/mongo/operation/write/command/drop_index.rb +19 -0
  47. data/lib/mongo/operation/write/command/insert.rb +1 -2
  48. data/lib/mongo/operation/write/command/remove_user.rb +19 -0
  49. data/lib/mongo/operation/write/command/update.rb +1 -2
  50. data/lib/mongo/operation/write/command/update_user.rb +19 -0
  51. data/lib/mongo/operation/write/write_command_enabled.rb +1 -3
  52. data/lib/mongo/protocol/compressed.rb +2 -1
  53. data/lib/mongo/protocol/serializers.rb +6 -6
  54. data/lib/mongo/retryable.rb +48 -5
  55. data/lib/mongo/server.rb +15 -0
  56. data/lib/mongo/server/connection.rb +21 -1
  57. data/lib/mongo/server/connection_pool.rb +3 -0
  58. data/lib/mongo/server/connection_pool/queue.rb +50 -5
  59. data/lib/mongo/server/description.rb +11 -3
  60. data/lib/mongo/server/description/features.rb +26 -7
  61. data/lib/mongo/session.rb +133 -6
  62. data/lib/mongo/session/server_session.rb +30 -0
  63. data/lib/mongo/session/session_pool.rb +20 -20
  64. data/lib/mongo/uri.rb +88 -44
  65. data/lib/mongo/uri/srv_protocol.rb +158 -0
  66. data/lib/mongo/version.rb +1 -1
  67. data/lib/mongo/write_concern/normalizable.rb +12 -0
  68. data/mongo.gemspec +1 -2
  69. data/spec/mongo/address_spec.rb +12 -0
  70. data/spec/mongo/auth/user/view_spec.rb +1 -5
  71. data/spec/mongo/bulk_write_spec.rb +232 -401
  72. data/spec/mongo/change_stream_examples_spec.rb +150 -0
  73. data/spec/mongo/client_spec.rb +142 -2
  74. data/spec/mongo/cluster/cursor_reaper_spec.rb +0 -70
  75. data/spec/mongo/cluster/socket_reaper_spec.rb +32 -0
  76. data/spec/mongo/cluster_spec.rb +11 -7
  77. data/spec/mongo/collection/view/aggregation_spec.rb +46 -1
  78. data/spec/mongo/collection/view/builder/find_command_spec.rb +15 -0
  79. data/spec/mongo/collection/view/change_stream_spec.rb +79 -12
  80. data/spec/mongo/collection/view/map_reduce_spec.rb +120 -4
  81. data/spec/mongo/collection/view/readable_spec.rb +23 -5
  82. data/spec/mongo/collection_spec.rb +292 -102
  83. data/spec/mongo/command_monitoring_spec.rb +26 -32
  84. data/spec/mongo/crud_spec.rb +1 -1
  85. data/spec/mongo/cursor_spec.rb +2 -3
  86. data/spec/mongo/database_spec.rb +30 -14
  87. data/spec/mongo/dns_seedlist_discovery_spec.rb +94 -0
  88. data/spec/mongo/grid/fs_bucket_spec.rb +1 -1
  89. data/spec/mongo/grid/stream/write_spec.rb +1 -1
  90. data/spec/mongo/index/view_spec.rb +8 -46
  91. data/spec/mongo/operation/write/bulk/delete_spec.rb +2 -2
  92. data/spec/mongo/operation/write/bulk/insert_spec.rb +2 -10
  93. data/spec/mongo/operation/write/{create_index_spec.rb → command/create_index_spec.rb} +2 -6
  94. data/spec/mongo/operation/write/command/delete_spec.rb +35 -7
  95. data/spec/mongo/operation/write/{drop_index_spec.rb → command/drop_index_spec.rb} +1 -1
  96. data/spec/mongo/operation/write/command/insert_spec.rb +37 -6
  97. data/spec/mongo/operation/write/{remove_user_spec.rb → command/remove_user_spec.rb} +2 -6
  98. data/spec/mongo/operation/write/command/update_spec.rb +34 -7
  99. data/spec/mongo/operation/write/{update_user_spec.rb → command/update_user_spec.rb} +1 -1
  100. data/spec/mongo/operation/write/create_user_spec.rb +1 -1
  101. data/spec/mongo/operation/write/delete_spec.rb +1 -1
  102. data/spec/mongo/operation/write/insert_spec.rb +2 -10
  103. data/spec/mongo/operation/write/update_spec.rb +3 -15
  104. data/spec/mongo/retryable_spec.rb +1 -1
  105. data/spec/mongo/retryable_writes_spec.rb +815 -0
  106. data/spec/mongo/server/connection_pool/queue_spec.rb +35 -2
  107. data/spec/mongo/server/connection_pool_spec.rb +234 -1
  108. data/spec/mongo/server/connection_spec.rb +10 -6
  109. data/spec/mongo/server/description/features_spec.rb +51 -37
  110. data/spec/mongo/server/description_spec.rb +6 -3
  111. data/spec/mongo/server_spec.rb +87 -0
  112. data/spec/mongo/session/server_session_spec.rb +43 -0
  113. data/spec/mongo/session/session_pool_spec.rb +63 -27
  114. data/spec/mongo/session_spec.rb +247 -0
  115. data/spec/mongo/shell_examples_spec.rb +2 -2
  116. data/spec/mongo/uri/srv_protocol_spec.rb +933 -0
  117. data/spec/mongo/uri_spec.rb +42 -3
  118. data/spec/mongo/write_concern/acknowledged_spec.rb +11 -0
  119. data/spec/mongo/write_concern/unacknowledged_spec.rb +11 -0
  120. data/spec/spec_helper.rb +11 -25
  121. data/spec/support/authorization.rb +2 -1
  122. data/spec/support/connection_string.rb +8 -4
  123. data/spec/support/crud.rb +38 -24
  124. data/spec/support/crud/write.rb +30 -3
  125. data/spec/support/crud_tests/read/aggregate-out.yml +21 -0
  126. data/spec/support/crud_tests/write/bulkWrite-arrayFilters.yml +44 -0
  127. data/spec/support/crud_tests/write/findOneAndUpdate-arrayFilters.yml +1 -1
  128. data/spec/support/crud_tests/write/insertMany.yml +1 -3
  129. data/spec/support/crud_tests/write/replaceOne.yml +1 -1
  130. data/spec/support/crud_tests/write/updateMany-arrayFilters.yml +1 -1
  131. data/spec/support/crud_tests/write/updateOne-arrayFilters.yml +1 -1
  132. data/spec/support/dns_seedlist_discovery_tests/longer-parent-in-return.yml +11 -0
  133. data/spec/support/dns_seedlist_discovery_tests/misformatted-option.yml +5 -0
  134. data/spec/support/dns_seedlist_discovery_tests/no-results.yml +5 -0
  135. data/spec/support/dns_seedlist_discovery_tests/not-enough-parts.yml +5 -0
  136. data/spec/support/dns_seedlist_discovery_tests/one-result-default-port.yml +10 -0
  137. data/spec/support/dns_seedlist_discovery_tests/one-txt-record-multiple-strings.yml +10 -0
  138. data/spec/support/dns_seedlist_discovery_tests/one-txt-record.yml +11 -0
  139. data/spec/support/dns_seedlist_discovery_tests/parent-part-mismatch1.yml +5 -0
  140. data/spec/support/dns_seedlist_discovery_tests/parent-part-mismatch2.yml +5 -0
  141. data/spec/support/dns_seedlist_discovery_tests/parent-part-mismatch3.yml +5 -0
  142. data/spec/support/dns_seedlist_discovery_tests/parent-part-mismatch4.yml +5 -0
  143. data/spec/support/dns_seedlist_discovery_tests/parent-part-mismatch5.yml +5 -0
  144. data/spec/support/dns_seedlist_discovery_tests/returned-parent-too-short.yml +5 -0
  145. data/spec/support/dns_seedlist_discovery_tests/returned-parent-wrong.yml +5 -0
  146. data/spec/support/dns_seedlist_discovery_tests/two-results-default-port.yml +11 -0
  147. data/spec/support/dns_seedlist_discovery_tests/two-results-nonstandard-port.yml +11 -0
  148. data/spec/support/dns_seedlist_discovery_tests/two-txt-records.yml +5 -0
  149. data/spec/support/dns_seedlist_discovery_tests/txt-record-not-allowed-option.yml +5 -0
  150. data/spec/support/dns_seedlist_discovery_tests/txt-record-with-overridden-ssl-option.yml +11 -0
  151. data/spec/support/dns_seedlist_discovery_tests/txt-record-with-overridden-uri-option.yml +11 -0
  152. data/spec/support/dns_seedlist_discovery_tests/txt-record-with-unallowed-option.yml +5 -0
  153. data/spec/support/dns_seedlist_discovery_tests/uri-with-port.yml +5 -0
  154. data/spec/support/dns_seedlist_discovery_tests/uri-with-two-hosts.yml +5 -0
  155. data/spec/support/retryable_writes_tests/bulkWrite.yml +305 -0
  156. data/spec/support/retryable_writes_tests/deleteOne.yml +51 -0
  157. data/spec/support/retryable_writes_tests/findOneAndDelete.yml +52 -0
  158. data/spec/support/retryable_writes_tests/findOneAndReplace.yml +57 -0
  159. data/spec/support/retryable_writes_tests/findOneAndUpdate.yml +56 -0
  160. data/spec/support/retryable_writes_tests/insertMany.yml +72 -0
  161. data/spec/support/retryable_writes_tests/insertOne.yml +55 -0
  162. data/spec/support/retryable_writes_tests/replaceOne.yml +60 -0
  163. data/spec/support/retryable_writes_tests/updateOne.yml +120 -0
  164. data/spec/support/shared/session.rb +525 -24
  165. metadata +437 -350
  166. metadata.gz.sig +0 -0
  167. data/lib/mongo/operation/commands/user_query.rb +0 -72
  168. data/lib/mongo/operation/write/create_index.rb +0 -67
  169. data/lib/mongo/operation/write/create_user.rb +0 -50
  170. data/lib/mongo/operation/write/drop_index.rb +0 -63
  171. data/lib/mongo/operation/write/remove_user.rb +0 -48
  172. data/lib/mongo/operation/write/update_user.rb +0 -50
@@ -179,6 +179,24 @@ describe Mongo::Collection::View::Readable do
179
179
  it_behaves_like 'a read concern aware operation'
180
180
  end
181
181
 
182
+ context 'when a session supporting causal consistency is used' do
183
+
184
+ let(:view) do
185
+ Mongo::Collection::View.new(collection, selector, session: session)
186
+ end
187
+
188
+ let(:operation) do
189
+ begin; view.map_reduce(map, reduce).to_a; rescue; end
190
+ end
191
+
192
+ let(:command) do
193
+ operation
194
+ subscriber.started_events.find { |cmd| cmd.command_name == 'mapreduce' }.command
195
+ end
196
+
197
+ it_behaves_like 'an operation supporting causally consistent reads'
198
+ end
199
+
182
200
  context 'when not iterating the map/reduce' do
183
201
 
184
202
  it 'returns the map/reduce object' do
@@ -305,7 +323,7 @@ describe Mongo::Collection::View::Readable do
305
323
  end
306
324
  end
307
325
 
308
- it 'takes a read preference option' do
326
+ it 'takes a read preference option', unless: sharded? do
309
327
  expect(view.count(read: { mode: :secondary })).to eq(10)
310
328
  end
311
329
 
@@ -460,13 +478,13 @@ describe Mongo::Collection::View::Readable do
460
478
  end
461
479
  end
462
480
 
463
- it 'takes a max_time_ms option', if: write_command_enabled? do
481
+ it 'takes a max_time_ms option' do
464
482
  expect {
465
483
  view.count(max_time_ms: 0.1)
466
484
  }.to raise_error(Mongo::Error::OperationFailure)
467
485
  end
468
486
 
469
- it 'sets the max_time_ms option on the command', if: write_command_enabled? do
487
+ it 'sets the max_time_ms option on the command' do
470
488
  expect(view.count(max_time_ms: 100)).to eq(10)
471
489
  end
472
490
 
@@ -830,7 +848,7 @@ describe Mongo::Collection::View::Readable do
830
848
  end
831
849
  end
832
850
 
833
- context 'when a max_time_ms is specified', if: write_command_enabled? do
851
+ context 'when a max_time_ms is specified' do
834
852
 
835
853
  let(:documents) do
836
854
  (1..3).map{ |i| { field: "test" }}
@@ -960,7 +978,7 @@ describe Mongo::Collection::View::Readable do
960
978
  end
961
979
 
962
980
  it 'does not apply the collation to the distinct' do
963
- expect(result).to eq(['bang', 'BANG'])
981
+ expect(result).to match_array(['bang', 'BANG'])
964
982
  end
965
983
  end
966
984
  end
@@ -14,6 +14,10 @@ describe Mongo::Collection do
14
14
  authorized_client[:validating]
15
15
  end
16
16
 
17
+ let(:client) do
18
+ authorized_client
19
+ end
20
+
17
21
  describe '#==' do
18
22
 
19
23
  let(:database) do
@@ -648,7 +652,6 @@ describe Mongo::Collection do
648
652
  end
649
653
  end
650
654
 
651
-
652
655
  describe '#drop' do
653
656
 
654
657
  let(:database) do
@@ -763,8 +766,12 @@ describe Mongo::Collection do
763
766
  client[TEST_COLL].find.first
764
767
  end
765
768
 
769
+ let(:operation_with_session) do
770
+ client[TEST_COLL].find({}, session: session).first
771
+ end
772
+
766
773
  let(:second_operation) do
767
- client[TEST_COLL].find.first
774
+ client[TEST_COLL].find({}, session: session).first
768
775
  end
769
776
 
770
777
  it_behaves_like 'an operation updating cluster time'
@@ -864,10 +871,6 @@ describe Mongo::Collection do
864
871
 
865
872
  context 'when provided options' do
866
873
 
867
- let(:view) do
868
- authorized_collection.find({}, options)
869
- end
870
-
871
874
  context 'when a session is provided' do
872
875
 
873
876
  let(:operation) do
@@ -879,7 +882,7 @@ describe Mongo::Collection do
879
882
  end
880
883
 
881
884
  let(:failed_operation) do
882
- authorized_collection.find({ '$._id' => 1 }, session: session).to_a
885
+ client[authorized_collection.name].find({ '$._id' => 1 }, session: session).to_a
883
886
  end
884
887
 
885
888
  let(:client) do
@@ -890,6 +893,58 @@ describe Mongo::Collection do
890
893
  it_behaves_like 'a failed operation using a session'
891
894
  end
892
895
 
896
+ context 'session id', if: test_sessions? do
897
+
898
+ let(:options) do
899
+ { session: session }
900
+ end
901
+
902
+ let(:client) do
903
+ authorized_client.with(heartbeat_frequency: 100).tap do |cl|
904
+ cl.subscribe(Mongo::Monitoring::COMMAND, subscriber)
905
+ end
906
+ end
907
+
908
+ let(:session) do
909
+ client.start_session
910
+ end
911
+
912
+ let(:subscriber) do
913
+ EventSubscriber.new
914
+ end
915
+
916
+ let(:view) do
917
+ Mongo::Collection::View.new(client[TEST_COLL], selector, view_options)
918
+ end
919
+
920
+ let(:command) do
921
+ client[TEST_COLL].find({}, session: session).explain
922
+ subscriber.started_events.find { |c| c.command_name == :explain }.command
923
+ end
924
+
925
+ it 'sends the session id' do
926
+ expect(command['lsid']).to eq(session.session_id)
927
+ end
928
+ end
929
+
930
+ context 'when a session supporting causal consistency is used' do
931
+
932
+ let(:operation) do
933
+ collection.find({}, session: session).to_a
934
+ end
935
+
936
+ let(:command) do
937
+ operation
938
+ subscriber.started_events.find { |cmd| cmd.command_name == 'find' }.command
939
+ end
940
+
941
+ it_behaves_like 'an operation supporting causally consistent reads'
942
+ end
943
+
944
+ let(:view) do
945
+ authorized_collection.find({}, options)
946
+ end
947
+
893
948
  context 'when provided :allow_partial_results' do
894
949
 
895
950
  let(:options) do
@@ -1064,6 +1119,19 @@ describe Mongo::Collection do
1064
1119
  it_behaves_like 'a failed operation using a session'
1065
1120
  end
1066
1121
 
1122
+ context 'when unacknowledged writes is used' do
1123
+
1124
+ let(:collection_with_unacknowledged_write_concern) do
1125
+ authorized_collection.with(write: { w: 0 })
1126
+ end
1127
+
1128
+ let(:operation) do
1129
+ collection_with_unacknowledged_write_concern.insert_many([{ name: 'test1' }, { name: 'test2' }], session: session)
1130
+ end
1131
+
1132
+ it_behaves_like 'a causally consistent client session with an unacknowledged write'
1133
+ end
1134
+
1067
1135
  context 'when a document contains invalid keys' do
1068
1136
 
1069
1137
  let(:docs) do
@@ -1218,6 +1286,21 @@ describe Mongo::Collection do
1218
1286
  end
1219
1287
  end
1220
1288
  end
1289
+
1290
+ context 'when unacknowledged writes is used' do
1291
+
1292
+ let(:collection_with_unacknowledged_write_concern) do
1293
+ authorized_collection.with(write: { w: 0 })
1294
+ end
1295
+
1296
+ let(:result) do
1297
+ collection_with_unacknowledged_write_concern.insert_many([{ _id: 1 }, { _id: 1 }])
1298
+ end
1299
+
1300
+ it 'does not raise an exception' do
1301
+ expect(result.inserted_count).to be(0)
1302
+ end
1303
+ end
1221
1304
  end
1222
1305
 
1223
1306
  describe '#insert_one' do
@@ -1228,8 +1311,12 @@ describe Mongo::Collection do
1228
1311
  client[TEST_COLL].insert_one({ name: 'testing' })
1229
1312
  end
1230
1313
 
1314
+ let(:operation_with_session) do
1315
+ client[TEST_COLL].insert_one({ name: 'testing' }, session: session)
1316
+ end
1317
+
1231
1318
  let(:second_operation) do
1232
- client[TEST_COLL].insert_one({ name: 'testing' })
1319
+ client[TEST_COLL].insert_one({ name: 'testing' }, session: session)
1233
1320
  end
1234
1321
 
1235
1322
  it_behaves_like 'an operation updating cluster time'
@@ -1239,14 +1326,10 @@ describe Mongo::Collection do
1239
1326
  authorized_collection.insert_one({ name: 'testing' })
1240
1327
  end
1241
1328
 
1242
- it 'inserts the document into the collection', if: write_command_enabled? do
1329
+ it 'inserts the document into the collection'do
1243
1330
  expect(result.written_count).to eq(1)
1244
1331
  end
1245
1332
 
1246
- it 'inserts the document into the collection', unless: write_command_enabled? do
1247
- expect(result.written_count).to eq(0)
1248
- end
1249
-
1250
1333
  it 'contains the id in the result' do
1251
1334
  expect(result.inserted_id).to_not be_nil
1252
1335
  end
@@ -1274,6 +1357,19 @@ describe Mongo::Collection do
1274
1357
  it_behaves_like 'a failed operation using a session'
1275
1358
  end
1276
1359
 
1360
+ context 'when unacknowledged writes is used' do
1361
+
1362
+ let(:collection_with_unacknowledged_write_concern) do
1363
+ authorized_collection.with(write: { w: 0 })
1364
+ end
1365
+
1366
+ let(:operation) do
1367
+ collection_with_unacknowledged_write_concern.insert_one({ name: 'testing' }, session: session)
1368
+ end
1369
+
1370
+ it_behaves_like 'a causally consistent client session with an unacknowledged write'
1371
+ end
1372
+
1277
1373
  context 'when the document contains invalid keys' do
1278
1374
 
1279
1375
  let(:doc) do
@@ -1459,13 +1555,31 @@ describe Mongo::Collection do
1459
1555
  client[TEST_COLL].aggregate([]).first
1460
1556
  end
1461
1557
 
1558
+ let(:operation_with_session) do
1559
+ client[TEST_COLL].aggregate([], session: session).first
1560
+ end
1561
+
1462
1562
  let(:second_operation) do
1463
- client[TEST_COLL].aggregate([]).first
1563
+ client[TEST_COLL].aggregate([], session: session).first
1464
1564
  end
1465
1565
 
1466
1566
  it_behaves_like 'an operation updating cluster time'
1467
1567
  end
1468
1568
 
1569
+ context 'when a session supporting causal consistency is used' do
1570
+
1571
+ let(:operation) do
1572
+ collection.aggregate([], session: session).first
1573
+ end
1574
+
1575
+ let(:command) do
1576
+ operation
1577
+ subscriber.started_events.find { |cmd| cmd.command_name == 'aggregate' }.command
1578
+ end
1579
+
1580
+ it_behaves_like 'an operation supporting causally consistent reads'
1581
+ end
1582
+
1469
1583
  it 'returns an Aggregation object' do
1470
1584
  expect(authorized_collection.aggregate([])).to be_a(Mongo::Collection::View::Aggregation)
1471
1585
  end
@@ -1480,6 +1594,17 @@ describe Mongo::Collection do
1480
1594
  expect(authorized_collection.aggregate([], options).options).to eq(BSON::Document.new(options))
1481
1595
  end
1482
1596
 
1597
+ context 'when the :comment option is provided' do
1598
+
1599
+ let(:options) do
1600
+ { :comment => 'testing' }
1601
+ end
1602
+
1603
+ it 'sets the options on the Aggregation object' do
1604
+ expect(authorized_collection.aggregate([], options).options).to eq(BSON::Document.new(options))
1605
+ end
1606
+ end
1607
+
1483
1608
  context 'when a session is provided' do
1484
1609
 
1485
1610
  let(:session) do
@@ -1605,6 +1730,20 @@ describe Mongo::Collection do
1605
1730
  it_behaves_like 'a failed operation using a session'
1606
1731
  end
1607
1732
 
1733
+ context 'when a session supporting causal consistency is used' do
1734
+
1735
+ let(:operation) do
1736
+ collection.count({}, session: session)
1737
+ end
1738
+
1739
+ let(:command) do
1740
+ operation
1741
+ subscriber.started_events.find { |cmd| cmd.command_name == :count }.command
1742
+ end
1743
+
1744
+ it_behaves_like 'an operation supporting causally consistent reads'
1745
+ end
1746
+
1608
1747
  context 'when a collation is specified' do
1609
1748
 
1610
1749
  let(:selector) do
@@ -1705,6 +1844,20 @@ describe Mongo::Collection do
1705
1844
  end
1706
1845
  end
1707
1846
 
1847
+ context 'when a session supporting causal consistency is used' do
1848
+
1849
+ let(:operation) do
1850
+ collection.distinct(:field, {}, session: session)
1851
+ end
1852
+
1853
+ let(:command) do
1854
+ operation
1855
+ subscriber.started_events.find { |cmd| cmd.command_name == :distinct }.command
1856
+ end
1857
+
1858
+ it_behaves_like 'an operation supporting causally consistent reads'
1859
+ end
1860
+
1708
1861
  context 'when a collation is specified' do
1709
1862
 
1710
1863
  let(:result) do
@@ -1762,7 +1915,7 @@ describe Mongo::Collection do
1762
1915
  end
1763
1916
 
1764
1917
  it 'does not apply the collation to the distinct' do
1765
- expect(result).to eq(['bang', 'BANG'])
1918
+ expect(result).to match_array(['bang', 'BANG'])
1766
1919
  end
1767
1920
  end
1768
1921
  end
@@ -1842,6 +1995,19 @@ describe Mongo::Collection do
1842
1995
  it_behaves_like 'a failed operation using a session'
1843
1996
  end
1844
1997
 
1998
+ context 'when unacknowledged writes is used' do
1999
+
2000
+ let(:collection_with_unacknowledged_write_concern) do
2001
+ authorized_collection.with(write: { w: 0 })
2002
+ end
2003
+
2004
+ let(:operation) do
2005
+ collection_with_unacknowledged_write_concern.delete_one({}, session: session)
2006
+ end
2007
+
2008
+ it_behaves_like 'a causally consistent client session with an unacknowledged write'
2009
+ end
2010
+
1845
2011
  context 'when a collation is provided' do
1846
2012
 
1847
2013
  let(:selector) do
@@ -2001,6 +2167,19 @@ describe Mongo::Collection do
2001
2167
  it_behaves_like 'a failed operation using a session'
2002
2168
  end
2003
2169
 
2170
+ context 'when unacknowledged writes is used' do
2171
+
2172
+ let(:collection_with_unacknowledged_write_concern) do
2173
+ authorized_collection.with(write: { w: 0 })
2174
+ end
2175
+
2176
+ let(:operation) do
2177
+ collection_with_unacknowledged_write_concern.delete_many({ '$._id' => 1}, session: session)
2178
+ end
2179
+
2180
+ it_behaves_like 'a causally consistent client session with an unacknowledged write'
2181
+ end
2182
+
2004
2183
  context 'when a collation is specified' do
2005
2184
 
2006
2185
  let(:selector) do
@@ -2119,34 +2298,24 @@ describe Mongo::Collection do
2119
2298
  authorized_collection.parallel_scan(2)
2120
2299
  end
2121
2300
 
2122
- it 'returns an array of cursors', if: write_command_enabled? do
2301
+ it 'returns an array of cursors' do
2123
2302
  cursors.each do |cursor|
2124
2303
  expect(cursor.class).to be(Mongo::Cursor)
2125
2304
  end
2126
2305
  end
2127
2306
 
2128
- it 'returns the correct number of documents', if: write_command_enabled? do
2307
+ it 'returns the correct number of documents' do
2129
2308
  expect(
2130
2309
  cursors.reduce(0) { |total, cursor| total + cursor.to_a.size }
2131
2310
  ).to eq(200)
2132
2311
  end
2133
2312
 
2134
- it 'raises an error', unless: write_command_enabled? do
2135
- expect {
2136
- cursors
2137
- }.to raise_error(Mongo::Error::OperationFailure)
2138
- end
2139
-
2140
2313
  context 'when a session is provided' do
2141
2314
 
2142
2315
  let(:cursors) do
2143
2316
  authorized_collection.parallel_scan(2, session: session)
2144
2317
  end
2145
2318
 
2146
- let(:session) do
2147
- authorized_client.start_session
2148
- end
2149
-
2150
2319
  let(:operation) do
2151
2320
  cursors.reduce(0) { |total, cursor| total + cursor.to_a.size }
2152
2321
  end
@@ -2163,6 +2332,24 @@ describe Mongo::Collection do
2163
2332
  it_behaves_like 'a failed operation using a session'
2164
2333
  end
2165
2334
 
2335
+ context 'when a session supporting causal consistency is used' do
2336
+
2337
+ let(:cursors) do
2338
+ collection.parallel_scan(2, session: session)
2339
+ end
2340
+
2341
+ let(:operation) do
2342
+ cursors.reduce(0) { |total, cursor| total + cursor.to_a.size }
2343
+ end
2344
+
2345
+ let(:command) do
2346
+ operation
2347
+ subscriber.started_events.find { |cmd| cmd.command_name == :parallelCollectionScan }.command
2348
+ end
2349
+
2350
+ it_behaves_like 'an operation supporting causally consistent reads'
2351
+ end
2352
+
2166
2353
  context 'when a read concern is provided', if: find_command_enabled? do
2167
2354
 
2168
2355
  let(:result) do
@@ -2224,7 +2411,7 @@ describe Mongo::Collection do
2224
2411
  end
2225
2412
  end
2226
2413
 
2227
- context 'when a max time ms value is provided', if: (!sharded? && write_command_enabled?) do
2414
+ context 'when a max time ms value is provided', if: !sharded? do
2228
2415
 
2229
2416
  let(:result) do
2230
2417
  authorized_collection.parallel_scan(2, options)
@@ -2276,14 +2463,10 @@ describe Mongo::Collection do
2276
2463
  authorized_collection.find(field: 'testing').first
2277
2464
  end
2278
2465
 
2279
- it 'updates the first matching document in the collection', if: write_command_enabled? do
2466
+ it 'updates the first matching document in the collection' do
2280
2467
  expect(response.modified_count).to eq(1)
2281
2468
  end
2282
2469
 
2283
- it 'does not return modified count', unless: write_command_enabled? do
2284
- expect(response.modified_count).to eq(nil)
2285
- end
2286
-
2287
2470
  it 'updates the documents in the collection' do
2288
2471
  expect(updated[:field]).to eq('testing')
2289
2472
  end
@@ -2299,14 +2482,10 @@ describe Mongo::Collection do
2299
2482
  authorized_collection.find(field: 'test1').to_a
2300
2483
  end
2301
2484
 
2302
- it 'reports that no documents were written', if: write_command_enabled? do
2485
+ it 'reports that no documents were written' do
2303
2486
  expect(response.modified_count).to eq(0)
2304
2487
  end
2305
2488
 
2306
- it 'does not return modified count', unless: write_command_enabled? do
2307
- expect(response.modified_count).to eq(nil)
2308
- end
2309
-
2310
2489
  it 'does not insert the document' do
2311
2490
  expect(updated).to be_empty
2312
2491
  end
@@ -2341,14 +2520,10 @@ describe Mongo::Collection do
2341
2520
  authorized_collection.find(field: 'test1').to_a
2342
2521
  end
2343
2522
 
2344
- it 'reports that no documents were written', if: write_command_enabled? do
2523
+ it 'reports that no documents were written' do
2345
2524
  expect(response.modified_count).to eq(0)
2346
2525
  end
2347
2526
 
2348
- it 'does not return modified count', unless: write_command_enabled? do
2349
- expect(response.modified_count).to eq(nil)
2350
- end
2351
-
2352
2527
  it 'does not insert the document' do
2353
2528
  expect(updated).to be_empty
2354
2529
  end
@@ -2550,6 +2725,19 @@ describe Mongo::Collection do
2550
2725
  it_behaves_like 'an operation using a session'
2551
2726
  it_behaves_like 'a failed operation using a session'
2552
2727
  end
2728
+
2729
+ context 'when unacknowledged writes is used' do
2730
+
2731
+ let(:collection_with_unacknowledged_write_concern) do
2732
+ authorized_collection.with(write: { w: 0 })
2733
+ end
2734
+
2735
+ let(:operation) do
2736
+ collection_with_unacknowledged_write_concern.replace_one({ a: 1 }, { x: 5 }, session: session)
2737
+ end
2738
+
2739
+ it_behaves_like 'a causally consistent client session with an unacknowledged write'
2740
+ end
2553
2741
  end
2554
2742
 
2555
2743
  describe '#update_many' do
@@ -2572,14 +2760,10 @@ describe Mongo::Collection do
2572
2760
  authorized_collection.find(field: 'testing').to_a.last
2573
2761
  end
2574
2762
 
2575
- it 'returns the number updated', if: write_command_enabled? do
2763
+ it 'returns the number updated' do
2576
2764
  expect(response.modified_count).to eq(2)
2577
2765
  end
2578
2766
 
2579
- it 'does not return modified count', unless: write_command_enabled? do
2580
- expect(response.modified_count).to eq(nil)
2581
- end
2582
-
2583
2767
  it 'updates the documents in the collection' do
2584
2768
  expect(updated[:field]).to eq('testing')
2585
2769
  end
@@ -2596,14 +2780,10 @@ describe Mongo::Collection do
2596
2780
  authorized_collection.find.to_a
2597
2781
  end
2598
2782
 
2599
- it 'reports that no documents were updated', if: write_command_enabled? do
2783
+ it 'reports that no documents were updated' do
2600
2784
  expect(response.modified_count).to eq(0)
2601
2785
  end
2602
2786
 
2603
- it 'does not return modified count', unless: write_command_enabled? do
2604
- expect(response.modified_count).to eq(nil)
2605
- end
2606
-
2607
2787
  it 'updates no documents in the collection' do
2608
2788
  expect(updated).to be_empty
2609
2789
  end
@@ -2639,14 +2819,10 @@ describe Mongo::Collection do
2639
2819
  authorized_collection.find.to_a
2640
2820
  end
2641
2821
 
2642
- it 'reports that no documents were updated', if: write_command_enabled? do
2822
+ it 'reports that no documents were updated' do
2643
2823
  expect(response.modified_count).to eq(0)
2644
2824
  end
2645
2825
 
2646
- it 'does not return modified count', unless: write_command_enabled? do
2647
- expect(response.modified_count).to eq(nil)
2648
- end
2649
-
2650
2826
  it 'updates no documents in the collection' do
2651
2827
  expect(updated).to be_empty
2652
2828
  end
@@ -2953,6 +3129,19 @@ describe Mongo::Collection do
2953
3129
  it_behaves_like 'an operation using a session'
2954
3130
  it_behaves_like 'a failed operation using a session'
2955
3131
  end
3132
+
3133
+ context 'when unacknowledged writes is used' do
3134
+
3135
+ let(:collection_with_unacknowledged_write_concern) do
3136
+ authorized_collection.with(write: { w: 0 })
3137
+ end
3138
+
3139
+ let(:operation) do
3140
+ collection_with_unacknowledged_write_concern.update_many({a: 1}, { '$set' => {x: 1} }, session: session)
3141
+ end
3142
+
3143
+ it_behaves_like 'a causally consistent client session with an unacknowledged write'
3144
+ end
2956
3145
  end
2957
3146
 
2958
3147
  describe '#update_one' do
@@ -2975,14 +3164,10 @@ describe Mongo::Collection do
2975
3164
  authorized_collection.find(field: 'testing').first
2976
3165
  end
2977
3166
 
2978
- it 'updates the first matching document in the collection', if: write_command_enabled? do
3167
+ it 'updates the first matching document in the collection' do
2979
3168
  expect(response.modified_count).to eq(1)
2980
3169
  end
2981
3170
 
2982
- it 'does not return modified count', unless: write_command_enabled? do
2983
- expect(response.modified_count).to eq(nil)
2984
- end
2985
-
2986
3171
  it 'updates the documents in the collection' do
2987
3172
  expect(updated[:field]).to eq('testing')
2988
3173
  end
@@ -2999,14 +3184,10 @@ describe Mongo::Collection do
2999
3184
  authorized_collection.find.to_a
3000
3185
  end
3001
3186
 
3002
- it 'reports that no documents were updated', if: write_command_enabled? do
3187
+ it 'reports that no documents were updated' do
3003
3188
  expect(response.modified_count).to eq(0)
3004
3189
  end
3005
3190
 
3006
- it 'does not return modified count', unless: write_command_enabled? do
3007
- expect(response.modified_count).to eq(nil)
3008
- end
3009
-
3010
3191
  it 'updates no documents in the collection' do
3011
3192
  expect(updated).to be_empty
3012
3193
  end
@@ -3042,14 +3223,10 @@ describe Mongo::Collection do
3042
3223
  authorized_collection.find.to_a
3043
3224
  end
3044
3225
 
3045
- it 'reports that no documents were updated', if: write_command_enabled? do
3226
+ it 'reports that no documents were updated' do
3046
3227
  expect(response.modified_count).to eq(0)
3047
3228
  end
3048
3229
 
3049
- it 'does not return modified count', unless: write_command_enabled? do
3050
- expect(response.modified_count).to eq(nil)
3051
- end
3052
-
3053
3230
  it 'updates no documents in the collection' do
3054
3231
  expect(updated).to be_empty
3055
3232
  end
@@ -3365,6 +3542,19 @@ describe Mongo::Collection do
3365
3542
  it_behaves_like 'an operation using a session'
3366
3543
  it_behaves_like 'a failed operation using a session'
3367
3544
  end
3545
+
3546
+ context 'when unacknowledged writes is used' do
3547
+
3548
+ let(:collection_with_unacknowledged_write_concern) do
3549
+ authorized_collection.with(write: { w: 0 })
3550
+ end
3551
+
3552
+ let(:operation) do
3553
+ collection_with_unacknowledged_write_concern.update_one({a: 1}, { '$set' => {x: 1} }, session: session)
3554
+ end
3555
+
3556
+ it_behaves_like 'a causally consistent client session with an unacknowledged write'
3557
+ end
3368
3558
  end
3369
3559
 
3370
3560
  describe '#find_one_and_delete' do
@@ -3447,7 +3637,7 @@ describe Mongo::Collection do
3447
3637
  end
3448
3638
  end
3449
3639
 
3450
- context 'when max_time_ms is provided', if: write_command_enabled? do
3640
+ context 'when max_time_ms is provided' do
3451
3641
 
3452
3642
  it 'includes the max_time_ms value in the command' do
3453
3643
  expect {
@@ -3472,7 +3662,7 @@ describe Mongo::Collection do
3472
3662
  end
3473
3663
  end
3474
3664
 
3475
- context 'when the operation fails', if: write_command_enabled? do
3665
+ context 'when the operation fails' do
3476
3666
 
3477
3667
  let(:result) do
3478
3668
  authorized_collection.find_one_and_delete(selector, max_time_ms: 0.1)
@@ -3685,7 +3875,7 @@ describe Mongo::Collection do
3685
3875
 
3686
3876
  context 'when max_time_ms is provided' do
3687
3877
 
3688
- it 'includes the max_time_ms value in the command', if: write_command_enabled? do
3878
+ it 'includes the max_time_ms value in the command' do
3689
3879
  expect {
3690
3880
  authorized_collection.find_one_and_update(selector, { '$set' => { field: 'testing' }}, max_time_ms: 0.1)
3691
3881
  }.to raise_error(Mongo::Error::OperationFailure)
@@ -3740,7 +3930,7 @@ describe Mongo::Collection do
3740
3930
  end
3741
3931
  end
3742
3932
 
3743
- context 'when the operation fails', if: write_command_enabled? do
3933
+ context 'when the operation fails' do
3744
3934
 
3745
3935
  let(:result) do
3746
3936
  authorized_collection.find_one_and_update(selector, { '$set' => { field: 'testing' }}, max_time_ms: 0.1)
@@ -4116,7 +4306,7 @@ describe Mongo::Collection do
4116
4306
  end
4117
4307
  end
4118
4308
 
4119
- context 'when max_time_ms is provided', if: write_command_enabled? do
4309
+ context 'when max_time_ms is provided' do
4120
4310
 
4121
4311
  it 'includes the max_time_ms value in the command' do
4122
4312
  expect {
@@ -4125,7 +4315,7 @@ describe Mongo::Collection do
4125
4315
  end
4126
4316
  end
4127
4317
 
4128
- context 'when the operation fails', if: write_command_enabled? do
4318
+ context 'when the operation fails' do
4129
4319
 
4130
4320
  let(:result) do
4131
4321
  authorized_collection.find_one_and_replace(selector, { field: 'testing' }, max_time_ms: 0.1)
@@ -4364,8 +4554,11 @@ describe Mongo::Collection do
4364
4554
  context 'when batch_size is provided' do
4365
4555
 
4366
4556
  before do
4367
- authorized_collection.insert_one(a: 2)
4368
- authorized_collection.insert_one(a: 3)
4557
+ Thread.new do
4558
+ sleep 1
4559
+ authorized_collection.insert_one(a: 2)
4560
+ authorized_collection.insert_one(a: 3)
4561
+ end
4369
4562
  end
4370
4563
 
4371
4564
  let(:change_stream) do
@@ -4375,31 +4568,28 @@ describe Mongo::Collection do
4375
4568
  it 'returns the documents in the batch size specified' do
4376
4569
  expect(change_stream.instance_variable_get(:@cursor)).to receive(:get_more).once.and_call_original
4377
4570
  enum.next
4378
- enum.next
4379
4571
  end
4380
4572
  end
4381
4573
 
4382
4574
  context 'when collation is provided' do
4383
- # pending 'server support for collation with the $changeStream operator'
4384
- #
4385
- # before do
4386
- # authorized_collection.update_one({ a: 1 }, { '$set' => { a: 2 } })
4387
- # end
4388
- #
4389
- # let(:change_doc) do
4390
- # change_stream.next
4391
- # change_stream.next
4392
- # end
4393
- #
4394
- # let(:change_stream) do
4395
- # authorized_collection.watch([ { '$match' => { operationType: 'UPDATE'}}],
4396
- # collation: { locale: 'en_US', strength: 2 } ).to_enum
4397
- # end
4398
- #
4399
- # it 'returns the change' do
4400
- # expect(change_doc[:operationType]).to eq('update')
4401
- # expect(change_doc[:fullDocument][:a]).to eq(2)
4402
- # end
4575
+
4576
+ before do
4577
+ authorized_collection.update_one({ a: 1 }, { '$set' => { a: 2 } })
4578
+ end
4579
+
4580
+ let(:change_doc) do
4581
+ enum.next
4582
+ end
4583
+
4584
+ let(:change_stream) do
4585
+ authorized_collection.watch([ { '$match' => { operationType: 'UPDATE'}}],
4586
+ collation: { locale: 'en_US', strength: 2 } ).to_enum
4587
+ end
4588
+
4589
+ it 'returns the change' do
4590
+ expect(change_doc['operationType']).to eq('update')
4591
+ expect(change_doc['updateDescription']['updatedFields']['a']).to eq(2)
4592
+ end
4403
4593
  end
4404
4594
  end
4405
4595
  end