mongo 2.5.0.beta → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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